[gnome-keyring] [gcr] More implementation of selector widget.



commit fa1f8bc0e794d7a40150623361076dc3d7498999
Author: Stef Walter <stef memberwebs com>
Date:   Wed Oct 20 20:47:39 2010 +0000

    [gcr] More implementation of selector widget.
    
     * Add a certificate base class to augment interface with default props.
     * All properties come from certificate rather than renderer.
     * Certificates are comparable.

 .gitignore                          |    3 +
 docs/reference/gcr/gcr-sections.txt |    4 +
 gcr/Makefile.am                     |    5 +
 gcr/gcr-certificate-renderer.c      |  111 ++---------
 gcr/gcr-certificate-renderer.h      |    2 -
 gcr/gcr-certificate.c               |  283 ++++++++++++++++++++++++++-
 gcr/gcr-certificate.h               |   37 +++-
 gcr/gcr-collection-model.c          |  106 +++++++++-
 gcr/gcr-collection-model.h          |   16 ++-
 gcr/gcr-column.h                    |    5 +-
 gcr/gcr-comparable.c                |  103 ++++++++++
 gcr/gcr-comparable.h                |   54 +++++
 gcr/gcr-library.c                   |    6 +-
 gcr/gcr-pkcs11-certificate.c        |   13 +-
 gcr/gcr-renderer.c                  |   33 ---
 gcr/gcr-renderer.h                  |    5 -
 gcr/gcr-selector.c                  |  364 +++++++++++++++++++++++++++++++++++
 gcr/gcr-selector.h                  |   82 ++++++++
 gcr/gcr-simple-certificate.c        |   32 ++-
 gcr/gcr.h                           |    1 +
 gcr/tests/test-ui-selector.c        |   82 +-------
 21 files changed, 1097 insertions(+), 250 deletions(-)
---
diff --git a/.gitignore b/.gitignore
index e129e2b..1e8f090 100644
--- a/.gitignore
+++ b/.gitignore
@@ -109,3 +109,6 @@ run-tests
 
 /ui/gnome-keyring-prompt.desktop
 /ui/gnome-keyring-prompt.desktop.in
+
+/docs/reference/*/*-scan
+/docs/reference/*/*-scan.c
diff --git a/docs/reference/gcr/gcr-sections.txt b/docs/reference/gcr/gcr-sections.txt
index 95ba401..43deadf 100644
--- a/docs/reference/gcr/gcr-sections.txt
+++ b/docs/reference/gcr/gcr-sections.txt
@@ -58,6 +58,10 @@ gcr_certificate_get_serial_number_hex
 gcr_certificate_get_key_size
 gcr_certificate_get_fingerprint
 gcr_certificate_get_fingerprint_hex
+gcr_certificate_mixin_class_init
+gcr_certificate_mixin_get_property
+GCR_CERTIFICATE_MIXIN_IMPLEMENT_COMPARABLE
+gcr_certificate_mixin_comparable_init
 <SUBSECTION Standard>
 GCR_CERTIFICATE
 GCR_IS_CERTIFICATE
diff --git a/gcr/Makefile.am b/gcr/Makefile.am
index 26b71c7..bfecc9a 100644
--- a/gcr/Makefile.am
+++ b/gcr/Makefile.am
@@ -35,6 +35,8 @@ inc_HEADERS = \
 	gcr-certificate-widget.h \
 	gcr-collection.h \
 	gcr-collection-model.h \
+	gcr-column.h \
+	gcr-comparable.h \
 	gcr-key-renderer.h \
 	gcr-key-widget.h \
 	gcr-importer.h \
@@ -42,6 +44,7 @@ inc_HEADERS = \
 	gcr-parser.h \
 	gcr-pkcs11-certificate.h \
 	gcr-renderer.h \
+	gcr-selector.h \
 	gcr-simple-certificate.h \
 	gcr-simple-collection.h \
 	gcr-trust.h \
@@ -76,6 +79,7 @@ libgcr GCR_VERSION_SUFFIX@_la_SOURCES = \
 	gcr-collection.c gcr-collection.h \
 	gcr-collection-model.c gcr-collection-model.h \
 	gcr-display-scrolled.c gcr-display-scrolled.h \
+	gcr-comparable.c gcr-comparable.h \
 	gcr-display-view.c gcr-display-view.h \
 	gcr-icons.c gcr-icons.h \
 	gcr-import-dialog.c gcr-import-dialog.h \
@@ -87,6 +91,7 @@ libgcr GCR_VERSION_SUFFIX@_la_SOURCES = \
 	gcr-parser.c gcr-parser.h \
 	gcr-pkcs11-certificate.c gcr-pkcs11-certificate.h \
 	gcr-renderer.c gcr-renderer.h \
+	gcr-selector.c gcr-selector.h \
 	gcr-simple-certificate.c gcr-simple-certificate.h \
 	gcr-simple-collection.c gcr-simple-collection.h \
 	gcr-trust.c gcr-trust.h \
diff --git a/gcr/gcr-certificate-renderer.c b/gcr/gcr-certificate-renderer.c
index 8b923c0..6029e58 100644
--- a/gcr/gcr-certificate-renderer.c
+++ b/gcr/gcr-certificate-renderer.c
@@ -42,13 +42,7 @@ enum {
 	PROP_0,
 	PROP_CERTIFICATE,
 	PROP_LABEL,
-	PROP_ATTRIBUTES,
-	PROP_DESCRIPTION,
-	PROP_ICON,
-	PROP_MARKUP,
-	PROP_SUBJECT,
-	PROP_ISSUER,
-	PROP_EXPIRY
+	PROP_ATTRIBUTES
 };
 
 struct _GcrCertificateRendererPrivate {
@@ -56,15 +50,16 @@ struct _GcrCertificateRendererPrivate {
 	GckAttributes *opt_attrs;
 	guint key_size;
 	gchar *label;
-	GIcon *icon;
 };
 
 static void gcr_renderer_iface_init (GcrRendererIface *iface);
-static void gcr_certificate_iface_init (GcrCertificateIface *iface);
+static void gcr_renderer_certificate_iface_init (GcrCertificateIface *iface);
 
 G_DEFINE_TYPE_WITH_CODE (GcrCertificateRenderer, gcr_certificate_renderer, G_TYPE_OBJECT,
-                         G_IMPLEMENT_INTERFACE (GCR_TYPE_RENDERER, gcr_renderer_iface_init)
-                         G_IMPLEMENT_INTERFACE (GCR_TYPE_CERTIFICATE, gcr_certificate_iface_init));
+	G_IMPLEMENT_INTERFACE (GCR_TYPE_RENDERER, gcr_renderer_iface_init);
+	GCR_CERTIFICATE_MIXIN_IMPLEMENT_COMPARABLE ();
+	G_IMPLEMENT_INTERFACE (GCR_TYPE_CERTIFICATE, gcr_renderer_certificate_iface_init);
+);
 
 /* -----------------------------------------------------------------------------
  * INTERNAL
@@ -90,26 +85,6 @@ calculate_label (GcrCertificateRenderer *self)
 	return g_strdup (_("Certificate"));
 }
 
-static gchar*
-calculate_markup (GcrCertificateRenderer *self)
-{
-	gchar *label;
-	gchar *issuer;
-	gchar *markup;
-
-	label = calculate_label (self);
-	issuer = gcr_certificate_get_issuer_cn (GCR_CERTIFICATE (self));
-
-	if (issuer)
-		markup = g_markup_printf_escaped ("%s\n<small>Issued by: %s</small>", label, issuer);
-	else
-		markup = g_markup_printf_escaped ("%s\n<small>Issued by: <i>No name</i></small>", label);
-
-	g_free (label);
-	g_free (issuer);
-	return markup;
-}
-
 static gboolean
 append_extension (GcrCertificateRenderer *self, GcrDisplayView *view,
                   GNode *asn, const guchar *data, gsize n_data, gint index)
@@ -266,7 +241,6 @@ static void
 gcr_certificate_renderer_init (GcrCertificateRenderer *self)
 {
 	self->pv = (G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_CERTIFICATE_RENDERER, GcrCertificateRendererPrivate));
-	self->pv->icon = g_themed_icon_new (GCR_ICON_CERTIFICATE);
 }
 
 static void
@@ -295,10 +269,6 @@ gcr_certificate_renderer_finalize (GObject *obj)
 	g_free (self->pv->label);
 	self->pv->label = NULL;
 
-	if (self->pv->icon)
-		g_object_unref (self->pv->icon);
-	self->pv->icon = NULL;
-
 	G_OBJECT_CLASS (gcr_certificate_renderer_parent_class)->finalize (obj);
 }
 
@@ -343,26 +313,8 @@ gcr_certificate_renderer_get_property (GObject *obj, guint prop_id, GValue *valu
 	case PROP_ATTRIBUTES:
 		g_value_set_boxed (value, self->pv->opt_attrs);
 		break;
-	case PROP_ICON:
-		g_value_set_object (value, self->pv->icon);
-		break;
-	case PROP_DESCRIPTION:
-		g_value_set_string (value, _("Certificate"));
-		break;
-	case PROP_MARKUP:
-		g_value_take_string (value, calculate_markup (self));
-		break;
-	case PROP_SUBJECT:
-		g_value_take_string (value, gcr_certificate_get_subject_cn (GCR_CERTIFICATE (self)));
-		break;
-	case PROP_ISSUER:
-		g_value_take_string (value, gcr_certificate_get_issuer_cn (GCR_CERTIFICATE (self)));
-		break;
-	case PROP_EXPIRY:
-		g_value_take_boxed (value, gcr_certificate_get_expiry_date (GCR_CERTIFICATE (self)));
-		break;
 	default:
-		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+		gcr_certificate_mixin_get_property (obj, prop_id, value, pspec);
 		break;
 	}
 }
@@ -383,27 +335,18 @@ gcr_certificate_renderer_class_init (GcrCertificateRendererClass *klass)
 
 	g_object_class_install_property (gobject_class, PROP_CERTIFICATE,
 	           g_param_spec_object ("certificate", "Certificate", "Certificate to display.",
-	                               GCR_TYPE_CERTIFICATE, G_PARAM_READWRITE));
+	                                GCR_TYPE_CERTIFICATE, G_PARAM_READWRITE));
 
-	g_object_class_install_property (gobject_class, PROP_CERTIFICATE,
-	           g_param_spec_string ("subject", "Subject", "Common name of subject",
-	                                "", G_PARAM_READABLE));
+	g_object_class_install_property (gobject_class, PROP_ATTRIBUTES,
+	           g_param_spec_boxed ("attributes", "Attributes", "Certificate pkcs11 attributes",
+	                               GCK_TYPE_ATTRIBUTES, G_PARAM_READWRITE));
 
-	g_object_class_install_property (gobject_class, PROP_CERTIFICATE,
-	           g_param_spec_string ("issuer", "Issuer", "Common name of issuer",
-	                                "", G_PARAM_READABLE));
-
-	g_object_class_install_property (gobject_class, PROP_CERTIFICATE,
-	           g_param_spec_boxed ("expiry", "Expiry", "Certificate expiry",
-	                               G_TYPE_DATE, G_PARAM_READABLE));
-
-	g_object_class_override_property (gobject_class, PROP_LABEL, "label");
-	g_object_class_override_property (gobject_class, PROP_ATTRIBUTES, "attributes");
-	g_object_class_override_property (gobject_class, PROP_DESCRIPTION, "description");
-	g_object_class_override_property (gobject_class, PROP_ICON, "icon");
-	g_object_class_override_property (gobject_class, PROP_MARKUP, "markup");
+	g_object_class_install_property (gobject_class, PROP_LABEL,
+	           g_param_spec_string ("label", "Label", "Certificate Label",
+	                                "", G_PARAM_READWRITE));
 
 	_gcr_icons_register ();
+	gcr_certificate_mixin_class_init (gobject_class);
 
 	/* Register this as a renderer which can be loaded */
 	registered = gck_attributes_new ();
