[gnome-keyring/ui-widgets: 2/7] [gcr] Rework how the certificate widget works.
- From: Stefan Walter <stefw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-keyring/ui-widgets: 2/7] [gcr] Rework how the certificate widget works.
- Date: Fri, 27 Aug 2010 03:24:40 +0000 (UTC)
commit 924f57edbf8f3c66935ef98df7368550aab1b945
Author: Stef Walter <stef memberwebs com>
Date: Sun Jun 20 16:53:21 2010 +0000
[gcr] Rework how the certificate widget works.
* Base class so we can use for other widgets.
* Details are part of an expander.
gcr/Makefile.am | 3 +
gcr/gcr-certificate-widget.c | 435 ++++++++++++++++++++++++++++++++++++++++
gcr/gcr-certificate-widget.h | 62 ++++++
gcr/gcr-display-view.c | 456 ++++++++++++++++++++++++++++++++++++++++++
gcr/gcr-display-view.h | 85 ++++++++
gcr/tests/ui-test-details.c | 6 +-
6 files changed, 1044 insertions(+), 3 deletions(-)
---
diff --git a/gcr/Makefile.am b/gcr/Makefile.am
index e0ae779..3f8842c 100644
--- a/gcr/Makefile.am
+++ b/gcr/Makefile.am
@@ -19,6 +19,7 @@ inc_HEADERS = \
gcr-certificate.h \
gcr-certificate-basics-widget.h \
gcr-certificate-details-widget.h \
+ gcr-certificate-widget.h \
gcr-importer.h \
gcr-parser.h \
gcr-types.h \
@@ -43,8 +44,10 @@ lib_LTLIBRARIES = libgcr.la
libgcr_la_SOURCES = \
gcr-certificate.c gcr-certificate.h \
+ gcr-certificate-widget.c gcr-certificate-widget.h \
gcr-certificate-basics-widget.c gcr-certificate-basics-widget.h \
gcr-certificate-details-widget.c gcr-certificate-details-widget.h \
+ gcr-display-view.c gcr-display-view.h \
gcr-import-dialog.c gcr-import-dialog.h \
gcr-importer.c gcr-importer.h \
gcr-internal.h \
diff --git a/gcr/gcr-certificate-widget.c b/gcr/gcr-certificate-widget.c
new file mode 100644
index 0000000..5d81b5b
--- /dev/null
+++ b/gcr/gcr-certificate-widget.c
@@ -0,0 +1,435 @@
+/*
+ * Copyright (C) 2008 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-certificate.h"
+#include "gcr-certificate-widget.h"
+#include "gcr-display-view.h"
+
+#include "egg/egg-asn1.h"
+#include "egg/egg-oid.h"
+#include "egg/egg-hex.h"
+
+#include <gdk/gdk.h>
+#include <glib/gi18n-lib.h>
+
+enum {
+ PROP_0,
+ PROP_CERTIFICATE
+};
+
+struct _GcrCertificateWidgetPrivate {
+ GcrCertificate *certificate;
+ GcrDisplayView *view;
+ guint key_size;
+};
+
+G_DEFINE_TYPE (GcrCertificateWidget, gcr_certificate_widget, GTK_TYPE_ALIGNMENT);
+
+/* -----------------------------------------------------------------------------
+ * INTERNAL
+ */
+
+static gboolean
+append_extension (GcrCertificateWidget *self, ASN1_TYPE asn,
+ const guchar *data, gsize n_data, gint index)
+{
+ GQuark oid;
+ gchar *name, *display;
+ gsize n_value;
+ const guchar *value;
+ const gchar *text;
+ gboolean critical;
+ int len, res;
+
+ /* Make sure it is present */
+ len = 0;
+ name = g_strdup_printf ("tbsCertificate.extensions.?%u", index);
+ res = asn1_read_value (asn, name, NULL, &len);
+ g_free (name);
+
+ if (res == ASN1_ELEMENT_NOT_FOUND)
+ return FALSE;
+
+ /* Dig out the OID */
+ name = g_strdup_printf ("tbsCertificate.extensions.?%u.extnID", index);
+ oid = egg_asn1_read_oid (asn, name);
+ g_free (name);
+ g_return_val_if_fail (oid, FALSE);
+
+
+ _gcr_display_view_append_heading (self->pv->view, _("Extension"));
+
+
+ /* Extension type */
+ text = egg_oid_get_description (oid);
+ _gcr_display_view_append_value (self->pv->view, _("Identifier"), text, FALSE);
+
+
+ /* Extension value */
+ name = g_strdup_printf ("tbsCertificate.extensions.?%u.extnValue", index);
+ value = egg_asn1_read_content (asn, data, n_data, name, &n_value);
+ g_free (name);
+
+ /* TODO: Parsing of extensions that we understand */
+ display = egg_hex_encode_full (value, n_value, TRUE, ' ', 1);
+ _gcr_display_view_append_value (self->pv->view, _("Value"), display, TRUE);
+ g_free (display);
+
+
+ /* Critical */
+ name = g_strdup_printf ("tbsCertificate.extensions.?%u.critical", index);
+ if (egg_asn1_read_boolean (asn, name, &critical))
+ _gcr_display_view_append_value (self->pv->view, _("Critical"), critical ? _("Yes") : _("No"), FALSE);
+ g_free (name);
+
+ return TRUE;
+}
+
+static void
+on_parsed_dn_part (guint index, GQuark oid, const guchar *value,
+ gsize n_value, gpointer user_data)
+{
+ GcrCertificateWidget *self = user_data;
+ const gchar *attr;
+ const gchar *desc;
+ gchar *field;
+ gchar *display;
+
+ g_return_if_fail (GCR_IS_CERTIFICATE_WIDGET (self));
+
+ attr = egg_oid_get_name (oid);
+ desc = egg_oid_get_description (oid);
+
+ /* Combine them into something sane */
+ if (attr && desc) {
+ if (strcmp (attr, desc) == 0)
+ field = g_strdup (attr);
+ else
+ field = g_strdup_printf ("%s (%s)", attr, desc);
+ } else if (!attr && !desc) {
+ field = g_strdup ("");
+ } else if (attr) {
+ field = g_strdup (attr);
+ } else if (desc) {
+ field = g_strdup (desc);
+ } else {
+ g_assert_not_reached ();
+ }
+
+ display = egg_asn1_dn_print_value (oid, value, n_value);
+ if (display == NULL)
+ display = g_strdup ("");
+
+ _gcr_display_view_append_value (self->pv->view, field, display, FALSE);
+ g_free (field);
+ g_free (display);
+}
+
+static void
+refresh_display (GcrCertificateWidget *self)
+{
+ const guchar *data, *value;
+ gsize n_data, n_value;
+ const gchar *text;
+ guint version, size;
+ guint index;
+ gchar *display;
+ ASN1_TYPE asn;
+ GQuark oid;
+ GDate date;
+
+ _gcr_display_view_clear (self->pv->view);
+
+ if (!self->pv->certificate)
+ return;
+
+ data = gcr_certificate_get_der_data (self->pv->certificate, &n_data);
+ g_return_if_fail (data);
+
+ asn = egg_asn1_decode ("PKIX1.Certificate", data, n_data);
+ g_return_if_fail (asn);
+
+ /* TODO: Calculate name properly */
+ _gcr_display_view_append_title (self->pv->view, "Certificate Name");
+
+#if 0
+ _gcr_display_view_append_table ()
+
+ Issued To:
+ Issued By:
+ Expires:
+#endif
+
+ display = egg_asn1_read_dn_part (asn, "tbsCertificate.subject.rdnSequence", "CN");
+ _gcr_display_view_append_content (self->pv->view, _("Identifies"), display);
+ g_free (display);
+
+ display = egg_asn1_read_dn_part (asn, "tbsCertificate.issuer.rdnSequence", "CN");
+ _gcr_display_view_append_content (self->pv->view, _("Verified by"), display);
+ g_free (display);
+
+ if (egg_asn1_read_date (asn, "tbsCertificate.validity.notAfter", &date)) {
+ display = g_malloc0 (128);
+ if (!g_date_strftime (display, 128, "%x", &date))
+ g_return_if_reached ();
+ _gcr_display_view_append_content (self->pv->view, _("Expires"), display);
+ g_free (display);
+ }
+
+ _gcr_display_view_start_details (self->pv->view);
+
+ /* The subject */
+ _gcr_display_view_append_heading (self->pv->view, _("Subject Name"));
+ egg_asn1_dn_parse (asn, "tbsCertificate.subject.rdnSequence", on_parsed_dn_part, self);
+
+ /* The Issuer */
+ _gcr_display_view_append_heading (self->pv->view, _("Issuer Name"));
+ egg_asn1_dn_parse (asn, "tbsCertificate.issuer.rdnSequence", on_parsed_dn_part, self);
+
+ /* The Issued Parameters */
+ _gcr_display_view_append_heading (self->pv->view, _("Issued Certificate"));
+
+ if (!egg_asn1_read_uint (asn, "tbsCertificate.version", &version))
+ g_return_if_reached ();
+ display = g_strdup_printf ("%u", version + 1);
+ _gcr_display_view_append_value (self->pv->view, _("Version"), display, FALSE);
+ g_free (display);
+
+ value = egg_asn1_read_content (asn, data, n_data, "tbsCertificate.serialNumber", &n_value);
+ g_return_if_fail (value);
+ display = egg_hex_encode_full (value, n_value, TRUE, ' ', 1);
+ _gcr_display_view_append_value (self->pv->view, _("Serial Number"), display, TRUE);
+ g_free (display);
+
+ display = g_malloc0 (128);
+ if (egg_asn1_read_date (asn, "tbsCertificate.validity.notBefore", &date)) {
+ if (!g_date_strftime (display, 128, "%Y-%m-%d", &date))
+ g_return_if_reached ();
+ _gcr_display_view_append_value (self->pv->view, _("Not Valid Before"), display, FALSE);
+ }
+ if (egg_asn1_read_date (asn, "tbsCertificate.validity.notAfter", &date)) {
+ if (!g_date_strftime (display, 128, "%Y-%m-%d", &date))
+ g_return_if_reached ();
+ _gcr_display_view_append_value (self->pv->view, _("Not Valid After"), display, FALSE);
+ }
+ g_free (display);
+
+ /* Signature */
+ _gcr_display_view_append_heading (self->pv->view, _("Signature"));
+
+ oid = egg_asn1_read_oid (asn, "signatureAlgorithm.algorithm");
+ text = egg_oid_get_description (oid);
+ _gcr_display_view_append_value (self->pv->view, _("Signature Algorithm"), text, FALSE);
+
+ value = egg_asn1_read_content (asn, data, n_data, "signatureAlgorithm.parameters", &n_value);
+ if (value && n_value) {
+ display = egg_hex_encode_full (value, n_value, TRUE, ' ', 1);
+ _gcr_display_view_append_value (self->pv->view, _("Signature Parameters"), display, TRUE);
+ g_free (display);
+ }
+
+ value = egg_asn1_read_content (asn, data, n_data, "signature", &n_value);
+ g_return_if_fail (value);
+ display = egg_hex_encode_full (value, n_value, TRUE, ' ', 1);
+ _gcr_display_view_append_value (self->pv->view, _("Signature"), display, TRUE);
+ g_free (display);
+
+ /* Public Key Info */
+ _gcr_display_view_append_heading (self->pv->view, _("Public Key Info"));
+
+ oid = egg_asn1_read_oid (asn, "tbsCertificate.subjectPublicKeyInfo.algorithm.algorithm");
+ text = egg_oid_get_description (oid);
+ _gcr_display_view_append_value (self->pv->view, _("Key Algorithm"), text, FALSE);
+
+ value = egg_asn1_read_content (asn, data, n_data, "tbsCertificate.subjectPublicKeyInfo.algorithm.parameters", &n_value);
+ if (value && n_value) {
+ display = egg_hex_encode_full (value, n_value, TRUE, ' ', 1);
+ _gcr_display_view_append_value (self->pv->view, _("Key Parameters"), display, TRUE);
+ g_free (display);
+ }
+
+ size = gcr_certificate_get_key_size (self->pv->certificate);
+ if (size > 0) {
+ display = g_strdup_printf ("%u", size);
+ _gcr_display_view_append_value (self->pv->view, _("Key Size"), display, FALSE);
+ g_free (display);
+ }
+
+ value = egg_asn1_read_content (asn, data, n_data, "tbsCertificate.subjectPublicKeyInfo.subjectPublicKey", &n_value);
+ g_return_if_fail (value);
+ display = egg_hex_encode_full (value, n_value, TRUE, ' ', 1);
+ _gcr_display_view_append_value (self->pv->view, _("Public Key"), display, TRUE);
+ g_free (display);
+
+ /* Fingerprints */
+ _gcr_display_view_append_heading (self->pv->view, _("Fingerprints"));
+
+ _gcr_display_view_append_fingerprint (self->pv->view, data, n_data, "SHA1", G_CHECKSUM_SHA1);
+ _gcr_display_view_append_fingerprint (self->pv->view, data, n_data, "MD5", G_CHECKSUM_MD5);
+
+ /* Extensions */
+ for (index = 1; TRUE; ++index) {
+ if (!append_extension (self, asn, data, n_data, index))
+ break;
+ }
+
+ asn1_delete_structure (&asn);
+}
+
+/* -----------------------------------------------------------------------------
+ * OBJECT
+ */
+
+static GObject*
+gcr_certificate_widget_constructor (GType type, guint n_props, GObjectConstructParam *props)
+{
+ GObject *obj = G_OBJECT_CLASS (gcr_certificate_widget_parent_class)->constructor (type, n_props, props);
+ GcrCertificateWidget *self = NULL;
+ GtkWidget *scroll;
+
+ g_return_val_if_fail (obj, NULL);
+
+ self = GCR_CERTIFICATE_WIDGET (obj);
+
+ self->pv->view = _gcr_display_view_new ();
+ _gcr_display_view_set_stock_image (self->pv->view, GTK_STOCK_DIALOG_AUTHENTICATION);
+
+ scroll = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
+ gtk_container_add (GTK_CONTAINER (scroll), GTK_WIDGET (self->pv->view));
+
+ gtk_container_add (GTK_CONTAINER (self), scroll);
+ gtk_widget_show_all (scroll);
+
+ return obj;
+}
+
+static void
+gcr_certificate_widget_init (GcrCertificateWidget *self)
+{
+ self->pv = (G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_CERTIFICATE_WIDGET, GcrCertificateWidgetPrivate));
+}
+
+static void
+gcr_certificate_widget_dispose (GObject *obj)
+{
+ GcrCertificateWidget *self = GCR_CERTIFICATE_WIDGET (obj);
+
+ if (self->pv->certificate)
+ g_object_unref (self->pv->certificate);
+ self->pv->certificate = NULL;
+
+ G_OBJECT_CLASS (gcr_certificate_widget_parent_class)->dispose (obj);
+}
+
+static void
+gcr_certificate_widget_finalize (GObject *obj)
+{
+ GcrCertificateWidget *self = GCR_CERTIFICATE_WIDGET (obj);
+
+ g_assert (!self->pv->certificate);
+
+ G_OBJECT_CLASS (gcr_certificate_widget_parent_class)->finalize (obj);
+}
+
+static void
+gcr_certificate_widget_set_property (GObject *obj, guint prop_id, const GValue *value,
+ GParamSpec *pspec)
+{
+ GcrCertificateWidget *self = GCR_CERTIFICATE_WIDGET (obj);
+
+ switch (prop_id) {
+ case PROP_CERTIFICATE:
+ gcr_certificate_widget_set_certificate (self, g_value_get_object (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gcr_certificate_widget_get_property (GObject *obj, guint prop_id, GValue *value,
+ GParamSpec *pspec)
+{
+ GcrCertificateWidget *self = GCR_CERTIFICATE_WIDGET (obj);
+
+ switch (prop_id) {
+ case PROP_CERTIFICATE:
+ g_value_set_object (value, self->pv->certificate);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gcr_certificate_widget_class_init (GcrCertificateWidgetClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gcr_certificate_widget_parent_class = g_type_class_peek_parent (klass);
+ g_type_class_add_private (klass, sizeof (GcrCertificateWidgetPrivate));
+
+ gobject_class->constructor = gcr_certificate_widget_constructor;
+ gobject_class->dispose = gcr_certificate_widget_dispose;
+ gobject_class->finalize = gcr_certificate_widget_finalize;
+ gobject_class->set_property = gcr_certificate_widget_set_property;
+ gobject_class->get_property = gcr_certificate_widget_get_property;
+
+ g_object_class_install_property (gobject_class, PROP_CERTIFICATE,
+ g_param_spec_object("certificate", "Certificate", "Certificate to display.",
+ GCR_TYPE_CERTIFICATE, G_PARAM_READWRITE));
+}
+
+/* -----------------------------------------------------------------------------
+ * PUBLIC
+ */
+
+GcrCertificateWidget*
+gcr_certificate_widget_new (GcrCertificate *certificate)
+{
+ return g_object_new (GCR_TYPE_CERTIFICATE_WIDGET, "certificate", certificate, NULL);
+}
+
+GcrCertificate*
+gcr_certificate_widget_get_certificate (GcrCertificateWidget *self)
+{
+ g_return_val_if_fail (GCR_IS_CERTIFICATE_WIDGET (self), NULL);
+ return self->pv->certificate;
+}
+
+void
+gcr_certificate_widget_set_certificate (GcrCertificateWidget *self, GcrCertificate *cert)
+{
+ g_return_if_fail (GCR_IS_CERTIFICATE_WIDGET (self));
+
+ if (self->pv->certificate)
+ g_object_unref (self->pv->certificate);
+ self->pv->certificate = cert;
+ if (self->pv->certificate)
+ g_object_ref (self->pv->certificate);
+
+ refresh_display (self);
+ refresh_display (self);
+ g_object_notify (G_OBJECT (self), "certificate");
+}
diff --git a/gcr/gcr-certificate-widget.h b/gcr/gcr-certificate-widget.h
new file mode 100644
index 0000000..e363e59
--- /dev/null
+++ b/gcr/gcr-certificate-widget.h
@@ -0,0 +1,62 @@
+/*
+ * 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_CERTIFICATE_WIDGET_H__
+#define __GCR_CERTIFICATE_WIDGET_H__
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+#include "gcr-certificate.h"
+#include "gcr-types.h"
+
+G_BEGIN_DECLS
+
+#define GCR_TYPE_CERTIFICATE_WIDGET (gcr_certificate_widget_get_type ())
+#define GCR_CERTIFICATE_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_CERTIFICATE_WIDGET, GcrCertificateWidget))
+#define GCR_CERTIFICATE_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_CERTIFICATE_WIDGET, GcrCertificateWidgetClass))
+#define GCR_IS_CERTIFICATE_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_CERTIFICATE_WIDGET))
+#define GCR_IS_CERTIFICATE_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_CERTIFICATE_WIDGET))
+#define GCR_CERTIFICATE_WIDGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_CERTIFICATE_WIDGET, GcrCertificateWidgetClass))
+
+typedef struct _GcrCertificateWidget GcrCertificateWidget;
+typedef struct _GcrCertificateWidgetClass GcrCertificateWidgetClass;
+typedef struct _GcrCertificateWidgetPrivate GcrCertificateWidgetPrivate;
+
+struct _GcrCertificateWidget {
+ GtkAlignment parent;
+ GcrCertificateWidgetPrivate *pv;
+};
+
+struct _GcrCertificateWidgetClass {
+ GtkAlignmentClass parent_class;
+};
+
+GType gcr_certificate_widget_get_type (void);
+
+GcrCertificateWidget* gcr_certificate_widget_new (GcrCertificate *cert);
+
+GcrCertificate* gcr_certificate_widget_get_certificate (GcrCertificateWidget *details);
+
+void gcr_certificate_widget_set_certificate (GcrCertificateWidget *details,
+ GcrCertificate *cert);
+
+G_END_DECLS
+
+#endif /* __GCR_CERTIFICATE_WIDGET_H__ */
diff --git a/gcr/gcr-display-view.c b/gcr/gcr-display-view.c
new file mode 100644
index 0000000..86b3f4d
--- /dev/null
+++ b/gcr/gcr-display-view.c
@@ -0,0 +1,456 @@
+/*
+ * 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-display-view.h"
+
+#include "egg/egg-oid.h"
+#include "egg/egg-hex.h"
+
+#include <gdk/gdk.h>
+#if 0
+#include <glib/gi18n-lib.h>
+#endif
+
+G_DEFINE_TYPE (GcrDisplayView, _gcr_display_view, GTK_TYPE_TEXT_VIEW);
+
+#define NORMAL_MARGIN 5
+#define FIELD_MARGIN 17
+#define COLUMN_MARGIN 6
+#define ICON_MARGIN 8
+
+struct _GcrDisplayViewPrivate {
+ GtkTextBuffer *buffer;
+ GtkTextTag *field_tag;
+ GtkTextTag *details_tag;
+ GtkWidget *details_widget;
+ GtkTextChildAnchor *details_anchor;
+ const gchar *extra_tag;
+ gint field_width;
+ GdkPixbuf *pixbuf;
+};
+
+/* -----------------------------------------------------------------------------
+ * INTERNAL
+ */
+
+static GtkTextTagTable*
+create_tag_table (GcrDisplayView *self)
+{
+ GtkTextTagTable *tags;
+ GtkTextTag *tag;
+ gint width, height;
+
+ g_assert (GCR_IS_DISPLAY_VIEW (self));
+
+ tags = gtk_text_tag_table_new ();
+
+ if (!gtk_icon_size_lookup (GTK_ICON_SIZE_DIALOG, &width, &height))
+ width = 48;
+
+ tag = g_object_new (GTK_TYPE_TEXT_TAG,
+ "name", "title",
+ "scale", PANGO_SCALE_LARGE,
+ "right-margin", (ICON_MARGIN * 2) + width,
+ "pixels-above-lines", 9,
+ "pixels-below-lines", 6,
+ "weight", PANGO_WEIGHT_BOLD,
+ NULL);
+ gtk_text_tag_table_add (tags, tag);
+ g_object_unref (tag);
+
+ tag = g_object_new (GTK_TYPE_TEXT_TAG,
+ "name", "content",
+ "right-margin", (ICON_MARGIN * 2) + width,
+ "left-margin", FIELD_MARGIN,
+ "pixels-below-lines", 3,
+ NULL);
+ gtk_text_tag_table_add (tags, tag);
+ g_object_unref (tag);
+
+ tag = g_object_new (GTK_TYPE_TEXT_TAG,
+ "name", "heading",
+ "pixels-above-lines", 9,
+ "pixels-below-lines", 3,
+ "weight", PANGO_WEIGHT_BOLD,
+ NULL);
+ gtk_text_tag_table_add (tags, tag);
+ g_object_unref (tag);
+
+ tag = g_object_new (GTK_TYPE_TEXT_TAG,
+ "name", "monospace",
+ "family", "monospace",
+ NULL);
+ gtk_text_tag_table_add (tags, tag);
+ g_object_unref (tag);
+
+ g_assert (!self->pv->field_tag);
+ self->pv->field_width = 0;
+ self->pv->field_tag = g_object_new (GTK_TYPE_TEXT_TAG,
+ "name", "field",
+ "left-margin", self->pv->field_width + FIELD_MARGIN,
+ "indent", self->pv->field_width,
+ "pixels-below-lines", 3,
+ "wrap-mode", GTK_WRAP_WORD_CHAR,
+ NULL);
+ gtk_text_tag_table_add (tags, self->pv->field_tag);
+
+ g_assert (!self->pv->details_tag);
+ self->pv->details_tag = g_object_new (GTK_TYPE_TEXT_TAG,
+ "name", "details",
+ "foreground", "red",
+ NULL);
+ gtk_text_tag_table_add (tags, self->pv->details_tag);
+
+ return tags;
+}
+
+
+static void
+on_expander_realize (GtkWidget *widget, gpointer user_data)
+{
+ GdkCursor *cursor = gdk_cursor_new (GDK_ARROW);
+ g_printerr ("realize cursor\n");
+ gdk_window_set_cursor (gtk_widget_get_window (widget), cursor);
+ gdk_cursor_unref (cursor);
+}
+
+static void
+on_expander_expanded (GObject *object, GParamSpec *param_spec, gpointer user_data)
+{
+ GtkExpander *expander = GTK_EXPANDER (object);
+ GcrDisplayView *self = GCR_DISPLAY_VIEW (user_data);
+ g_object_set (self->pv->details_tag,
+ "invisible", gtk_expander_get_expanded (expander) ? FALSE : TRUE,
+ NULL);
+}
+
+/* -----------------------------------------------------------------------------
+ * OBJECT
+ */
+
+static GObject*
+_gcr_display_view_constructor (GType type, guint n_props, GObjectConstructParam *props)
+{
+ GObject *obj = G_OBJECT_CLASS (_gcr_display_view_parent_class)->constructor (type, n_props, props);
+ GcrDisplayView *self = NULL;
+ GtkTextView *view = NULL;
+ GtkTextTagTable *tags;
+ GdkColor color;
+ GtkWidget *widget;
+
+ g_return_val_if_fail (obj, NULL);
+
+ self = GCR_DISPLAY_VIEW (obj);
+ view = GTK_TEXT_VIEW (obj);
+
+ tags = create_tag_table (self);
+ self->pv->buffer = gtk_text_buffer_new (tags);
+ g_object_unref (tags);
+
+ gtk_text_view_set_buffer (view, self->pv->buffer);
+ gtk_text_view_set_editable (view, FALSE);
+ gtk_text_view_set_left_margin (view, NORMAL_MARGIN);
+ gtk_text_view_set_right_margin (view, NORMAL_MARGIN);
+ gtk_text_view_set_cursor_visible (view, FALSE);
+
+ widget = gtk_expander_new_with_mnemonic ("_Details");
+ g_signal_connect_object (widget, "notify::expanded",
+ G_CALLBACK (on_expander_expanded), self, 0);
+ g_signal_connect_object (widget, "realize",
+ G_CALLBACK (on_expander_realize), self, 0);
+ on_expander_expanded (G_OBJECT (widget), NULL, self);
+ /* TODO: We need to retrieve the background color of the text view */
+ gdk_color_parse ("white", &color);
+ gtk_widget_modify_bg (widget, GTK_STATE_NORMAL, &color);
+
+ self->pv->details_widget = gtk_event_box_new ();
+ gtk_container_add (GTK_CONTAINER (self->pv->details_widget), widget);
+ g_signal_connect_object (self->pv->details_widget, "realize",
+ G_CALLBACK (on_expander_realize), self, 0);
+ g_object_ref (self->pv->details_widget);
+ gtk_widget_show (widget);
+
+ return obj;
+}
+
+static void
+_gcr_display_view_init (GcrDisplayView *self)
+{
+ self->pv = (G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_DISPLAY_VIEW, GcrDisplayViewPrivate));
+}
+
+static void
+_gcr_display_view_finalize (GObject *obj)
+{
+ GcrDisplayView *self = GCR_DISPLAY_VIEW (obj);
+
+ if (self->pv->buffer)
+ g_object_unref (self->pv->buffer);
+ self->pv->buffer = NULL;
+
+ if (self->pv->field_tag)
+ g_object_unref (self->pv->field_tag);
+ self->pv->field_tag = NULL;
+
+ if (self->pv->pixbuf)
+ g_object_unref (self->pv->pixbuf);
+ self->pv->pixbuf = NULL;
+
+ if (self->pv->details_widget)
+ g_object_unref (self->pv->details_widget);
+ self->pv->details_widget = NULL;
+
+ G_OBJECT_CLASS (_gcr_display_view_parent_class)->finalize (obj);
+}
+
+static void
+_gcr_display_view_realize (GtkWidget *widget)
+{
+ GcrDisplayView *self = GCR_DISPLAY_VIEW (widget);
+ GtkStyle *style;
+
+ if (GTK_WIDGET_CLASS (_gcr_display_view_parent_class)->realize)
+ GTK_WIDGET_CLASS (_gcr_display_view_parent_class)->realize (widget);
+
+ g_printerr ("setting color\n");
+ style = gtk_widget_get_style (widget);
+ gtk_widget_modify_bg (self->pv->details_widget, GTK_STATE_NORMAL, &style->base[GTK_STATE_NORMAL]);
+}
+
+static gboolean
+_gcr_display_view_expose_event (GtkWidget *widget, GdkEventExpose *event)
+{
+ GcrDisplayView *self = GCR_DISPLAY_VIEW (widget);
+ GtkTextView *view = GTK_TEXT_VIEW (widget);
+ gboolean handled = FALSE;
+ GdkRectangle visible;
+ GdkRectangle position;
+ GdkGC *gc;
+
+ /* Have GtkTextView draw the text first. */
+ if (GTK_WIDGET_CLASS (_gcr_display_view_parent_class)->expose_event)
+ handled = GTK_WIDGET_CLASS (_gcr_display_view_parent_class)->expose_event (widget, event);
+
+ if (self->pv->pixbuf == NULL)
+ return handled;
+
+ /* Render the pixbuf if it's available */
+ if (event->window == gtk_text_view_get_window (view, GTK_TEXT_WINDOW_TEXT)) {
+
+ position.height = gdk_pixbuf_get_height (self->pv->pixbuf);
+ position.width = gdk_pixbuf_get_width (self->pv->pixbuf);
+
+ gtk_text_view_get_visible_rect (view, &visible);
+
+ gtk_text_view_buffer_to_window_coords (view, GTK_TEXT_WINDOW_TEXT,
+ visible.width - position.width - ICON_MARGIN, ICON_MARGIN,
+ &position.x, &position.y);
+
+ gc = gdk_gc_new (event->window);
+ gdk_draw_pixbuf (event->window, gc, self->pv->pixbuf,
+ 0, 0, position.x, position.y, position.width, position.height,
+ GDK_RGB_DITHER_NORMAL, 0, 0);
+ g_object_unref (gc);
+ }
+
+ return handled;
+}
+
+static void
+_gcr_display_view_class_init (GcrDisplayViewClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+ _gcr_display_view_parent_class = g_type_class_peek_parent (klass);
+ g_type_class_add_private (klass, sizeof (GcrDisplayViewPrivate));
+
+ gobject_class->constructor = _gcr_display_view_constructor;
+ gobject_class->finalize = _gcr_display_view_finalize;
+
+ widget_class->realize = _gcr_display_view_realize;
+ widget_class->expose_event = _gcr_display_view_expose_event;
+}
+
+/* -----------------------------------------------------------------------------
+ * PUBLIC
+ */
+
+GcrDisplayView*
+_gcr_display_view_new (void)
+{
+ return g_object_new (GCR_TYPE_DISPLAY_VIEW, NULL);
+}
+
+void
+_gcr_display_view_clear (GcrDisplayView *self)
+{
+ GtkTextIter start, iter;
+ if (gtk_widget_get_parent (self->pv->details_widget))
+ gtk_container_remove (GTK_CONTAINER (self), self->pv->details_widget);
+ gtk_text_buffer_get_start_iter (self->pv->buffer, &start);
+ gtk_text_buffer_get_end_iter (self->pv->buffer, &iter);
+ gtk_text_buffer_delete (self->pv->buffer, &start, &iter);
+ self->pv->extra_tag = NULL;
+ self->pv->field_width = 0;
+}
+
+void
+_gcr_display_view_start_details (GcrDisplayView *self)
+{
+ GtkTextChildAnchor *anchor;
+ GtkTextIter iter;
+
+ self->pv->extra_tag = "details";
+
+ gtk_text_buffer_get_end_iter (self->pv->buffer, &iter);
+ anchor = gtk_text_buffer_create_child_anchor (self->pv->buffer, &iter);
+ gtk_text_view_add_child_at_anchor (GTK_TEXT_VIEW (self), self->pv->details_widget, anchor);
+ gtk_widget_show_all (self->pv->details_widget);
+ gtk_text_buffer_insert (self->pv->buffer, &iter, "\n", 1);
+}
+
+void
+_gcr_display_view_append_content (GcrDisplayView *self, const gchar *content, const gchar *details)
+{
+ GtkTextIter iter;
+ gchar *memory = NULL;
+
+ g_return_if_fail (GCR_IS_DISPLAY_VIEW (self));
+ g_return_if_fail (content);
+
+ if (details)
+ content = memory = g_strdup_printf ("%s: %s", content, details);
+
+ gtk_text_buffer_get_end_iter (self->pv->buffer, &iter);
+ gtk_text_buffer_insert_with_tags_by_name (self->pv->buffer, &iter, content, -1,
+ "content", self->pv->extra_tag, NULL);
+ gtk_text_buffer_insert_with_tags_by_name (self->pv->buffer, &iter, "\n", 1,
+ self->pv->extra_tag, NULL);
+
+ g_free (memory);
+}
+
+void
+_gcr_display_view_append_value (GcrDisplayView *self, const gchar *field,
+ const gchar *value, gboolean monospace)
+{
+ PangoRectangle extents;
+ PangoTabArray *tabs;
+ PangoLayout *layout;
+ GtkTextIter iter;
+ gchar *text;
+
+ text = g_strdup_printf ("%s:", field);
+ if (value == NULL)
+ value = "";
+
+ /* Measure the width of the field */
+ layout = gtk_widget_create_pango_layout (GTK_WIDGET (self), text);
+ pango_layout_get_extents (layout, NULL, &extents);
+ pango_extents_to_pixels (&extents, NULL);
+ g_object_unref (layout);
+
+ /* Make the tab wide enough to accomodate */
+ if (extents.width > self->pv->field_width) {
+ self->pv->field_width = extents.width + COLUMN_MARGIN;
+ tabs = pango_tab_array_new (1, TRUE);
+ pango_tab_array_set_tab (tabs, 0, PANGO_TAB_LEFT, self->pv->field_width);
+ g_object_set (self->pv->field_tag,
+ "left-margin", FIELD_MARGIN,
+ "indent", 0 - self->pv->field_width,
+ "tabs", tabs,
+ NULL);
+ pango_tab_array_free (tabs);
+ }
+
+ gtk_text_buffer_get_end_iter (self->pv->buffer, &iter);
+ gtk_text_buffer_insert_with_tags_by_name (self->pv->buffer, &iter, text, -1,
+ "field", self->pv->extra_tag, NULL);
+ gtk_text_buffer_insert_with_tags_by_name (self->pv->buffer, &iter, "\t", 1,
+ self->pv->extra_tag, NULL);
+ gtk_text_buffer_insert_with_tags_by_name (self->pv->buffer, &iter, value, -1, "field",
+ monospace ? "monospace" : self->pv->extra_tag,
+ monospace ? self->pv->extra_tag : NULL, NULL);
+ gtk_text_buffer_insert_with_tags_by_name (self->pv->buffer, &iter, "\n", 1,
+ self->pv->extra_tag, NULL);
+
+ g_free (text);
+}
+
+void
+_gcr_display_view_append_title (GcrDisplayView *self, const gchar *title)
+{
+ GtkTextIter iter;
+
+ gtk_text_buffer_get_end_iter (self->pv->buffer, &iter);
+ gtk_text_buffer_insert_with_tags_by_name (self->pv->buffer, &iter, title, -1,
+ "title", self->pv->extra_tag, NULL);
+ gtk_text_buffer_insert_with_tags_by_name (self->pv->buffer, &iter, "\n", 1,
+ self->pv->extra_tag, NULL);
+}
+
+void
+_gcr_display_view_append_heading (GcrDisplayView *self, const gchar *heading)
+{
+ GtkTextIter iter;
+
+ gtk_text_buffer_get_end_iter (self->pv->buffer, &iter);
+ gtk_text_buffer_insert_with_tags_by_name (self->pv->buffer, &iter, heading, -1,
+ "heading", self->pv->extra_tag, NULL);
+ gtk_text_buffer_insert_with_tags_by_name (self->pv->buffer, &iter, "\n", 1,
+ self->pv->extra_tag, NULL);
+}
+
+void
+_gcr_display_view_append_fingerprint (GcrDisplayView *self, const guchar *data,
+ gsize n_data, const gchar *name, GChecksumType type)
+{
+ GChecksum *checksum;
+ guint8 *buffer;
+ gsize n_buffer;
+ gchar *display;
+
+ checksum = g_checksum_new (type);
+ g_return_if_fail (checksum);
+ g_checksum_update (checksum, data, n_data);
+
+ n_buffer = g_checksum_type_get_length (type);
+ g_return_if_fail (n_buffer);
+ buffer = g_malloc0 (n_buffer);
+
+ g_checksum_get_digest (checksum, buffer, &n_buffer);
+ g_checksum_free (checksum);
+
+ display = egg_hex_encode_full (buffer, n_buffer, TRUE, ' ', 1);
+ _gcr_display_view_append_value (self, name, display, TRUE);
+ g_free (display);
+
+ g_free (buffer);
+}
+
+void
+_gcr_display_view_set_stock_image (GcrDisplayView *self, const gchar *stock_id)
+{
+ if (self->pv->pixbuf)
+ g_object_unref (self->pv->pixbuf);
+ self->pv->pixbuf = gtk_widget_render_icon (GTK_WIDGET (self), stock_id, GTK_ICON_SIZE_DIALOG, NULL);
+}
diff --git a/gcr/gcr-display-view.h b/gcr/gcr-display-view.h
new file mode 100644
index 0000000..f47aecf
--- /dev/null
+++ b/gcr/gcr-display-view.h
@@ -0,0 +1,85 @@
+/*
+ * 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_DISPLAY_VIEW_H__
+#define __GCR_DISPLAY_VIEW_H__
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+#include "gcr-certificate.h"
+#include "gcr-types.h"
+
+G_BEGIN_DECLS
+
+#define GCR_TYPE_DISPLAY_VIEW (_gcr_display_view_get_type ())
+#define GCR_DISPLAY_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_DISPLAY_VIEW, GcrDisplayView))
+#define GCR_DISPLAY_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_DISPLAY_VIEW, GcrDisplayViewClass))
+#define GCR_IS_DISPLAY_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_DISPLAY_VIEW))
+#define GCR_IS_DISPLAY_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_DISPLAY_VIEW))
+#define GCR_DISPLAY_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_DISPLAY_VIEW, GcrDisplayViewClass))
+
+typedef struct _GcrDisplayView GcrDisplayView;
+typedef struct _GcrDisplayViewClass GcrDisplayViewClass;
+typedef struct _GcrDisplayViewPrivate GcrDisplayViewPrivate;
+
+struct _GcrDisplayView {
+ GtkTextView parent;
+ GcrDisplayViewPrivate *pv;
+};
+
+struct _GcrDisplayViewClass {
+ GtkTextViewClass parent_class;
+};
+
+GType _gcr_display_view_get_type (void);
+
+GcrDisplayView* _gcr_display_view_new (void);
+
+void _gcr_display_view_clear (GcrDisplayView *self);
+
+void _gcr_display_view_append_value (GcrDisplayView *self,
+ const gchar *field,
+ const gchar *value,
+ gboolean monospace);
+
+void _gcr_display_view_append_title (GcrDisplayView *self,
+ const gchar *title);
+
+void _gcr_display_view_append_content (GcrDisplayView *self,
+ const gchar *content,
+ const gchar *details);
+
+void _gcr_display_view_start_details (GcrDisplayView *self);
+
+void _gcr_display_view_append_heading (GcrDisplayView *self,
+ const gchar *heading);
+
+void _gcr_display_view_append_fingerprint (GcrDisplayView *self,
+ const guchar *data,
+ gsize n_data,
+ const gchar *name,
+ GChecksumType type);
+
+void _gcr_display_view_set_stock_image (GcrDisplayView *self,
+ const gchar *stock_id);
+
+G_END_DECLS
+
+#endif /* __GCR_DISPLAY_VIEW_H__ */
diff --git a/gcr/tests/ui-test-details.c b/gcr/tests/ui-test-details.c
index f369209..c8bb49c 100644
--- a/gcr/tests/ui-test-details.c
+++ b/gcr/tests/ui-test-details.c
@@ -1,7 +1,7 @@
#include "config.h"
-#include "gcr-certificate-details-widget.h"
+#include "gcr-certificate-widget.h"
#include "gcr-simple-certificate.h"
#include <gtk/gtk.h>
@@ -34,7 +34,7 @@ chdir_base_dir (char* argv0)
static void
test_details (const gchar *path)
{
- GcrCertificateDetailsWidget *details;
+ GcrCertificateWidget *details;
GcrCertificate *certificate;
GtkDialog *dialog;
guchar *data;
@@ -50,7 +50,7 @@ test_details (const gchar *path)
dialog = GTK_DIALOG (gtk_dialog_new ());
g_object_ref_sink (dialog);
- details = gcr_certificate_details_widget_new (certificate);
+ details = gcr_certificate_widget_new (certificate);
gtk_widget_show (GTK_WIDGET (details));
gtk_container_add (GTK_CONTAINER (gtk_dialog_get_content_area (dialog)), GTK_WIDGET (details));
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]