[gnome-keyring/ui-widgets: 2/7] [gcr] Rework how the certificate widget works.



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]