@@ -429,6 +372,7 @@ gcr_certificate_renderer_render (GcrRenderer *renderer, GcrViewer *viewer)
 	GNode *asn;
 	GQuark oid;
 	GDate date;
+	GIcon *icon;
 
 	self = GCR_CERTIFICATE_RENDERER (renderer);
 
@@ -448,7 +392,9 @@ gcr_certificate_renderer_render (GcrRenderer *renderer, GcrViewer *viewer)
 	if (!data)
 		return;
 
-	_gcr_display_view_set_icon (view, GCR_RENDERER (self), self->pv->icon);
+	icon = gcr_certificate_get_icon (cert);
+	_gcr_display_view_set_icon (view, GCR_RENDERER (self), icon);
+	g_object_unref (icon);
 
 	asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "Certificate", data, n_data);
 	g_return_if_fail (asn);
@@ -602,25 +548,12 @@ gcr_certificate_renderer_populate_popup (GcrRenderer *self, GcrViewer *viewer,
 static void
 gcr_renderer_iface_init (GcrRendererIface *iface)
 {
-	static GcrModelColumn columns[] = {
-		{ "expiry", /* Below */ 0, N_("Expires"), 0 },
-		{ "label", G_TYPE_STRING, N_("Name"), 0 },
-		{ "description", G_TYPE_STRING, N_("Type"), 0 },
-		{ "subject", G_TYPE_STRING, N_("Subject"), 0 },
-		{ "issuer", G_TYPE_STRING, N_("Issued By"), 0 },
-		{ NULL }
-	};
-
-	/* Not constant so fill it in here */
-	columns[0].type = G_TYPE_DATE;
-
 	iface->populate_popup = gcr_certificate_renderer_populate_popup;
 	iface->render_view = gcr_certificate_renderer_render;
-	iface->column_info = columns;
 }
 
 static gconstpointer
-gcr_certificate_renderer_real_get_der_data (GcrCertificate *cert, gsize *n_data)
+gcr_certificate_renderer_get_der_data (GcrCertificate *cert, gsize *n_data)
 {
 	GcrCertificateRenderer *self = GCR_CERTIFICATE_RENDERER (cert);
 	GckAttribute *attr;
@@ -641,9 +574,9 @@ gcr_certificate_renderer_real_get_der_data (GcrCertificate *cert, gsize *n_data)
 }
 
 static void
-gcr_certificate_iface_init (GcrCertificateIface *iface)
+gcr_renderer_certificate_iface_init (GcrCertificateIface *iface)
 {
-	iface->get_der_data = gcr_certificate_renderer_real_get_der_data;
+	iface->get_der_data = gcr_certificate_renderer_get_der_data;
 }
 
 /* -----------------------------------------------------------------------------
diff --git a/gcr/gcr-certificate-renderer.h b/gcr/gcr-certificate-renderer.h
index ff58ce3..2cc225b 100644
--- a/gcr/gcr-certificate-renderer.h
+++ b/gcr/gcr-certificate-renderer.h
@@ -57,8 +57,6 @@ struct _GcrCertificateRendererClass {
 
 GType                     gcr_certificate_renderer_get_type           (void);
 
-const GcrModelColumn*     gcr_certificate_renderer_get_columns        (void);
-
 GcrCertificateRenderer*   gcr_certificate_renderer_new                (GcrCertificate *cert);
 
 GcrCertificateRenderer*   gcr_certificate_renderer_new_for_attributes (const gchar *label,
diff --git a/gcr/gcr-certificate.c b/gcr/gcr-certificate.c
index 6b17d28..b7a1289 100644
--- a/gcr/gcr-certificate.c
+++ b/gcr/gcr-certificate.c
@@ -21,8 +21,10 @@
 
 #include "config.h"
 
-#include "gcr-internal.h"
 #include "gcr-certificate.h"
+#include "gcr-comparable.h"
+#include "gcr-icons.h"
+#include "gcr-internal.h"
 
 #include "egg/egg-asn1x.h"
 #include "egg/egg-asn1-defs.h"
@@ -30,6 +32,7 @@
 #include "egg/egg-hex.h"
 
 #include <string.h>
+#include <glib/gi18n-lib.h>
 
 /**
  * SECTION:gcr-certificate
@@ -46,6 +49,15 @@
  *
  * You can use #GcrSimpleCertificate to simply load a certificate for which
  * you already have the raw certificate data.
+ *
+ * The #GcrCertificate interface has several properties that must be implemented.
+ * You can use a mixin to implement these properties if desired. See the
+ * gcr_certificate_mixin_class_init() and gcr_certificate_mixin_get_property()
+ * functions.
+ *
+ * All certificates are comparable. If implementing a #GcrCertificate, you can
+ * use GCR_CERTIFICATE_MIXIN_IMPLEMENT_COMPARABLE() to implement the #GcrComparable
+ * interface.
  */
 
 /* 
@@ -71,6 +83,17 @@ typedef struct _GcrCertificateInfo {
 static gconstpointer _gcr_certificate_get_subject_const (GcrCertificate *self, gsize *n_data);
 static gconstpointer _gcr_certificate_get_issuer_const (GcrCertificate *self, gsize *n_data);
 
+enum {
+	PROP_FIRST = 0x0007000,
+	PROP_LABEL,
+	PROP_MARKUP,
+	PROP_DESCRIPTION,
+	PROP_ICON,
+	PROP_SUBJECT,
+	PROP_ISSUER,
+	PROP_EXPIRY
+};
+
 /* -----------------------------------------------------------------------------
  * INTERNAL 
  */
@@ -223,12 +246,48 @@ digest_certificate (GcrCertificate *self, GChecksumType type)
 	return digest;
 }
 
+static gchar*
+calculate_markup (GcrCertificate *self)
+{
+	gchar *label = NULL;
+	gchar *issuer;
+	gchar *markup;
+
+	g_object_get (self, "label", &label, NULL);
+	issuer = gcr_certificate_get_issuer_cn (self);
+
+	if (issuer)
+		markup = g_markup_printf_escaped ("%s\n<small>Issued by: %s</small>", label, issuer);
+	else
+		markup = g_markup_printf_escaped ("%s\n<small>Issued by: <i>No name</i></small>", label);
+
+	g_free (label);
+	g_free (issuer);
+	return markup;
+}
+
+static gchar*
+calculate_expiry (GcrCertificate *self)
+{
+	GDate *date;
+	gchar *result;
+
+	date = gcr_certificate_get_expiry_date (self);
+	result = g_malloc0 (256);
+	if (!g_date_strftime (result, 256, "%s", date)) {
+		g_free (result);
+		result = NULL;
+	}
+	g_date_free (date);
+	return result;
+}
+
 /* ---------------------------------------------------------------------------------
  * INTERFACE
  */
 
 static void
