From 1fc52f98cfd8e568f5b986d0b3aeca77bed7e712 Mon Sep 17 00:00:00 2001 From: Stef Walter Date: Wed, 20 Oct 2010 20:47:39 +0000 Subject: [PATCH] [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. --- 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 | 26 ++- gcr/gcr.h | 1 + gcr/tests/test-ui-selector.c | 82 +------- 20 files changed, 1091 insertions(+), 247 deletions(-) create mode 100644 gcr/gcr-comparable.c create mode 100644 gcr/gcr-comparable.h create mode 100644 gcr/gcr-selector.c create mode 100644 gcr/gcr-selector.h 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 GCR_CERTIFICATE GCR_IS_CERTIFICATE diff --git a/gcr/Makefile.am b/gcr/Makefile.am index e50931b..f3b3949 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\nIssued by: %s", label, issuer); - else - markup = g_markup_printf_escaped ("%s\nIssued by: No name", 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 e412991..f877738 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 +#include /** * 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\nIssued by: %s", label, issuer); + else + markup = g_markup_printf_escaped ("%s\nIssued by: No name", 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: + * + * + * 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); + * ); + * + */ + +/** + * 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: + * + * + * 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; + * } + *} + * + * + * Example of use as get_property function: + * + * + * static void + * my_class_init (MyClass *klass) + * { + * GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + * gobject_class->get_property = gcr_certificate_mixin_get_property; + * + * ... + * } + * + + */ +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 056171e..09c74b1 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 +#include 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 + +/* --------------------------------------------------------------------------------- + * 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 + +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 cfc4d1c..cd95be7 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 + +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 dfa6023..217e341 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); +/* Forward declarations */ +static void gcr_simple_certificate_iface_init (GcrCertificateIface *iface); + G_DEFINE_TYPE_WITH_CODE (GcrSimpleCertificate, gcr_simple_certificate, G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (GCR_TYPE_CERTIFICATE, gcr_certificate_iface)); + 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,15 +82,20 @@ 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); @@ -97,9 +107,9 @@ gcr_simple_certificate_real_get_der_data (GcrCertificate *base, gsize *n_data) } static void -gcr_certificate_iface (GcrCertificateIface *iface) +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); -- 2.7.4