-gcr_certificate_base_init (gpointer g_class)
+gcr_certificate_iface_init (gpointer gobject_iface)
 {
 	static volatile gsize initialized = 0;
 
@@ -237,7 +296,33 @@ gcr_certificate_base_init (gpointer g_class)
 		OID_RSA_KEY = g_quark_from_static_string ("1.2.840.113549.1.1.1");
 		OID_DSA_KEY = g_quark_from_static_string ("1.2.840.10040.4.1");
 
-		/* Add properties and signals to the interface */
+		g_object_interface_install_property (gobject_iface,
+		         g_param_spec_string ("label", "Label", "Certificate label",
+		                              "", G_PARAM_READABLE));
+
+		g_object_interface_install_property (gobject_iface,
+		         g_param_spec_string ("description", "Description", "Description of object being rendered",
+		                              "", G_PARAM_READABLE));
+
+		g_object_interface_install_property (gobject_iface,
+		         g_param_spec_string ("markup", "Markup", "Markup which describes object being rendered",
+		                              "", G_PARAM_READABLE));
+
+		g_object_interface_install_property (gobject_iface,
+		         g_param_spec_object ("icon", "Icon", "Icon for the object being rendered",
+		                              G_TYPE_ICON, G_PARAM_READABLE));
+
+		g_object_interface_install_property (gobject_iface,
+		           g_param_spec_string ("subject", "Subject", "Common name of subject",
+		                                "", G_PARAM_READABLE));
+
+		g_object_interface_install_property (gobject_iface,
+		           g_param_spec_string ("issuer", "Issuer", "Common name of issuer",
+		                                "", G_PARAM_READABLE));
+
+		g_object_interface_install_property (gobject_iface,
+		           g_param_spec_string ("expiry", "Expiry", "Certificate expiry",
+		                                "", G_PARAM_READABLE));
 
 		g_once_init_leave (&initialized, 1);
 	}
@@ -250,7 +335,7 @@ gcr_certificate_get_type (void)
 	if (!type) {
 		static const GTypeInfo info = {
 			sizeof (GcrCertificateIface),
-			gcr_certificate_base_init,               /* base init */
+			gcr_certificate_iface_init,               /* base init */
 			NULL,             /* base finalize */
 			NULL,             /* class_init */
 			NULL,             /* class finalize */
@@ -260,17 +345,58 @@ gcr_certificate_get_type (void)
 			NULL,             /* instance init */
 		};
 		type = g_type_register_static (G_TYPE_INTERFACE, "GcrCertificateIface", &info, 0);
-		g_type_interface_add_prerequisite (type, G_TYPE_OBJECT);
+		g_type_interface_add_prerequisite (type, GCR_TYPE_COMPARABLE);
 	}
 	
 	return type;
 }
 
-
 /* -----------------------------------------------------------------------------
  * PUBLIC 
  */
 
+const GcrColumn*
+gcr_certificate_get_columns (void)
+{
+	static GcrColumn columns[] = {
+		{ "icon", 0, NULL, 0 },
+		{ "label", G_TYPE_STRING, N_("Name"), 0 },
+		{ "description", G_TYPE_STRING, N_("Type"), 0 },
+		{ "subject", G_TYPE_STRING, N_("Subject"), 0 },
+		{ "issuer", G_TYPE_STRING, N_("Issued By"), 0 },
+		{ "expiry", G_TYPE_STRING, N_("Expires"), 0 },
+		{ NULL }
+	};
+
+	columns[0].type = G_TYPE_ICON;
+	return columns;
+}
+
+gint
+gcr_certificate_compare (GcrComparable *first, GcrComparable *other)
+{
+	gconstpointer data1, data2;
+	gsize size1, size2;
+
+	if (!GCR_IS_CERTIFICATE (first))
+		first = NULL;
+	if (!GCR_IS_CERTIFICATE (other))
+		other = NULL;
+
+	if (first == other)
+		return TRUE;
+	if (!first)
+		return 1;
+	if (!other)
+		return -1;
+
+	data1 = gcr_certificate_get_der_data (GCR_CERTIFICATE (first), &size1);
+	data2 = gcr_certificate_get_der_data (GCR_CERTIFICATE (other), &size2);
+
+	return gcr_comparable_memcmp (data1, size1, data2, size2);
+}
+
+
 /**
  * gcr_certificate_get_der_data:
  * @self: a #GcrCertificate
@@ -752,3 +878,148 @@ gcr_certificate_get_serial_number_hex (GcrCertificate *self)
 	g_free (serial);
 	return hex;
 }
+
+GIcon*
+gcr_certificate_get_icon (GcrCertificate *self)
+{
+	g_return_val_if_fail (GCR_IS_CERTIFICATE (self), FALSE);
+	return g_themed_icon_new (GCR_ICON_CERTIFICATE);
+}
+
+/* -----------------------------------------------------------------------------
+ * MIXIN
+ */
+
+/**
+ * GCR_CERTIFICATE_MIXIN_IMPLEMENT_COMPARABLE:
+ *
+ * Implement the GcrComparable interface. Use this macro like this:
+ *
+ * <informalexample><programlisting>
+ * G_DEFINE_TYPE_WITH_CODE (MyCertificate, my_certificate, G_TYPE_OBJECT,
+ *	GCR_CERTIFICATE_MIXIN_IMPLEMENT_COMPARABLE ();
+ *	G_IMPLEMENT_INTERFACE (GCR_TYPE_CERTIFICATE, my_certificate_iface_init);
+ * );
+ * </programlisting></informalexample>
+ */
+
+/**
+ * gcr_certificate_mixin_comparable_init:
+ * @iface: The interface
+ *
+ * Initialize a #GcrComparableIface to compare the current certificate.
+ * In general it's easier to use the GCR_CERTIFICATE_MIXIN_IMPLEMENT_COMPARABLE()
+ * macro instead of this function.
+ */
+void
+gcr_certificate_mixin_comparable_init (GcrComparableIface *iface)
+{
+	iface->compare = gcr_certificate_compare;
+}
+
+/**
+ * gcr_certificate_mixin_class_init:
+ * @object_class: The GObjectClass for this class
+ *
+ * Initialize the certificate mixin for the class. This mixin implements the
+ * various required properties for the certificate.
+ *
+ * Call this function near the end of your derived class_init() function. The
+ * derived class must implement the #GcrCertificate interface.
+ */
+void
+gcr_certificate_mixin_class_init (GObjectClass *object_class)
+{
+	if (!g_object_class_find_property (object_class, "description"))
+		g_object_class_override_property (object_class, PROP_DESCRIPTION, "description");
+	if (!g_object_class_find_property (object_class, "markup"))
+		g_object_class_override_property (object_class, PROP_MARKUP, "markup");
+	if (!g_object_class_find_property (object_class, "label"))
+		g_object_class_override_property (object_class, PROP_LABEL, "label");
+	if (!g_object_class_find_property (object_class, "icon"))
+		g_object_class_override_property (object_class, PROP_ICON, "icon");
+	if (!g_object_class_find_property (object_class, "subject"))
+		g_object_class_override_property (object_class, PROP_SUBJECT, "subject");
+	if (!g_object_class_find_property (object_class, "issuer"))
+		g_object_class_override_property (object_class, PROP_ISSUER, "issuer");
+	if (!g_object_class_find_property (object_class, "expiry"))
+		g_object_class_override_property (object_class, PROP_EXPIRY, "expiry");
+
+	_gcr_initialize ();
+}
+
+/**
+ * gcr_certificate_mixin_get_property:
+ * @obj: The object
+ * @prop_id: The property id
+ * @value: The value to fill in.
+ * @pspec: The param specification.
+ *
+ * Implementation to get various required certificate properties. This should
+ * be called from your derived class get_property function, or used as a
+ * get_property virtual function.
+ *
+ * Example of use as called from derived class get_property function:
+ *
+ * <informalexample><programlisting>
+ * static void
+ * my_get_property (GObject *obj, guint prop_id, GValue *value, GParamSpec *pspec)
+ * {
+ * 	switch (prop_id) {
+ *
+ * 	...
+ *
+ * 	default:
+ * 		gcr_certificate_mixin_get_property (obj, prop_id, value, pspec);
+ * 		break;
+ * 	}
+ *}
+ * </programlisting></informalexample>
+ *
+ * Example of use as get_property function:
+ *
+ * <informalexample><programlisting>
+ * static void
+ * my_class_init (MyClass *klass)
+ * {
+ * 	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ * 	gobject_class->get_property = gcr_certificate_mixin_get_property;
+ *
+ * 	...
+ * }
+ * </programlisting></informalexample>
+
+ */
+void
+gcr_certificate_mixin_get_property (GObject *obj, guint prop_id,
+                                    GValue *value, GParamSpec *pspec)
+{
+	GcrCertificate *cert = GCR_CERTIFICATE (obj);
+
+	switch (prop_id) {
+	case PROP_LABEL:
+		g_value_take_string (value, gcr_certificate_get_subject_cn (cert));
+		break;
+	case PROP_SUBJECT:
+		g_value_take_string (value, gcr_certificate_get_subject_cn (cert));
+		break;
+	case PROP_ICON:
+		g_value_set_object (value, gcr_certificate_get_icon (cert));
+		break;
+	case PROP_DESCRIPTION:
+		g_value_set_string (value, _("Certificate"));
+		break;
+	case PROP_MARKUP:
+		g_value_take_string (value, calculate_markup (cert));
+		break;
+	case PROP_ISSUER:
+		g_value_take_string (value, gcr_certificate_get_issuer_cn (cert));
+		break;
+	case PROP_EXPIRY:
+		g_value_take_string (value, calculate_expiry (cert));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+		break;
+	}
+}
diff --git a/gcr/gcr-certificate.h b/gcr/gcr-certificate.h
index 1232500..32b37b6 100644
--- a/gcr/gcr-certificate.h
+++ b/gcr/gcr-certificate.h
@@ -27,23 +27,27 @@
 #define __GCR_CERTIFICATE_H__
 
 #include "gcr-types.h"
+#include "gcr-column.h"
+#include "gcr-comparable.h"
 
 #include <glib-object.h>
+#include <gio/gio.h>
 
 G_BEGIN_DECLS
 
-#define GCR_TYPE_CERTIFICATE                 (gcr_certificate_get_type())
-#define GCR_CERTIFICATE(obj)                 (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_CERTIFICATE, GcrCertificate))
-#define GCR_IS_CERTIFICATE(obj)              (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_CERTIFICATE))
-#define GCR_CERTIFICATE_GET_INTERFACE(inst)  (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GCR_TYPE_CERTIFICATE, GcrCertificateIface))
+#define GCR_CERTIFICATE_COLUMNS                 (gcr_certificate_get_columns ())
+#define GCR_TYPE_CERTIFICATE                    (gcr_certificate_get_type ())
+#define GCR_CERTIFICATE(obj)                    (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_CERTIFICATE, GcrCertificate))
+#define GCR_IS_CERTIFICATE(obj)                 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_CERTIFICATE))
+#define GCR_CERTIFICATE_GET_INTERFACE(inst)     (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GCR_TYPE_CERTIFICATE, GcrCertificateIface))
 
-typedef struct _GcrCertificate      GcrCertificate;
-typedef struct _GcrCertificateIface GcrCertificateIface;
+typedef struct _GcrCertificate          GcrCertificate;
+typedef struct _GcrCertificateIface     GcrCertificateIface;
 
 struct _GcrCertificateIface {
 	GTypeInterface parent;
 
-	gconstpointer (*get_der_data)   (GcrCertificate *self, gsize *n_data);
+	gconstpointer (*get_der_data) (GcrCertificate *self, gsize *n_data);
 
 	gpointer dummy1;
 	gpointer dummy2;
@@ -59,6 +63,11 @@ GType               gcr_certificate_get_type               (void);
 gconstpointer       gcr_certificate_get_der_data           (GcrCertificate *self,
                                                             gsize *n_data);
 
+const GcrColumn*    gcr_certificate_get_columns            (void);
+
+gint                gcr_certificate_compare                (GcrComparable *self,
+                                                            GcrComparable *other);
+
 gchar*              gcr_certificate_get_issuer_cn          (GcrCertificate *self);
 
 gchar*              gcr_certificate_get_issuer_dn          (GcrCertificate *self);
@@ -100,6 +109,20 @@ guchar*             gcr_certificate_get_fingerprint        (GcrCertificate *self
 gchar*              gcr_certificate_get_fingerprint_hex    (GcrCertificate *self, 
                                                             GChecksumType type);
 
+GIcon*              gcr_certificate_get_icon               (GcrCertificate *self);
+
+#define GCR_CERTIFICATE_MIXIN_IMPLEMENT_COMPARABLE() \
+	G_IMPLEMENT_INTERFACE (GCR_TYPE_COMPARABLE, gcr_certificate_mixin_comparable_init)
+
+void                gcr_certificate_mixin_comparable_init  (GcrComparableIface *iface);
+
+void                gcr_certificate_mixin_class_init       (GObjectClass *object_class);
+
+void                gcr_certificate_mixin_get_property     (GObject *obj,
+                                                            guint prop_id,
+                                                            GValue *value,
+                                                            GParamSpec *pspec);
+
 G_END_DECLS
 
 #endif /* __GCR_CERTIFICATE_H__ */
diff --git a/gcr/gcr-collection-model.c b/gcr/gcr-collection-model.c
index db05bea..5c8d753 100644
--- a/gcr/gcr-collection-model.c
+++ b/gcr/gcr-collection-model.c
@@ -33,6 +33,7 @@ enum {
 struct _GcrCollectionModelPrivate {
 	GcrCollection *collection;
 	GHashTable *object_to_index;
+	GHashTable *toggled_active;
 
 	gint cache_stamp;
 	gint last_stamp;
@@ -50,6 +51,8 @@ static void gcr_collection_model_tree_model (GtkTreeModelIface *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));
 
+#define UNUSED_VALUE GUINT_TO_POINTER (1)
+
 /* -----------------------------------------------------------------------------
  * INTERNAL
  */
@@ -304,6 +307,15 @@ gcr_collection_model_real_get_value (GtkTreeModel *model, GtkTreeIter *iter,
 	g_return_if_fail (G_IS_OBJECT (object));
 	g_return_if_fail (column >= 0 && column < self->pv->n_columns);
 
+	/* The selected column? */
+	if (column == self->pv->n_columns - 1) {
+		g_assert (!self->pv->column_names[column]);
+		g_assert (self->pv->column_types[column] == G_TYPE_BOOLEAN);
+		g_value_init (value, G_TYPE_BOOLEAN);
+		g_value_set_boolean (value, gcr_collection_model_get_selected (self, iter));
+		return;
+	}
+
 	/* Figure out which property */
 	type = self->pv->column_types[column];
 	property = self->pv->column_names[column];
@@ -494,7 +506,7 @@ gcr_collection_model_dispose (GObject *object)
 	/* Disconnect from all rows */
 	for (i = self->pv->objects->len; i > 0; --i) {
 		obj = g_ptr_array_index (self->pv->objects, i - 1);
-		disconnect_object (self, object);
+		disconnect_object (self, obj);
 	}
 
 	/* Disconnect from the collection */
@@ -505,6 +517,9 @@ gcr_collection_model_dispose (GObject *object)
 		self->pv->collection = NULL;
 	}
 
+	if (self->pv->toggled_active)
+		g_hash_table_remove_all (self->pv->toggled_active);
+
 	G_OBJECT_CLASS (gcr_collection_model_parent_class)->dispose (object);
 }
 
@@ -524,6 +539,10 @@ gcr_collection_model_finalize (GObject *object)
 	g_ptr_array_free (self->pv->objects, TRUE);
 	self->pv->objects = NULL;
 
+	if (self->pv->toggled_active)
+		g_hash_table_destroy (self->pv->toggled_active);
+	self->pv->toggled_active = NULL;
+
 	if (self->pv->column_names) {
 		g_strfreev (self->pv->column_names);
 		self->pv->column_names = NULL;
@@ -563,14 +582,14 @@ gcr_collection_model_class_init (GcrCollectionModelClass *klass)
 GcrCollectionModel*
 gcr_collection_model_new (GcrCollection *collection, ...)
 {
-	GcrModelColumn column;
+	GcrColumn column;
 	GcrCollectionModel *self;
 	const gchar *arg;
 	GArray *array;
 	va_list va;
 
 	/* With a null terminator */
-	array = g_array_new (TRUE, TRUE, sizeof (GcrModelColumn));
+	array = g_array_new (TRUE, TRUE, sizeof (GcrColumn));
 
 	va_start (va, collection);
 	while ((arg = va_arg (va, const gchar*)) != NULL) {
@@ -582,13 +601,13 @@ gcr_collection_model_new (GcrCollection *collection, ...)
 	}
 	va_end (va);
 
-	self = gcr_collection_model_new_full (collection, (GcrModelColumn*)array->data);
+	self = gcr_collection_model_new_full (collection, (GcrColumn*)array->data);
 	g_array_free (array, TRUE);
 	return self;
 }
 
 GcrCollectionModel*
-gcr_collection_model_new_full (GcrCollection *collection, const GcrModelColumn *columns)
+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);
@@ -596,27 +615,32 @@ gcr_collection_model_new_full (GcrCollection *collection, const GcrModelColumn *
 }
 
 gint
-gcr_collection_model_set_columns (GcrCollectionModel *self, const GcrModelColumn *columns)
+gcr_collection_model_set_columns (GcrCollectionModel *self, const GcrColumn *columns)
 {
-	const GcrModelColumn *col;
+	const GcrColumn *col;
 	guint i, n_columns;
 
 	g_return_val_if_fail (GCR_IS_COLLECTION_MODEL (self), -1);
 	g_return_val_if_fail (self->pv->n_columns == 0, -1);
 
-	/* Count the number of columns */
-	for (col = columns, n_columns = 0; col->property; ++col)
+	/* Count the number of columns, extra column for selected */
+	for (col = columns, n_columns = 1; col->property; ++col)
 		++n_columns;
 
 	self->pv->column_names = g_new0 (gchar*, n_columns + 1);
 	self->pv->column_types = g_new0 (GType, n_columns + 1);
 	self->pv->n_columns = n_columns;
 
-	for (i = 0; i < n_columns; ++i) {
+	/* All the columns, except the selected column */
+	for (i = 0; i < n_columns - 1; ++i) {
 		self->pv->column_names[i] = g_strdup (columns[i].property);
 		self->pv->column_types[i] = columns[i].type;
 	}
 
+	/* The selected column */
+	self->pv->column_names[i] = NULL;
+	self->pv->column_types[i] = G_TYPE_BOOLEAN;
+
 	return n_columns - 1;
 }
 
@@ -647,3 +671,65 @@ gcr_collection_model_iter_for_object (GcrCollectionModel *self, GObject *object,
 
 	return iter_for_index (self, index, iter);
 }
+
+guint
+gcr_collection_model_column_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;
+}
+
+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->toggled_active)
+		self->pv->toggled_active = g_hash_table_new (g_direct_hash, g_direct_equal);
+
+	if (g_hash_table_lookup (self->pv->toggled_active, object))
+		g_hash_table_remove (self->pv->toggled_active, object);
+	else
+		g_hash_table_insert (self->pv->toggled_active, object, UNUSED_VALUE);
+}
+
+void
+gcr_collection_model_set_selected (GcrCollectionModel *self, GtkTreeIter *iter, gboolean selected)
+{
+	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->toggled_active)
+		self->pv->toggled_active = g_hash_table_new (g_direct_hash, g_direct_equal);
+
+	if (selected)
+		g_hash_table_insert (self->pv->toggled_active, object, UNUSED_VALUE);
+	else
+		g_hash_table_remove (self->pv->toggled_active, object);
+}
+
+gboolean
+gcr_collection_model_get_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->toggled_active)
+		return FALSE;
+
+	return g_hash_table_lookup (self->pv->toggled_active, object) ? TRUE : FALSE;
+}
diff --git a/gcr/gcr-collection-model.h b/gcr/gcr-collection-model.h
index fb750d2..1765126 100644
--- a/gcr/gcr-collection-model.h
+++ b/gcr/gcr-collection-model.h
@@ -54,10 +54,10 @@ GcrCollectionModel*   gcr_collection_model_new                 (GcrCollection *c
                                                                 ...) G_GNUC_NULL_TERMINATED;
 
 GcrCollectionModel*   gcr_collection_model_new_full            (GcrCollection *collection,
-                                                                const GcrModelColumn *columns);
+                                                                const GcrColumn *columns);
 
 gint                  gcr_collection_model_set_columns         (GcrCollectionModel *self,
-                                                                const GcrModelColumn *columns);
+                                                                const GcrColumn *columns);
 
 GObject*              gcr_collection_model_object_for_iter     (GcrCollectionModel *self,
                                                                 const GtkTreeIter *iter);
@@ -66,4 +66,16 @@ gboolean              gcr_collection_model_iter_for_object     (GcrCollectionMod
                                                                 GObject *object,
                                                                 GtkTreeIter *iter);
 
+guint                 gcr_collection_model_column_selected     (GcrCollectionModel *self);
+
+void                  gcr_collection_model_toggle_selected     (GcrCollectionModel *self,
+                                                                GtkTreeIter *iter);
+
+void                  gcr_collection_model_set_selected        (GcrCollectionModel *self,
+                                                                GtkTreeIter *iter,
+                                                                gboolean selected);
+
+gboolean              gcr_collection_model_get_selected        (GcrCollectionModel *self,
+                                                                GtkTreeIter *iter);
+
 #endif /* __GCR_COLLECTION_MODEL_H__ */
diff --git a/gcr/gcr-column.h b/gcr/gcr-column.h
index ce26da7..53a3530 100644
--- a/gcr/gcr-column.h
+++ b/gcr/gcr-column.h
@@ -28,12 +28,13 @@
 
 G_BEGIN_DECLS
 
-typedef struct _GcrModelColumn {
+typedef struct _GcrColumn {
 	const gchar *property;
 	GType type;
 	const gchar *label;
+	gpointer user_data;
 	gpointer reserved;
-} GcrModelColumn;
+} GcrColumn;
 
 G_END_DECLS
 
diff --git a/gcr/gcr-comparable.c b/gcr/gcr-comparable.c
new file mode 100644
index 0000000..3f4d513
--- /dev/null
+++ b/gcr/gcr-comparable.c
@@ -0,0 +1,103 @@
+/*
+ * 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 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.
+ */
+
+#include "config.h"
+
+#include "gcr-comparable.h"
+
+#include <string.h>
+
+/* ---------------------------------------------------------------------------------
+ * INTERFACE
+ */
+
+static void
+gcr_comparable_base_init (gpointer g_class)
+{
+	static volatile gsize initialized = 0;
+
+	if (g_once_init_enter (&initialized)) {
+		/* Add properties and signals to the interface */
+		g_once_init_leave (&initialized, 1);
+	}
+}
+
+GType
+gcr_comparable_get_type (void)
+{
+	static GType type = 0;
+	if (!type) {
+		static const GTypeInfo info = {
+			sizeof (GcrComparableIface),
+			gcr_comparable_base_init,               /* base init */
+			NULL,             /* base finalize */
+			NULL,             /* class_init */
+			NULL,             /* class finalize */
+			NULL,             /* class data */
+			0,
+			0,                /* n_preallocs */
+			NULL,             /* instance init */
+		};
+		type = g_type_register_static (G_TYPE_INTERFACE, "GcrComparableIface", &info, 0);
+		g_type_interface_add_prerequisite (type, G_TYPE_OBJECT);
+	}
+
+	return type;
+}
+
+
+/* -----------------------------------------------------------------------------
+ * PUBLIC
+ */
+
+gint
+gcr_comparable_compare (GcrComparable *self, GcrComparable *other)
+{
+	g_return_val_if_fail (GCR_IS_COMPARABLE (self), -1);
+	g_return_val_if_fail (GCR_COMPARABLE_GET_INTERFACE (self)->compare, -1);
+	g_return_val_if_fail (G_IS_OBJECT (self), -1);
+	return GCR_COMPARABLE_GET_INTERFACE (self)->compare (self, other);
+}
+
+gint
+gcr_comparable_memcmp (gconstpointer mem1, gsize size1,
+                       gconstpointer mem2, gsize size2)
+{
+	gint result;
+
+	if (mem1 == mem2 && size1 == size2)
+		return 0;
+
+	if (!mem1)
+		return 1;
+	if (!mem2)
+		return -1;
+
+	result = memcmp (mem1, mem2, MIN (size1, size2));
+	if (result != 0)
+		return result;
+
+	if (size1 == size2)
+		return 0;
+	if (size1 < size2)
+		return -1;
+	return 1;
+}
diff --git a/gcr/gcr-comparable.h b/gcr/gcr-comparable.h
new file mode 100644
index 0000000..39f1d8a
--- /dev/null
+++ b/gcr/gcr-comparable.h
@@ -0,0 +1,54 @@
+/*
+ * 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 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.
+ */
+
+#ifndef __GCR_COMPARABLE_H__
+#define __GCR_COMPARABLE_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GCR_TYPE_COMPARABLE                 (gcr_comparable_get_type())
+#define GCR_COMPARABLE(obj)                 (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_COMPARABLE, GcrComparable))
+#define GCR_IS_COMPARABLE(obj)              (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_COMPARABLE))
+#define GCR_COMPARABLE_GET_INTERFACE(inst)  (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GCR_TYPE_COMPARABLE, GcrComparableIface))
+
+typedef struct _GcrComparable      GcrComparable;
+typedef struct _GcrComparableIface GcrComparableIface;
+
+struct _GcrComparableIface {
+	GTypeInterface parent;
+	gint (*compare) (GcrComparable *self, GcrComparable *other);
+};
+
+GType               gcr_comparable_get_type               (void);
+
+gint                gcr_comparable_compare                (GcrComparable *self,
+                                                           GcrComparable *other);
+
+gint                gcr_comparable_memcmp                 (gconstpointer mem1,
+                                                           gsize size1,
+                                                           gconstpointer mem2,
+                                                           gsize size2);
+
+G_END_DECLS
+
+#endif /* __GCR_COMPARABLE_H__ */
diff --git a/gcr/gcr-library.c b/gcr/gcr-library.c
index 0e65f31..d66bed3 100644
--- a/gcr/gcr-library.c
+++ b/gcr/gcr-library.c
@@ -179,11 +179,11 @@ _gcr_initialize (void)
 		trust_lookup_uris[1] = g_strdup ("pkcs11:library-manufacturer=GNOME%20Keyring;serial=1:XDG:DEFAULT");
 		trust_lookup_uris[2] = NULL;
 
-		g_type_class_unref (g_type_class_ref (GCR_TYPE_CERTIFICATE_RENDERER));
-		g_type_class_unref (g_type_class_ref (GCR_TYPE_KEY_RENDERER));
-
 		g_once_init_leave (&gcr_initialized, 1);
 	}
+
+	g_type_class_unref (g_type_class_ref (GCR_TYPE_CERTIFICATE_RENDERER));
+	g_type_class_unref (g_type_class_ref (GCR_TYPE_KEY_RENDERER));
 }
 
 /**
diff --git a/gcr/gcr-pkcs11-certificate.c b/gcr/gcr-pkcs11-certificate.c
index e8dbd31..998c89b 100644
--- a/gcr/gcr-pkcs11-certificate.c
+++ b/gcr/gcr-pkcs11-certificate.c
@@ -60,7 +60,9 @@ struct _GcrPkcs11CertificatePrivate {
 
 static void gcr_certificate_iface (GcrCertificateIface *iface);
 G_DEFINE_TYPE_WITH_CODE (GcrPkcs11Certificate, gcr_pkcs11_certificate, GCK_TYPE_OBJECT,
-                         G_IMPLEMENT_INTERFACE (GCR_TYPE_CERTIFICATE, gcr_certificate_iface));
+	GCR_CERTIFICATE_MIXIN_IMPLEMENT_COMPARABLE ();
+	G_IMPLEMENT_INTERFACE (GCR_TYPE_CERTIFICATE, gcr_certificate_iface);
+);
 
 /* ----------------------------------------------------------------------------
  * INTERAL
@@ -235,7 +237,7 @@ gcr_pkcs11_certificate_get_property (GObject *obj, guint prop_id, GValue *value,
 		g_value_set_boxed (value, gcr_pkcs11_certificate_get_attributes (self));
 		break;
 	default:
-		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+		gcr_certificate_mixin_get_property (obj, prop_id, value, pspec);
 		break;
 	}
 }
@@ -271,13 +273,14 @@ gcr_pkcs11_certificate_class_init (GcrPkcs11CertificateClass *klass)
 
 	g_type_class_add_private (gobject_class, sizeof (GcrPkcs11CertificatePrivate));
 
+	gcr_certificate_mixin_class_init (gobject_class);
 	_gcr_initialize ();
 }
 
 static gconstpointer
-gcr_pkcs11_certificate_real_get_der_data (GcrCertificate *base, gsize *n_data)
+gcr_pkcs11_certificate_get_der_data (GcrCertificate *cert, gsize *n_data)
 {
-	GcrPkcs11Certificate *self = GCR_PKCS11_CERTIFICATE (base);
+	GcrPkcs11Certificate *self = GCR_PKCS11_CERTIFICATE (cert);
 	GckAttribute *attr;
 
 	g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL);
@@ -293,7 +296,7 @@ gcr_pkcs11_certificate_real_get_der_data (GcrCertificate *base, gsize *n_data)
 static void
 gcr_certificate_iface (GcrCertificateIface *iface)
 {
-	iface->get_der_data = (gpointer)gcr_pkcs11_certificate_real_get_der_data;
+	iface->get_der_data = gcr_pkcs11_certificate_get_der_data;
 }
 
 /* -----------------------------------------------------------------------------
diff --git a/gcr/gcr-renderer.c b/gcr/gcr-renderer.c
index 46afac1..8d96dd9 100644
--- a/gcr/gcr-renderer.c
+++ b/gcr/gcr-renderer.c
@@ -56,18 +56,6 @@ gcr_renderer_base_init (gpointer gobject_iface)
 		         g_param_spec_boxed ("attributes", "Attributes", "The data displayed in the renderer",
 		                             GCK_TYPE_ATTRIBUTES, G_PARAM_READWRITE));
 
-		g_object_interface_install_property (gobject_iface,
-		         g_param_spec_string ("description", "Description", "Description of object being rendered",
-		                              "", G_PARAM_READABLE));
-
-		g_object_interface_install_property (gobject_iface,
-		         g_param_spec_string ("markup", "Markup", "Markup which describes object being rendered",
-		                              "", G_PARAM_READABLE));
-
-		g_object_interface_install_property (gobject_iface,
-		         g_param_spec_object ("icon", "Icon", "Icon for the object being rendered",
-		                              G_TYPE_ICON, G_PARAM_READABLE));
-
 		signals[DATA_CHANGED] = g_signal_new ("data-changed", GCR_TYPE_RENDERER, G_SIGNAL_RUN_LAST,
 		                                      G_STRUCT_OFFSET (GcrRendererIface, data_changed),
 		                                      NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
@@ -188,24 +176,3 @@ gcr_renderer_register (GType renderer_type, GckAttributes *attrs)
 	g_array_append_val (registered_renderers, registered);
 	registered_sorted = FALSE;
 }
-
-const GcrModelColumn*
-gcr_renderer_columns (GType renderer_type)
-{
-	const GcrModelColumn *columns;
-	GcrRendererIface *renderer;
-	GTypeClass *klass;
-
-	klass = g_type_class_ref (renderer_type);
-	g_return_val_if_fail (klass, NULL);
-
-	renderer = g_type_interface_peek (klass, GCR_TYPE_RENDERER);
-	g_return_val_if_fail (renderer, NULL);
-
-	columns = renderer->column_info;
-	g_return_val_if_fail (columns, NULL);
-
-	g_type_class_unref (klass);
-
-	return columns;
-}
diff --git a/gcr/gcr-renderer.h b/gcr/gcr-renderer.h
index 2676dd2..e262508 100644
--- a/gcr/gcr-renderer.h
+++ b/gcr/gcr-renderer.h
@@ -40,9 +40,6 @@ typedef struct _GcrRendererIface GcrRendererIface;
 struct _GcrRendererIface {
 	GTypeInterface parent;
 
-	/* data */
-	const GcrModelColumn *column_info;
-
 	/* signals */
 	void (*data_changed) (GcrRenderer *self);
 
@@ -84,8 +81,6 @@ void                      gcr_renderer_emit_data_changed          (GcrRenderer *
 GcrRenderer*              gcr_renderer_create                     (const gchar *label,
                                                                    GckAttributes *attrs);
 
-const GcrModelColumn*     gcr_renderer_columns                    (GType renderer_type);
-
 void                      gcr_renderer_register                   (GType renderer_type,
                                                                    GckAttributes *attrs);
 
diff --git a/gcr/gcr-selector.c b/gcr/gcr-selector.c
new file mode 100644
index 0000000..334c2d3
--- /dev/null
+++ b/gcr/gcr-selector.c
@@ -0,0 +1,364 @@
+/*
+ * 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 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.
+ */
+
+#include "config.h"
+
+#include "gcr-collection-model.h"
+#include "gcr-internal.h"
+#include "gcr-selector.h"
+
+enum {
+	PROP_0,
+	PROP_COLLECTION,
+	PROP_COLUMNS,
+	PROP_MODE
+};
+
+#if 0
+enum {
+	XXXX,
+	LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+#endif
+
+struct _GcrSelectorPrivate {
+	GtkComboBox *combo;
+	GtkTreeView *tree;
+	GcrCollection *collection;
+	const GcrColumn *columns;
+	GcrCollectionModel *model;
+	GcrSelectorMode mode;
+};
+
+G_DEFINE_TYPE (GcrSelector, gcr_selector, GTK_TYPE_ALIGNMENT);
+
+/* -----------------------------------------------------------------------------
+ * INTERNAL
+ */
+
+static void
+on_check_column_toggled (GtkCellRendererToggle *cell, gchar *path, GcrCollectionModel *model)
+{
+	GtkTreeIter iter;
+
+	g_assert (path != NULL);
+
+	if (gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (model), &iter, path))
+		gcr_collection_model_toggle_selected (model, &iter);
+}
+
+static void
+add_string_column (GcrSelector *self, const GcrColumn *column, guint index)
+{
+	GtkCellRenderer *cell;
+	GtkTreeViewColumn *col;
+
+	g_assert (column->type == G_TYPE_STRING);
+
+	cell = gtk_cell_renderer_text_new ();
+	g_object_set (G_OBJECT (cell), "ellipsize", PANGO_ELLIPSIZE_END, NULL);
+	col = gtk_tree_view_column_new_with_attributes (column->label, cell, "text", index, NULL);
+	gtk_tree_view_column_set_resizable (col, TRUE);
+	gtk_tree_view_append_column (self->pv->tree, col);
+}
+
+static void
+add_icon_column (GcrSelector *self, const GcrColumn *column, guint index)
+{
+	GtkCellRenderer *cell;
+	GtkTreeViewColumn *col;
+
+	g_assert (column->type == G_TYPE_ICON);
+
+	cell = gtk_cell_renderer_pixbuf_new ();
+	g_object_set (cell, "stock-size", GTK_ICON_SIZE_BUTTON, NULL);
+	col = gtk_tree_view_column_new_with_attributes (column->label, cell, "gicon", index, NULL);
+	gtk_tree_view_column_set_resizable (col, TRUE);
+	gtk_tree_view_append_column (self->pv->tree, col);
+}
+
+static void
+add_check_column (GcrSelector *self, guint index)
+{
+	GtkCellRenderer *cell;
+	GtkTreeViewColumn *col;
+
+	cell = gtk_cell_renderer_toggle_new ();
+	g_signal_connect (cell, "toggled", G_CALLBACK (on_check_column_toggled), self->pv->model);
+
+	col = gtk_tree_view_column_new_with_attributes ("", cell, "active", index, NULL);
+	gtk_tree_view_column_set_resizable (col, FALSE);
+	gtk_tree_view_append_column (self->pv->tree, col);
+}
+
+static void
+construct_single_selector (GcrSelector *self)
+{
+	GtkCellRenderer *cell;
+	GtkWidget *widget;
+
+	self->pv->model = gcr_collection_model_new (self->pv->collection,
+	                                            "icon", G_TYPE_ICON,
+	                                            "markup", G_TYPE_STRING,
+	                                            NULL);
+
+	widget = gtk_combo_box_new_with_model (GTK_TREE_MODEL (self->pv->model));
+	self->pv->combo = GTK_COMBO_BOX (widget);
+
+	/* The icon */
+	cell = gtk_cell_renderer_pixbuf_new ();
+	g_object_set (cell, "stock-size", GTK_ICON_SIZE_DND, NULL);
+	gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (widget), cell, FALSE);
+	gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (widget), cell, "gicon", 0);
+
+	/* The markup */
+	cell = gtk_cell_renderer_text_new ();
+	gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (widget), cell, TRUE);
+	gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (widget), cell, "markup", 1);
+
+	gtk_widget_show (widget);
+	gtk_container_add (GTK_CONTAINER (self), widget);
+}
+
+static void
+construct_multiple_selector (GcrSelector *self)
+{
+	const GcrColumn *column;
+	GtkWidget *widget, *scroll;
+	guint i;
+
+	self->pv->model = gcr_collection_model_new_full (self->pv->collection,
+	                                                 self->pv->columns);
+
+	widget = gtk_tree_view_new_with_model (GTK_TREE_MODEL (self->pv->model));
+	self->pv->tree = GTK_TREE_VIEW (widget);
+
+	/* First add the check mark column */
+	add_check_column (self, gcr_collection_model_column_selected (self->pv->model));
+
+	for (column = self->pv->columns, i = 0; column->property; ++column, ++i) {
+		if (column->type == G_TYPE_STRING)
+			add_string_column (self, column, i);
+		else if (column->type == G_TYPE_ICON)
+			add_icon_column (self, column, i);
+		else {
+			g_warning ("skipping unsupported column '%s' of type: %s",
+			           column->label, g_type_name (column->type));
+		}
+	}
+
+	scroll = gtk_scrolled_window_new (NULL, NULL);
+	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scroll), GTK_SHADOW_ETCHED_IN);
+	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+	gtk_container_add (GTK_CONTAINER (scroll), widget);
+	gtk_container_add (GTK_CONTAINER (self), scroll);
+
+	gtk_widget_show_all (scroll);
+}
+
+/* -----------------------------------------------------------------------------
+ * OBJECT
+ */
+
+GType
+gcr_selector_mode_get_type (void)
+{
+	static GType type = 0;
+	static GEnumValue values[] = {
+		{ GCR_SELECTOR_MODE_SINGLE, "single", "Single"},
+		{ GCR_SELECTOR_MODE_MULTIPLE, "multiple", "Multiple"},
+		{ 0, NULL, NULL }
+	};
+	if (!type)
+		type = g_enum_register_static ("GcrSelectorMode", values);
+	return type;
+}
+
+static GObject*
+gcr_selector_constructor (GType type, guint n_props, GObjectConstructParam *props)
+{
+	GcrSelector *self = GCR_SELECTOR (G_OBJECT_CLASS (gcr_selector_parent_class)->constructor(type, n_props, props));
+	g_return_val_if_fail (self, NULL);
+
+	g_return_val_if_fail (self->pv->columns, NULL);
+
+	switch (self->pv->mode) {
+	case GCR_SELECTOR_MODE_SINGLE:
+		construct_single_selector (self);
+		break;
+	case GCR_SELECTOR_MODE_MULTIPLE:
+		construct_multiple_selector (self);
+		break;
+	default:
+		g_assert_not_reached ();
+		break;
+	}
+
+	return G_OBJECT (self);
+}
+
+static void
+gcr_selector_init (GcrSelector *self)
+{
+	self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_SELECTOR, GcrSelectorPrivate);
+}
+
+static void
+gcr_selector_dispose (GObject *obj)
+{
+	GcrSelector *self = GCR_SELECTOR (obj);
+
+	if (self->pv->model)
+		g_object_unref (self->pv->model);
+	self->pv->model = NULL;
+
+	if (self->pv->collection)
+		g_object_unref (self->pv->collection);
+	self->pv->collection = NULL;
+
+	G_OBJECT_CLASS (gcr_selector_parent_class)->dispose (obj);
+}
+
+static void
+gcr_selector_finalize (GObject *obj)
+{
+	GcrSelector *self = GCR_SELECTOR (obj);
+
+	g_assert (!self->pv->collection);
+	g_assert (!self->pv->model);
+	self->pv->combo = NULL;
+	self->pv->tree = NULL;
+
+	G_OBJECT_CLASS (gcr_selector_parent_class)->finalize (obj);
+}
+
+static void
+gcr_selector_set_property (GObject *obj, guint prop_id, const GValue *value,
+                           GParamSpec *pspec)
+{
+	GcrSelector *self = GCR_SELECTOR (obj);
+	switch (prop_id) {
+	case PROP_COLLECTION:
+		g_return_if_fail (!self->pv->collection);
+		self->pv->collection = g_value_dup_object (value);
+		g_return_if_fail (self->pv->collection);
+		break;
+	case PROP_COLUMNS:
+		g_return_if_fail (!self->pv->columns);
+		self->pv->columns = g_value_get_pointer (value);
+		g_return_if_fail (self->pv->columns);
+		break;
+	case PROP_MODE:
+		self->pv->mode = g_value_get_enum (value);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+gcr_selector_get_property (GObject *obj, guint prop_id, GValue *value,
+                         GParamSpec *pspec)
+{
+	GcrSelector *self = GCR_SELECTOR (obj);
+
+	switch (prop_id) {
+	case PROP_COLLECTION:
+		g_value_set_object (value, gcr_selector_get_collection (self));
+		break;
+	case PROP_COLUMNS:
+		g_value_set_pointer (value, (gpointer)gcr_selector_get_columns (self));
+		break;
+	case PROP_MODE:
+		g_value_set_enum (value, gcr_selector_get_mode (self));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+gcr_selector_class_init (GcrSelectorClass *klass)
+{
+	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+	gobject_class->constructor = gcr_selector_constructor;
+	gobject_class->dispose = gcr_selector_dispose;
+	gobject_class->finalize = gcr_selector_finalize;
+	gobject_class->set_property = gcr_selector_set_property;
+	gobject_class->get_property = gcr_selector_get_property;
+
+	g_type_class_add_private (gobject_class, sizeof (GcrSelectorPrivate));
+
+	g_object_class_install_property (gobject_class, PROP_COLLECTION,
+	           g_param_spec_object ("collection", "Collection", "Collection to select 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 to display in multiple selector",
+	                                 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+	g_object_class_install_property (gobject_class, PROP_MODE,
+	           g_param_spec_enum ("mode", "Mode", "The mode of the selector",
+	                              GCR_TYPE_SELECTOR_MODE, GCR_SELECTOR_MODE_SINGLE,
+	                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+	_gcr_initialize ();
+}
+
+/* -----------------------------------------------------------------------------
+ * PUBLIC
+ */
+
+GcrSelector*
+gcr_selector_new (GcrCollection *collection, const GcrColumn *columns, GcrSelectorMode mode)
+{
+	return g_object_new (GCR_TYPE_SELECTOR,
+	                     "collection", collection,
+	                     "columns", columns,
+	                     "mode", mode,
+	                     NULL);
+}
+
+GcrCollection*
+gcr_selector_get_collection (GcrSelector *self)
+{
+	g_return_val_if_fail (GCR_IS_SELECTOR (self), NULL);
+	return self->pv->collection;
+}
+
+const GcrColumn*
+gcr_selector_get_columns (GcrSelector *self)
+{
+	g_return_val_if_fail (GCR_IS_SELECTOR (self), NULL);
+	return self->pv->columns;
+}
+
+GcrSelectorMode
+gcr_selector_get_mode (GcrSelector *self)
+{
+	g_return_val_if_fail (GCR_IS_SELECTOR (self), 0);
+	return self->pv->mode;
+}
diff --git a/gcr/gcr-selector.h b/gcr/gcr-selector.h
new file mode 100644
index 0000000..88fba51
--- /dev/null
+++ b/gcr/gcr-selector.h
@@ -0,0 +1,82 @@
+/*
+ * 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 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.
+ */
+
+#ifndef __GCR_SELECTOR_H__
+#define __GCR_SELECTOR_H__
+
+#include "gcr-types.h"
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GCR_TYPE_SELECTOR               (gcr_selector_get_type ())
+#define GCR_TYPE_SELECTOR_MODE          (gcr_selector_mode_get_type ())
+#define GCR_SELECTOR(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_SELECTOR, GcrSelector))
+#define GCR_SELECTOR_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_SELECTOR, GcrSelectorClass))
+#define GCR_IS_SELECTOR(obj)            (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_SELECTOR))
+#define GCR_IS_SELECTOR_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_SELECTOR))
+#define GCR_SELECTOR_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_SELECTOR, GcrSelectorClass))
+
+typedef struct _GcrSelector GcrSelector;
+typedef struct _GcrSelectorClass GcrSelectorClass;
+typedef struct _GcrSelectorPrivate GcrSelectorPrivate;
+
+typedef enum _GcrSelectorMode {
+	GCR_SELECTOR_MODE_SINGLE = 1,
+	GCR_SELECTOR_MODE_MULTIPLE
+} GcrSelectorMode;
+
+struct _GcrSelector {
+	GtkAlignment parent;
+	GcrSelectorPrivate *pv;
+};
+
+struct _GcrSelectorClass {
+	GtkAlignmentClass parent_class;
+
+#if 0
+	/* signals --------------------------------------------------------- */
+
+	/* A callback for each password needed */
+	gboolean (*authenticate) (GcrSelector *self, gint count);
+
+	void     (*parsed) (GcrSelector *self);
+#endif
+};
+
+GType                    gcr_selector_get_type               (void);
+
+GType                    gcr_selector_mode_get_type          (void);
+
+GcrSelector*             gcr_selector_new                    (GcrCollection *collection,
+                                                              const GcrColumn *columns,
+                                                              GcrSelectorMode mode);
+
+GcrCollection*           gcr_selector_get_collection         (GcrSelector *self);
+
+const GcrColumn*         gcr_selector_get_columns            (GcrSelector *self);
+
+GcrSelectorMode          gcr_selector_get_mode               (GcrSelector *self);
+
+G_END_DECLS
+
+#endif /* __GCR_SELECTOR_H__ */
diff --git a/gcr/gcr-simple-certificate.c b/gcr/gcr-simple-certificate.c
index 5ec7ff2..a3174bc 100644
--- a/gcr/gcr-simple-certificate.c
+++ b/gcr/gcr-simple-certificate.c
@@ -22,6 +22,7 @@
 #include "config.h"
 
 #include "gcr-certificate.h"
+#include "gcr-comparable.h"
 #include "gcr-internal.h"
 #include "gcr-simple-certificate.h"
 
@@ -46,9 +47,13 @@ struct _GcrSimpleCertificatePrivate {
 	guchar *owned;
 };
 
-static void gcr_certificate_iface (GcrCertificateIface *iface); 
-G_DEFINE_TYPE_WITH_CODE (GcrSimpleCertificate, gcr_simple_certificate, G_TYPE_OBJECT, 
-                         G_IMPLEMENT_INTERFACE (GCR_TYPE_CERTIFICATE, gcr_certificate_iface));
+/* Forward declarations */
+static void gcr_simple_certificate_iface_init (GcrCertificateIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GcrSimpleCertificate, gcr_simple_certificate, G_TYPE_OBJECT,
+	GCR_CERTIFICATE_MIXIN_IMPLEMENT_COMPARABLE ();
+	G_IMPLEMENT_INTERFACE (GCR_TYPE_CERTIFICATE, gcr_simple_certificate_iface_init);
+);
 
 /* -----------------------------------------------------------------------------
  * OBJECT 
@@ -61,7 +66,7 @@ gcr_simple_certificate_init (GcrSimpleCertificate *self)
 }
 
 static void
-gcr_simple_certificate_finalize (GObject *obj)
+gcr_simple_certificate_real_finalize (GObject *obj)
 {
 	GcrSimpleCertificate *self = GCR_SIMPLE_CERTIFICATE (obj);
 
@@ -77,16 +82,21 @@ static void
 gcr_simple_certificate_class_init (GcrSimpleCertificateClass *klass)
 {
 	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
-	gobject_class->finalize = gcr_simple_certificate_finalize;
+
+	gobject_class->finalize = gcr_simple_certificate_real_finalize;
+	gobject_class->get_property = gcr_certificate_mixin_get_property;
+
 	g_type_class_add_private (gobject_class, sizeof (GcrSimpleCertificatePrivate));
+
+	gcr_certificate_mixin_class_init (gobject_class);
 	_gcr_initialize ();
 }
 
 static gconstpointer
-gcr_simple_certificate_real_get_der_data (GcrCertificate *base, gsize *n_data)
+gcr_simple_certificate_get_der_data (GcrCertificate *cert, gsize *n_data)
 {
-	GcrSimpleCertificate *self = GCR_SIMPLE_CERTIFICATE (base);
-	
+	GcrSimpleCertificate *self = GCR_SIMPLE_CERTIFICATE (cert);
+
 	g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL);
 	g_return_val_if_fail (n_data, NULL);
 	g_return_val_if_fail (self->pv->data, NULL);
@@ -96,10 +106,10 @@ gcr_simple_certificate_real_get_der_data (GcrCertificate *base, gsize *n_data)
 	return self->pv->data;
 }
 
-static void 
-gcr_certificate_iface (GcrCertificateIface *iface) 
+static void
+gcr_simple_certificate_iface_init (GcrCertificateIface *iface)
 {
-	iface->get_der_data = (gpointer)gcr_simple_certificate_real_get_der_data;
+	iface->get_der_data = gcr_simple_certificate_get_der_data;
 }
 
 /* -----------------------------------------------------------------------------
diff --git a/gcr/gcr.h b/gcr/gcr.h
index 8ac536b..9987dc7 100644
--- a/gcr/gcr.h
+++ b/gcr/gcr.h
@@ -46,6 +46,7 @@
 #include "gcr-parser.h"
 #include "gcr-renderer.h"
 #include "gcr-pkcs11-certificate.h"
+#include "gcr-selector.h"
 #include "gcr-simple-certificate.h"
 #include "gcr-simple-collection.h"
 #include "gcr-trust.h"
diff --git a/gcr/tests/test-ui-selector.c b/gcr/tests/test-ui-selector.c
index a9e717e..9aea8b9 100644
--- a/gcr/tests/test-ui-selector.c
+++ b/gcr/tests/test-ui-selector.c
@@ -61,77 +61,11 @@ add_to_selector (GcrParser *parser, const gchar *path)
 	g_free (data);
 }
 
-#if 1
-static void
-build_selector (GtkDialog *dialog, GcrCollection *collection)
-{
-	GcrCollectionModel *model;
-	GtkWidget *combo;
-	GtkCellRenderer *cell;
-
-	model = gcr_collection_model_new (collection,
-	                                  "icon", G_TYPE_ICON,
-	                                  "markup", G_TYPE_STRING,
-	                                  NULL);
-
-	combo = gtk_combo_box_new_with_model (GTK_TREE_MODEL (model));
-	cell = gtk_cell_renderer_pixbuf_new ();
-	g_object_set (cell, "stock-size", GTK_ICON_SIZE_DND, NULL);
-	gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), cell, FALSE);
-	gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combo), cell, "gicon", 0);
-
-	cell = gtk_cell_renderer_text_new ();
-	gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), cell, TRUE);
-	gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combo), cell, "markup", 1);
-
-	gtk_widget_show (GTK_WIDGET (combo));
-	gtk_container_add (GTK_CONTAINER (gtk_dialog_get_content_area (dialog)), combo);
-
-	gtk_window_set_default_size (GTK_WINDOW (dialog), 550, 400);
-	gtk_container_set_border_width (GTK_CONTAINER (dialog), 20);
-
-	g_object_unref (model);
-}
-#endif
-
-#if 0
-static void
-build_selector (GtkDialog *dialog, GcrCollection *collection)
-{
-	GcrCollectionModel *model;
-	const GcrModelColumn *columns;
-	GtkWidget *combo;
-	GtkCellRenderer *cell;
-
-	columns = gcr_renderer_columns (GCR_TYPE_CERTIFICATE_RENDERER);
-	model = gcr_collection_model_new_full (collection, columns);
-
-	gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
-
-	combo = gtk_combo_box_new_with_model (GTK_TREE_MODEL (model));
-	cell = gtk_cell_renderer_pixbuf_new ();
-	g_object_set (cell, "stock-size", GTK_ICON_SIZE_DND, NULL);
-	gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), cell, FALSE);
-	gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combo), cell, "gicon", 0);
-
-	cell = gtk_cell_renderer_text_new ();
-	gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), cell, TRUE);
-	gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combo), cell, "markup", 1);
-
-	gtk_widget_show (GTK_WIDGET (combo));
-	gtk_container_add (GTK_CONTAINER (gtk_dialog_get_content_area (dialog)), combo);
-
-	gtk_window_set_default_size (GTK_WINDOW (dialog), 550, 400);
-	gtk_container_set_border_width (GTK_CONTAINER (dialog), 20);
-
-	g_object_unref (model);
-}
-#endif
-
 int
 main (int argc, char *argv[])
 {
 	GcrCollection *collection;
+	GcrSelector *selector;
 	GtkDialog *dialog;
 	GcrParser *parser;
 	int i;
@@ -142,15 +76,13 @@ main (int argc, char *argv[])
 	g_object_ref_sink (dialog);
 
 	collection = gcr_simple_collection_new ();
-	build_selector (dialog, collection);
+	selector = gcr_selector_new (collection, GCR_CERTIFICATE_COLUMNS, GCR_SELECTOR_MODE_MULTIPLE);
 
-#if 0
-	{
-		GtkWidget *widget = gtk_file_chooser_button_new ("Tester", GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
-		gtk_widget_show (widget);
-		gtk_container_add (GTK_CONTAINER (gtk_dialog_get_content_area (dialog)), widget);
-	}
-#endif
+	gtk_widget_show (GTK_WIDGET (selector));
+	gtk_container_add (GTK_CONTAINER (gtk_dialog_get_content_area (dialog)), GTK_WIDGET (selector));
+
+	gtk_window_set_default_size (GTK_WINDOW (dialog), 550, 400);
+	gtk_container_set_border_width (GTK_CONTAINER (dialog), 20);
 
 	parser = gcr_parser_new ();
 	g_signal_connect (parser, "parsed", G_CALLBACK (on_parser_parsed), collection);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]