[seahorse/pgp/subkey-list-box: 2/2] pgp: Create specific widget for subkey lists
- From: Niels De Graef <nielsdg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [seahorse/pgp/subkey-list-box: 2/2] pgp: Create specific widget for subkey lists
- Date: Tue, 27 Jul 2021 22:13:39 +0000 (UTC)
commit 46f55e6cef8200821441fa673157ddd92957b089
Author: Niels De Graef <nielsdegraef gmail com>
Date: Tue Jul 27 23:16:20 2021 +0200
pgp: Create specific widget for subkey lists
Try to show a cleaner UI by getting rid of the `GtkTreeView`. This also
allows us to do things like showing tooltips on the specific
capabilities of each subkey (for example "Sign").
data/seahorse.gresource.xml | 1 +
libseahorse/seahorse.css | 12 +
pgp/meson.build | 1 +
pgp/seahorse-gpgme-key-op.c | 14 +-
pgp/seahorse-gpgme-key.c | 2 +-
pgp/seahorse-gpgme-subkey.c | 91 ++----
pgp/seahorse-gpgme-subkey.h | 8 +-
pgp/seahorse-pgp-key-properties.c | 197 +-----------
pgp/seahorse-pgp-key.c | 1 +
pgp/seahorse-pgp-private-key-properties.ui | 148 +--------
pgp/seahorse-pgp-public-key-properties.ui | 37 +--
pgp/seahorse-pgp-subkey-list-box-row.ui | 233 +++++++++++++++
pgp/seahorse-pgp-subkey-list-box.c | 464 +++++++++++++++++++++++++++++
pgp/seahorse-pgp-subkey-list-box.h | 42 +++
pgp/seahorse-pgp-subkey.c | 89 +++++-
pgp/seahorse-pgp-subkey.h | 9 +
po/POTFILES.in | 2 +
17 files changed, 918 insertions(+), 433 deletions(-)
---
diff --git a/data/seahorse.gresource.xml b/data/seahorse.gresource.xml
index da8c3f67..32aa3b2d 100644
--- a/data/seahorse.gresource.xml
+++ b/data/seahorse.gresource.xml
@@ -38,6 +38,7 @@
<file alias="seahorse-keyserver-sync.ui"
preprocess="xml-stripblanks">../pgp/seahorse-keyserver-sync.ui</file>
<file alias="seahorse-pgp-private-key-properties.ui"
preprocess="xml-stripblanks">../pgp/seahorse-pgp-private-key-properties.ui</file>
<file alias="seahorse-pgp-public-key-properties.ui"
preprocess="xml-stripblanks">../pgp/seahorse-pgp-public-key-properties.ui</file>
+ <file alias="seahorse-pgp-subkey-list-box-row.ui"
preprocess="xml-stripblanks">../pgp/seahorse-pgp-subkey-list-box-row.ui</file>
<!-- PKCS#11 -->
<file alias="seahorse-pkcs11-generate.ui"
preprocess="xml-stripblanks">../pkcs11/seahorse-pkcs11-generate.ui</file>
diff --git a/libseahorse/seahorse.css b/libseahorse/seahorse.css
index e80e048c..0cc49df0 100644
--- a/libseahorse/seahorse.css
+++ b/libseahorse/seahorse.css
@@ -38,6 +38,18 @@
border-color: shade (@theme_bg_color, 0.66);
}
+.pgp-subkey-usage-label {
+ border: 1px solid shade(@theme_bg_color, 0.9);
+ background-color: shade(@theme_bg_color, .95);
+ padding-left: 3px;
+ padding-right: 3px;
+ border-radius: 4px;
+}
+
+:selected .pgp-subkey-usage-label {
+ background-color: shade(@theme_selected_bg_color, .95);
+}
+
levelbar .strength-weak {
background-color: #cc0000;
border-color: #cc0000;
diff --git a/pgp/meson.build b/pgp/meson.build
index 3576596d..3346c5d6 100644
--- a/pgp/meson.build
+++ b/pgp/meson.build
@@ -29,6 +29,7 @@ pgp_sources = files(
'seahorse-pgp-photo.c',
'seahorse-pgp-signature.c',
'seahorse-pgp-subkey.c',
+ 'seahorse-pgp-subkey-list-box.c',
'seahorse-pgp-uid.c',
'seahorse-transfer.c',
'seahorse-unknown.c',
diff --git a/pgp/seahorse-gpgme-key-op.c b/pgp/seahorse-gpgme-key-op.c
index 84f7e036..52aaac1a 100644
--- a/pgp/seahorse-gpgme-key-op.c
+++ b/pgp/seahorse-gpgme-key-op.c
@@ -1138,6 +1138,7 @@ seahorse_gpgme_key_op_set_expires (SeahorseGpgmeSubkey *subkey,
GDateTime *old_expires;
ExpireParm exp_parm;
SeahorseEditParm *parms;
+ SeahorsePgpKey *parent_key;
gpgme_key_t key;
g_return_val_if_fail (SEAHORSE_GPGME_IS_SUBKEY (subkey), GPG_E (GPG_ERR_WRONG_KEY_USAGE));
@@ -1149,7 +1150,8 @@ seahorse_gpgme_key_op_set_expires (SeahorseGpgmeSubkey *subkey,
g_return_val_if_fail (!g_date_time_equal (old_expires, expires),
GPG_E (GPG_ERR_INV_VALUE));
- key = seahorse_gpgme_subkey_get_pubkey (subkey);
+ parent_key = seahorse_pgp_subkey_get_parent_key (SEAHORSE_PGP_SUBKEY (subkey));
+ key = seahorse_gpgme_key_get_public (SEAHORSE_GPGME_KEY (parent_key));
g_return_val_if_fail (key, GPG_E (GPG_ERR_INV_VALUE));
exp_parm.index = seahorse_pgp_subkey_get_index (SEAHORSE_PGP_SUBKEY (subkey));
@@ -1560,13 +1562,15 @@ del_key_transit (unsigned int current_state,
gpgme_error_t
seahorse_gpgme_key_op_del_subkey (SeahorseGpgmeSubkey *subkey)
{
- SeahorseEditParm *parms;
+ SeahorsePgpKey *parent_key;
gpgme_key_t key;
+ SeahorseEditParm *parms;
int index;
g_return_val_if_fail (SEAHORSE_GPGME_IS_SUBKEY (subkey), GPG_E (GPG_ERR_WRONG_KEY_USAGE));
- key = seahorse_gpgme_subkey_get_pubkey (subkey);
+ parent_key = seahorse_pgp_subkey_get_parent_key (SEAHORSE_PGP_SUBKEY (subkey));
+ key = seahorse_gpgme_key_get_public (SEAHORSE_GPGME_KEY (parent_key));
g_return_val_if_fail (key, GPG_E (GPG_ERR_INV_VALUE));
index = seahorse_pgp_subkey_get_index (SEAHORSE_PGP_SUBKEY (subkey));
@@ -1743,6 +1747,7 @@ seahorse_gpgme_key_op_revoke_subkey (SeahorseGpgmeSubkey *subkey, SeahorseRevoke
RevSubkeyParm rev_parm;
SeahorseEditParm *parms;
gpgme_subkey_t gsubkey;
+ SeahorsePgpKey *parent_key;
gpgme_key_t key;
g_return_val_if_fail (SEAHORSE_GPGME_IS_SUBKEY (subkey), GPG_E (GPG_ERR_WRONG_KEY_USAGE));
@@ -1750,7 +1755,8 @@ seahorse_gpgme_key_op_revoke_subkey (SeahorseGpgmeSubkey *subkey, SeahorseRevoke
gsubkey = seahorse_gpgme_subkey_get_subkey (subkey);
g_return_val_if_fail (!gsubkey->revoked, GPG_E (GPG_ERR_INV_VALUE));
- key = seahorse_gpgme_subkey_get_pubkey (subkey);
+ parent_key = seahorse_pgp_subkey_get_parent_key (SEAHORSE_PGP_SUBKEY (subkey));
+ key = seahorse_gpgme_key_get_public (SEAHORSE_GPGME_KEY (parent_key));
g_return_val_if_fail (key, GPG_E (GPG_ERR_INV_VALUE));
rev_parm.index = seahorse_pgp_subkey_get_index (SEAHORSE_PGP_SUBKEY (subkey));
diff --git a/pgp/seahorse-gpgme-key.c b/pgp/seahorse-gpgme-key.c
index 712d3196..b4cc07f5 100644
--- a/pgp/seahorse-gpgme-key.c
+++ b/pgp/seahorse-gpgme-key.c
@@ -280,7 +280,7 @@ realize_subkeys (SeahorseGpgmeKey *self)
for (gsubkey = self->pubkey->subkeys; gsubkey; gsubkey = gsubkey->next) {
g_autoptr(SeahorseGpgmeSubkey) subkey = NULL;
- subkey = seahorse_gpgme_subkey_new (self->pubkey, gsubkey);
+ subkey = seahorse_gpgme_subkey_new (self, gsubkey);
g_ptr_array_add (results, g_steal_pointer (&subkey));
}
}
diff --git a/pgp/seahorse-gpgme-subkey.c b/pgp/seahorse-gpgme-subkey.c
index a03d3d6a..e215131f 100644
--- a/pgp/seahorse-gpgme-subkey.c
+++ b/pgp/seahorse-gpgme-subkey.c
@@ -29,28 +29,18 @@
enum {
PROP_0,
- PROP_PUBKEY,
- PROP_SUBKEY
+ PROP_SUBKEY,
+ N_PROPS
};
struct _SeahorseGpgmeSubkey {
SeahorsePgpSubkey parent_instance;
- gpgme_key_t pubkey; /* The public key that this subkey is part of */
- gpgme_subkey_t subkey; /* The subkey referred to */
+ gpgme_subkey_t subkey;
};
G_DEFINE_TYPE (SeahorseGpgmeSubkey, seahorse_gpgme_subkey, SEAHORSE_PGP_TYPE_SUBKEY);
-
-gpgme_key_t
-seahorse_gpgme_subkey_get_pubkey (SeahorseGpgmeSubkey *self)
-{
- g_return_val_if_fail (SEAHORSE_GPGME_IS_SUBKEY (self), NULL);
- g_return_val_if_fail (self->pubkey, NULL);
- return self->pubkey;
-}
-
gpgme_subkey_t
seahorse_gpgme_subkey_get_subkey (SeahorseGpgmeSubkey *self)
{
@@ -62,22 +52,25 @@ seahorse_gpgme_subkey_get_subkey (SeahorseGpgmeSubkey *self)
void
seahorse_gpgme_subkey_set_subkey (SeahorseGpgmeSubkey *self, gpgme_subkey_t subkey)
{
+ SeahorsePgpSubkey *base = SEAHORSE_PGP_SUBKEY (self);
+ SeahorseGpgmeKey *parent;
+ gpgme_key_t pubkey;
g_autofree char *description = NULL, *fingerprint = NULL, *name = NULL;
- SeahorsePgpSubkey *base;
const char *algo_type;
- GObject *obj;
gpgme_subkey_t sub;
int i, index;
g_autoptr(GDateTime) created = NULL;
g_autoptr(GDateTime) expires = NULL;
- guint flags;
+ unsigned int flags;
g_return_if_fail (SEAHORSE_GPGME_IS_SUBKEY (self));
g_return_if_fail (subkey);
/* Make sure that this subkey is in the pubkey */
+ parent = SEAHORSE_GPGME_KEY (seahorse_pgp_subkey_get_parent_key (base));
+ pubkey = seahorse_gpgme_key_get_public (parent);
index = -1;
- for (i = 0, sub = self->pubkey->subkeys; sub; ++i, sub = sub->next) {
+ for (i = 0, sub = pubkey->subkeys; sub; ++i, sub = sub->next) {
if (sub == subkey) {
index = i;
break;
@@ -94,15 +87,13 @@ seahorse_gpgme_subkey_set_subkey (SeahorseGpgmeSubkey *self, gpgme_subkey_t subk
/* Additional properties */
fingerprint = seahorse_pgp_subkey_calc_fingerprint (subkey->fpr);
- name = seahorse_gpgme_uid_calc_name (self->pubkey->uids);
+ name = seahorse_gpgme_uid_calc_name (pubkey->uids);
description = seahorse_pgp_subkey_calc_description (name, index);
self->subkey = subkey;
- obj = G_OBJECT (self);
- g_object_freeze_notify (obj);
+ g_object_freeze_notify (G_OBJECT (self));
- base = SEAHORSE_PGP_SUBKEY (self);
seahorse_pgp_subkey_set_index (base, index);
seahorse_pgp_subkey_set_keyid (base, subkey->keyid);
seahorse_pgp_subkey_set_algorithm (base, algo_type);
@@ -138,8 +129,8 @@ seahorse_gpgme_subkey_set_subkey (SeahorseGpgmeSubkey *self, gpgme_subkey_t subk
seahorse_pgp_subkey_set_flags (base, flags);
- g_object_notify (obj, "subkey");
- g_object_thaw_notify (obj);
+ g_object_notify (G_OBJECT (self), "subkey");
+ g_object_thaw_notify (G_OBJECT (self));
}
static void
@@ -147,31 +138,15 @@ seahorse_gpgme_subkey_init (SeahorseGpgmeSubkey *self)
{
}
-static GObject*
-seahorse_gpgme_subkey_constructor (GType type, guint n_props, GObjectConstructParam *props)
-{
- GObject *obj;
- SeahorseGpgmeSubkey *self = NULL;
-
- obj = G_OBJECT_CLASS (seahorse_gpgme_subkey_parent_class)->constructor (type, n_props, props);
- if (obj) {
- self = SEAHORSE_GPGME_SUBKEY (obj);
- g_return_val_if_fail (self->pubkey, NULL);
- }
-
- return obj;
-}
-
static void
-seahorse_gpgme_subkey_get_property (GObject *object, guint prop_id,
- GValue *value, GParamSpec *pspec)
+seahorse_gpgme_subkey_get_property (GObject *object,
+ unsigned int prop_id,
+ GValue *value,
+ GParamSpec *pspec)
{
SeahorseGpgmeSubkey *self = SEAHORSE_GPGME_SUBKEY (object);
switch (prop_id) {
- case PROP_PUBKEY:
- g_value_set_boxed (value, seahorse_gpgme_subkey_get_pubkey (self));
- break;
case PROP_SUBKEY:
g_value_set_pointer (value, seahorse_gpgme_subkey_get_subkey (self));
break;
@@ -179,18 +154,14 @@ seahorse_gpgme_subkey_get_property (GObject *object, guint prop_id,
}
static void
-seahorse_gpgme_subkey_set_property (GObject *object, guint prop_id, const GValue *value,
- GParamSpec *pspec)
+seahorse_gpgme_subkey_set_property (GObject *object,
+ unsigned int prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
{
SeahorseGpgmeSubkey *self = SEAHORSE_GPGME_SUBKEY (object);
switch (prop_id) {
- case PROP_PUBKEY:
- g_return_if_fail (!self->pubkey);
- self->pubkey = g_value_get_boxed (value);
- if (self->pubkey)
- gpgme_key_ref (self->pubkey);
- break;
case PROP_SUBKEY:
seahorse_gpgme_subkey_set_subkey (self, g_value_get_pointer (value));
break;
@@ -202,10 +173,6 @@ seahorse_gpgme_subkey_finalize (GObject *gobject)
{
SeahorseGpgmeSubkey *self = SEAHORSE_GPGME_SUBKEY (gobject);
- /* Unref the key */
- if (self->pubkey)
- gpgme_key_unref (self->pubkey);
- self->pubkey = NULL;
self->subkey = NULL;
G_OBJECT_CLASS (seahorse_gpgme_subkey_parent_class)->finalize (gobject);
@@ -216,25 +183,23 @@ seahorse_gpgme_subkey_class_init (SeahorseGpgmeSubkeyClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
- gobject_class->constructor = seahorse_gpgme_subkey_constructor;
gobject_class->finalize = seahorse_gpgme_subkey_finalize;
gobject_class->set_property = seahorse_gpgme_subkey_set_property;
gobject_class->get_property = seahorse_gpgme_subkey_get_property;
- g_object_class_install_property (gobject_class, PROP_PUBKEY,
- g_param_spec_boxed ("pubkey", "Public Key", "GPGME Public Key that this subkey is on",
- SEAHORSE_GPGME_BOXED_KEY,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY));
-
g_object_class_install_property (gobject_class, PROP_SUBKEY,
g_param_spec_pointer ("subkey", "Subkey", "GPGME Subkey",
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
}
SeahorseGpgmeSubkey*
-seahorse_gpgme_subkey_new (gpgme_key_t pubkey, gpgme_subkey_t subkey)
+seahorse_gpgme_subkey_new (SeahorseGpgmeKey *parent_key,
+ gpgme_subkey_t subkey)
{
+ g_return_val_if_fail (SEAHORSE_GPGME_IS_KEY (parent_key), NULL);
+ g_return_val_if_fail (subkey, NULL);
+
return g_object_new (SEAHORSE_GPGME_TYPE_SUBKEY,
- "pubkey", pubkey,
+ "parent-key", parent_key,
"subkey", subkey, NULL);
}
diff --git a/pgp/seahorse-gpgme-subkey.h b/pgp/seahorse-gpgme-subkey.h
index 248a269d..670fc670 100644
--- a/pgp/seahorse-gpgme-subkey.h
+++ b/pgp/seahorse-gpgme-subkey.h
@@ -2,6 +2,7 @@
* Seahorse
*
* Copyright (C) 2008 Stefan Walter
+ * Copyright (C) 2021 Niels De Graef
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -24,16 +25,15 @@
#include <gpgme.h>
#include "pgp/seahorse-pgp-subkey.h"
+#include "pgp/seahorse-gpgme-key.h"
#define SEAHORSE_GPGME_TYPE_SUBKEY (seahorse_gpgme_subkey_get_type ())
G_DECLARE_FINAL_TYPE (SeahorseGpgmeSubkey, seahorse_gpgme_subkey,
SEAHORSE_GPGME, SUBKEY,
SeahorsePgpSubkey)
-SeahorseGpgmeSubkey* seahorse_gpgme_subkey_new (gpgme_key_t pubkey,
- gpgme_subkey_t subkey);
-
-gpgme_key_t seahorse_gpgme_subkey_get_pubkey (SeahorseGpgmeSubkey *self);
+SeahorseGpgmeSubkey* seahorse_gpgme_subkey_new (SeahorseGpgmeKey *parent_key,
+ gpgme_subkey_t subkey);
gpgme_subkey_t seahorse_gpgme_subkey_get_subkey (SeahorseGpgmeSubkey *self);
diff --git a/pgp/seahorse-pgp-key-properties.c b/pgp/seahorse-pgp-key-properties.c
index 5c4451f8..42b770e7 100644
--- a/pgp/seahorse-pgp-key-properties.c
+++ b/pgp/seahorse-pgp-key-properties.c
@@ -40,6 +40,7 @@
#include "seahorse-pgp-uid.h"
#include "seahorse-pgp-signature.h"
#include "seahorse-pgp-subkey.h"
+#include "seahorse-pgp-subkey-list-box.h"
#include "seahorse-common.h"
@@ -88,7 +89,7 @@ struct _SeahorsePgpKeyProperties {
GtkLabel *details_strength_label;
GtkLabel *details_expires_label;
GtkComboBox *details_trust_combobox;
- GtkTreeView *details_subkey_tree;
+ GtkWidget *subkeys_container;
/* Private key widgets */
GtkTreeView *names_tree;
@@ -949,28 +950,6 @@ const GType trust_columns[] = {
G_TYPE_INT /* validity */
};
-static SeahorsePgpSubkey*
-get_selected_subkey (SeahorsePgpKeyProperties *self)
-{
- return get_selected_object (self->details_subkey_tree, SUBKEY_OBJECT);
-}
-
-static void
-details_subkey_selected (GtkTreeSelection *selection, SeahorsePgpKeyProperties *self)
-{
- SeahorsePgpSubkey* subkey;
- guint flags = 0;
-
- subkey = get_selected_object (self->details_subkey_tree, SUBKEY_OBJECT);
- if (subkey)
- flags = seahorse_pgp_subkey_get_flags (subkey);
-
- set_action_enabled (self, "subkeys.change-expires", subkey != NULL);
- set_action_enabled (self, "subkeys.revoke",
- subkey != NULL && !(flags & SEAHORSE_FLAG_REVOKED));
- set_action_enabled (self, "subkeys.delete", subkey != NULL);
-}
-
static void
on_add_subkey_completed (GObject *object, GAsyncResult *res, gpointer user_data)
{
@@ -1014,81 +993,6 @@ on_subkeys_add (GSimpleAction *action, GVariant *param, gpointer user_data)
gtk_widget_destroy (GTK_WIDGET (dialog));
}
-static void
-on_subkeys_delete (GSimpleAction *action, GVariant *param, gpointer user_data)
-{
- SeahorsePgpKeyProperties *self = SEAHORSE_PGP_KEY_PROPERTIES (user_data);
- SeahorsePgpSubkey *subkey;
- guint index;
- gboolean ret;
- const gchar *label;
- g_autofree gchar *message = NULL;
- gpgme_error_t err;
-
- subkey = get_selected_subkey (self);
- if (!subkey)
- return;
-
- g_return_if_fail (SEAHORSE_GPGME_IS_SUBKEY (subkey));
-
- index = seahorse_pgp_subkey_get_index (subkey);
- label = seahorse_object_get_label (SEAHORSE_OBJECT (self->key));
- message = g_strdup_printf (_("Are you sure you want to permanently delete subkey %d of %s?"), index,
label);
- ret = seahorse_delete_dialog_prompt (GTK_WINDOW (self), message);
-
- if (ret == FALSE)
- return;
-
- err = seahorse_gpgme_key_op_del_subkey (SEAHORSE_GPGME_SUBKEY (subkey));
- if (!GPG_IS_OK (err))
- seahorse_gpgme_handle_error (err, _("Couldn’t delete subkey"));
-}
-
-static void
-on_subkeys_revoke (GSimpleAction *action, GVariant *param, gpointer user_data)
-{
- SeahorsePgpKeyProperties *self = SEAHORSE_PGP_KEY_PROPERTIES (user_data);
- SeahorsePgpSubkey *subkey = get_selected_subkey (self);
- GtkWidget *dialog;
-
- if (!subkey)
- return;
-
- g_return_if_fail (SEAHORSE_GPGME_IS_SUBKEY (subkey));
- dialog = seahorse_gpgme_revoke_dialog_new (SEAHORSE_GPGME_SUBKEY (subkey),
- GTK_WINDOW (self));
- gtk_dialog_run (GTK_DIALOG (dialog));
- gtk_widget_destroy (dialog);
-}
-
-static void
-on_subkeys_change_expires (GSimpleAction *action, GVariant *param, gpointer user_data)
-{
- SeahorsePgpKeyProperties *self = SEAHORSE_PGP_KEY_PROPERTIES (user_data);
- g_autoptr(SeahorsePgpSubkey) subkey = NULL;
- GtkDialog *dialog;
-
- subkey = get_selected_subkey (self);
- if (subkey == NULL) {
- GListModel *subkeys;
-
- subkeys = seahorse_pgp_key_get_subkeys (self->key);
- subkey = g_list_model_get_item (subkeys, 0);
- } else {
- g_object_ref (subkey);
- }
-
- g_return_if_fail (SEAHORSE_GPGME_IS_SUBKEY (subkey));
-
- if (subkey == NULL)
- return;
-
- dialog = seahorse_gpgme_expires_dialog_new (SEAHORSE_GPGME_SUBKEY (subkey),
- GTK_WINDOW (self));
- gtk_dialog_run (dialog);
- gtk_widget_destroy (GTK_WIDGET (dialog));
-}
-
static void
on_pgp_details_trust_changed (GtkComboBox *selection, gpointer user_data)
{
@@ -1237,7 +1141,6 @@ setup_trust_combobox (SeahorsePgpKeyProperties *self)
static void
do_details (SeahorsePgpKeyProperties *self)
{
- GtkListStore *store;
GtkTreeModel *model;
GtkTreeIter iter;
char dbuffer[G_ASCII_DTOSTR_BUF_SIZE];
@@ -1310,85 +1213,6 @@ do_details (SeahorsePgpKeyProperties *self)
valid = gtk_tree_model_iter_next (model, &iter);
}
-
- /* Clear/create table store */
- store = GTK_LIST_STORE (gtk_tree_view_get_model (self->details_subkey_tree));
- if (store) {
- gtk_list_store_clear (store);
- } else {
-
- /* This is our first time so create a store */
- store = gtk_list_store_newv (SUBKEY_N_COLUMNS, (GType*)subkey_columns);
- gtk_tree_view_set_model (self->details_subkey_tree, GTK_TREE_MODEL (store));
-
- /* Make the columns for the view */
- gtk_tree_view_insert_column_with_attributes (self->details_subkey_tree,
- -1, _("ID"), gtk_cell_renderer_text_new (),
- "text", SUBKEY_ID, NULL);
- gtk_tree_view_insert_column_with_attributes (self->details_subkey_tree,
- -1, _("Type"), gtk_cell_renderer_text_new (),
- "text", SUBKEY_TYPE, NULL);
- gtk_tree_view_insert_column_with_attributes (self->details_subkey_tree,
- -1, _("Usage"), gtk_cell_renderer_text_new (),
- "text", SUBKEY_USAGE, NULL);
- gtk_tree_view_insert_column_with_attributes (self->details_subkey_tree,
- -1, _("Created"), gtk_cell_renderer_text_new (),
- "text", SUBKEY_CREATED, NULL);
- gtk_tree_view_insert_column_with_attributes (self->details_subkey_tree,
- -1, _("Expires"), gtk_cell_renderer_text_new (),
- "text", SUBKEY_EXPIRES, NULL);
- gtk_tree_view_insert_column_with_attributes (self->details_subkey_tree,
- -1, _("Status"), gtk_cell_renderer_text_new (),
- "text", SUBKEY_STATUS, NULL);
- gtk_tree_view_insert_column_with_attributes (self->details_subkey_tree,
- -1, _("Strength"), gtk_cell_renderer_text_new (),
- "text", SUBKEY_LENGTH, NULL);
- }
-
- for (guint i = 0; i < g_list_model_get_n_items (subkeys); i++) {
- g_autoptr(SeahorsePgpSubkey) subkey = NULL;
- const char *status = NULL;
- g_autofree char *expiration_date = NULL;
- g_autofree char *created_date = NULL;
- g_autofree char *usage = NULL;
- GDateTime *expires;
- guint flags;
-
- subkey = g_list_model_get_item (subkeys, i);
- expires = seahorse_pgp_subkey_get_expires (subkey);
- flags = seahorse_pgp_subkey_get_flags (subkey);
- status = "";
-
- if (flags & SEAHORSE_FLAG_REVOKED)
- status = _("Revoked");
- else if (flags & SEAHORSE_FLAG_EXPIRED)
- status = _("Expired");
- else if (flags & SEAHORSE_FLAG_DISABLED)
- status = _("Disabled");
- else if (flags & SEAHORSE_FLAG_IS_VALID)
- status = _("Good");
-
- if (!expires)
- expiration_date = g_strdup (C_("Expires", "Never"));
- else
- expiration_date = g_date_time_format (expires, "%x");
-
- created_date = g_date_time_format (seahorse_pgp_subkey_get_created (subkey), "%x");
-
- usage = seahorse_pgp_subkey_get_usage (subkey);
-
- gtk_list_store_append (store, &iter);
- gtk_list_store_set (store, &iter,
- SUBKEY_OBJECT, subkey,
- SUBKEY_ID, seahorse_pgp_subkey_get_keyid (subkey),
- SUBKEY_TYPE, seahorse_pgp_subkey_get_algorithm (subkey),
- SUBKEY_USAGE, usage,
- SUBKEY_CREATED, created_date,
- SUBKEY_EXPIRES, expiration_date,
- SUBKEY_STATUS, status,
- SUBKEY_LENGTH, seahorse_pgp_subkey_get_length (subkey),
- -1);
- }
}
/* -----------------------------------------------------------------------------
@@ -1716,9 +1540,6 @@ static const GActionEntry PRIVATE_KEY_ACTIONS[] = {
{ "photos.next", on_photos_next },
{ "photos.make-primary", on_photos_make_primary },
{ "subkeys.add", on_subkeys_add },
- { "subkeys.delete", on_subkeys_delete },
- { "subkeys.revoke", on_subkeys_revoke },
- { "subkeys.change-expires", on_subkeys_change_expires },
};
static const GActionEntry PUBLIC_KEY_ACTIONS[] = {
@@ -1742,6 +1563,8 @@ key_notify (GObject *object, GParamSpec *pspec, gpointer user_data)
static void
get_common_widgets (SeahorsePgpKeyProperties *self, GtkBuilder *builder)
{
+ GtkWidget *subkeys_listbox;
+
self->owner_name_label = GTK_LABEL (gtk_builder_get_object (builder, "owner-name-label"));
self->owner_email_label = GTK_LABEL (gtk_builder_get_object (builder, "owner-email-label"));
self->owner_comment_label = GTK_LABEL (gtk_builder_get_object (builder, "owner-comment-label"));
@@ -1760,7 +1583,7 @@ get_common_widgets (SeahorsePgpKeyProperties *self, GtkBuilder *builder)
self->details_strength_label = GTK_LABEL (gtk_builder_get_object (builder, "details-strength-label"));
self->details_expires_label = GTK_LABEL (gtk_builder_get_object (builder, "details-expires-label"));
self->details_trust_combobox = GTK_COMBO_BOX (gtk_builder_get_object (builder,
"details-trust-combobox"));
- self->details_subkey_tree = GTK_TREE_VIEW (gtk_builder_get_object (builder, "details-subkey-tree"));
+ self->subkeys_container = GTK_WIDGET (gtk_builder_get_object (builder, "subkeys_container"));
g_signal_connect_object (self->photo_event_box, "scroll-event",
G_CALLBACK (on_pgp_owner_photoid_button),
@@ -1768,6 +1591,11 @@ get_common_widgets (SeahorsePgpKeyProperties *self, GtkBuilder *builder)
g_signal_connect_object (self->details_trust_combobox, "changed",
G_CALLBACK (on_pgp_details_trust_changed),
self, 0);
+
+ subkeys_listbox = seahorse_pgp_subkey_list_box_new (self->key);
+ gtk_widget_show (subkeys_listbox);
+ gtk_container_add (GTK_CONTAINER (self->subkeys_container),
+ subkeys_listbox);
}
static void
@@ -1888,11 +1716,6 @@ create_private_key_dialog (SeahorsePgpKeyProperties *self)
target_list, G_N_ELEMENTS (target_list),
GDK_ACTION_COPY);
- /* Enable and disable buttons as subkeys are selected */
- g_signal_connect (gtk_tree_view_get_selection (self->details_subkey_tree),
- "changed", G_CALLBACK (details_subkey_selected), self);
- details_subkey_selected (NULL, self);
-
/* Enable and disable buttons as UIDs are selected */
selection = gtk_tree_view_get_selection (self->names_tree);
g_signal_connect (selection, "changed", G_CALLBACK (update_names), self);
diff --git a/pgp/seahorse-pgp-key.c b/pgp/seahorse-pgp-key.c
index 48768f11..df7920ff 100644
--- a/pgp/seahorse-pgp-key.c
+++ b/pgp/seahorse-pgp-key.c
@@ -380,6 +380,7 @@ seahorse_pgp_key_add_subkey (SeahorsePgpKey *self,
return;
}
+ seahorse_pgp_subkey_set_parent_key (subkey, self);
g_list_store_append (G_LIST_STORE (priv->subkeys), subkey);
}
diff --git a/pgp/seahorse-pgp-private-key-properties.ui b/pgp/seahorse-pgp-private-key-properties.ui
index 071a1e95..f65e83f7 100644
--- a/pgp/seahorse-pgp-private-key-properties.ui
+++ b/pgp/seahorse-pgp-private-key-properties.ui
@@ -922,156 +922,38 @@
</object>
</child>
<child>
- <object class="GtkExpander" id="subkey-expander">
+ <object class="GtkBox" id="subkeys_container">
<property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="expanded">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="orientation">horizontal</property>
<child>
- <object class="GtkBox">
+ <object class="GtkLabel">
<property name="visible">True</property>
- <property name="orientation">vertical</property>
- <property name="margin">12</property>
- <child>
- <object class="GtkButton" id="details-add-button">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">False</property>
- <property name="border_width">6</property>
- <property name="action-name">props.subkeys.add</property>
- <child>
- <object class="GtkBox">
- <property name="visible">True</property>
- <property name="orientation">horizontal</property>
- <property name="halign">center</property>
- <property name="spacing">2</property>
- <child>
- <object class="GtkImage">
- <property name="visible">True</property>
- <property name="stock">gtk-add</property>
- </object>
- </child>
- <child>
- <object class="GtkLabel">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Add</property>
- <property name="use_underline">True</property>
- </object>
- </child>
- </object>
- </child>
- </object>
- </child>
- <child>
- <object class="GtkButton" id="details-date-button">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">False</property>
- <property name="border_width">6</property>
- <property name="action-name">props.subkeys.change-expires</property>
- <child>
- <object class="GtkBox">
- <property name="visible">True</property>
- <property name="orientation">horizontal</property>
- <property name="halign">center</property>
- <property name="spacing">2</property>
- <child>
- <object class="GtkImage">
- <property name="visible">True</property>
- <property name="icon_name">x-office-calendar</property>
- </object>
- </child>
- <child>
- <object class="GtkLabel">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Expire</property>
- <property name="use_underline">True</property>
- </object>
- </child>
- </object>
- </child>
- </object>
- </child>
- <child>
- <object class="GtkButton" id="details-revoke-button">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">False</property>
- <property name="border_width">6</property>
- <property name="action-name">props.subkeys.revoke</property>
- <child>
- <object class="GtkBox">
- <property name="visible">True</property>
- <property name="orientation">horizontal</property>
- <property name="halign">center</property>
- <property name="spacing">2</property>
- <child>
- <object class="GtkImage">
- <property name="visible">True</property>
- <property name="stock">gtk-close</property>
- </object>
- </child>
- <child>
- <object class="GtkLabel">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Revoke</property>
- <property name="use_underline">True</property>
- </object>
- </child>
- </object>
- </child>
- </object>
- </child>
- <child>
- <object class="GtkButton" id="details-delete-button">
- <property name="label">gtk-delete</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">False</property>
- <property name="border_width">6</property>
- <property name="use_stock">True</property>
- <property name="action-name">props.subkeys.delete</property>
- </object>
- </child>
+ <property name="hexpand">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Subkeys</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
</object>
</child>
<child>
- <object class="GtkScrolledWindow">
+ <object class="GtkButton">
<property name="visible">True</property>
<property name="can_focus">True</property>
- <property name="hscrollbar_policy">automatic</property>
- <property name="vscrollbar_policy">automatic</property>
- <property name="shadow_type">in</property>
- <child>
- <object class="GtkTreeView" id="details-subkey-tree">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- </object>
- </child>
+ <property name="receives_default">False</property>
+ <property name="action-name">props.subkeys.add</property>
+ <property name="use-underline">True</property>
+ <property name="label" translatable="yes">_Add subkey</property>
</object>
- <packing>
- <property name="expand">True</property>
- </packing>
</child>
</object>
</child>
- <child type="label">
- <object class="GtkLabel">
- <property name="visible">True</property>
- <property name="label" translatable="yes">_Subkeys</property>
- <property name="use_underline">True</property>
- <attributes>
- <attribute name="weight" value="bold"/>
- </attributes>
- </object>
- </child>
</object>
- <packing>
- <property name="position">2</property>
- </packing>
</child>
</object>
</child>
diff --git a/pgp/seahorse-pgp-public-key-properties.ui b/pgp/seahorse-pgp-public-key-properties.ui
index 7b21ef48..9b861ad9 100644
--- a/pgp/seahorse-pgp-public-key-properties.ui
+++ b/pgp/seahorse-pgp-public-key-properties.ui
@@ -869,40 +869,27 @@ B4C3 4349 0932 7854 3452</property>
</object>
</child>
<child>
- <object class="GtkExpander" id="subkey-expander">
+ <object class="GtkBox" id="subkeys_container">
<property name="visible">True</property>
- <property name="can_focus">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
<child>
- <object class="GtkScrolledWindow">
+ <object class="GtkBox">
<property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="shadow_type">in</property>
- <property name="vexpand">True</property>
- <property name="margin-top">6</property>
- <property name="margin-start">12</property>
+ <property name="orientation">horizontal</property>
<child>
- <object class="GtkTreeView" id="details-subkey-tree">
- <property name="height_request">100</property>
+ <object class="GtkLabel">
<property name="visible">True</property>
- <property name="can_focus">True</property>
- <child internal-child="selection">
- <object class="GtkTreeSelection" id="treeview-selection3"/>
- </child>
+ <property name="hexpand">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Subkeys</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
</object>
</child>
</object>
</child>
- <child type="label">
- <object class="GtkLabel">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label" translatable="yes">_Subkeys</property>
- <property name="use_underline">True</property>
- <attributes>
- <attribute name="weight" value="bold"/>
- </attributes>
- </object>
- </child>
</object>
</child>
</object>
diff --git a/pgp/seahorse-pgp-subkey-list-box-row.ui b/pgp/seahorse-pgp-subkey-list-box-row.ui
new file mode 100644
index 00000000..9b1d0ba8
--- /dev/null
+++ b/pgp/seahorse-pgp-subkey-list-box-row.ui
@@ -0,0 +1,233 @@
+<?xml version="1.0"?>
+<interface>
+ <requires lib="gtk+" version="3.24"/>
+ <menu id="subkey_menu">
+ <section>
+ <item>
+ <attribute name="label" translatable="yes">Change expiration date</attribute>
+ <attribute name="action">subkey.change-expires</attribute>
+ </item>
+ <item>
+ <attribute name="label" translatable="yes">Revoke subkey</attribute>
+ <attribute name="action">subkey.revoke</attribute>
+ </item>
+ <item>
+ <attribute name="label" translatable="yes">Delete subkey</attribute>
+ <attribute name="action">subkey.delete</attribute>
+ </item>
+ </section>
+ </menu>
+ <template class="SeahorsePgpSubkeyListBoxRow" parent="GtkListBoxRow">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkGrid">
+ <property name="visible">True</property>
+ <property name="column-spacing">12</property>
+ <property name="margin">6</property>
+ <child>
+ <object class="GtkLabel" id="keyid_label">
+ <property name="visible">True</property>
+ <property name="selectable">True</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="top_attach">0</property>
+ <property name="left_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="usages_box">
+ <property name="visible">True</property>
+ <property name="hexpand">True</property>
+ <property name="spacing">3</property>
+ <property name="orientation">horizontal</property>
+ </object>
+ <packing>
+ <property name="top_attach">0</property>
+ <property name="left_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkImage" id="status_box">
+ <property name="visible">True</property>
+ <property name="icon-name">emblem-important-symbolic</property>
+ <style>
+ <class name="pgp-subkey-status-box" />
+ </style>
+ </object>
+ <packing>
+ <property name="top_attach">0</property>
+ <property name="left_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="expires_label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="top_attach">0</property>
+ <property name="left_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRevealer" id="revealer">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkSeparator">
+ <property name="visible">True</property>
+ <property name="margin">12</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkGrid">
+ <property name="visible">True</property>
+ <property name="row-spacing">6</property>
+ <property name="column-spacing">6</property>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="xalign">1</property>
+ <property name="label" translatable="yes">Fingerprint</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ <packing>
+ <property name="top_attach">0</property>
+ <property name="left_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="fingerprint_label">
+ <property name="visible">True</property>
+ <property name="selectable">True</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="top_attach">0</property>
+ <property name="left_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="xalign">1</property>
+ <property name="label" translatable="yes">Type</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="left_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="algo_label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="left_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="xalign">1</property>
+ <property name="label" translatable="yes">Created</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ <packing>
+ <property name="top_attach">2</property>
+ <property name="left_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="created_label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="top_attach">2</property>
+ <property name="left_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="action_box">
+ <property name="visible">True</property>
+ <property name="orientation">horizontal</property>
+ <property name="spacing">3</property>
+ <property name="margin">6</property>
+ <child>
+ <object class="GtkButton">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Change expiry date</property>
+ <property name="action-name">subkey.change-expires</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Revoke</property>
+ <property name="action-name">subkey.revoke</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Delete</property>
+ <property name="action-name">subkey.delete</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="top_attach">3</property>
+ <property name="left_attach">0</property>
+ <property name="width">2</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="left_attach">0</property>
+ <property name="width">5</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton">
+ <property name="visible">True</property>
+ <property name="halign">end</property>
+ <property name="action-name">subkey.toggle-reveal</property>
+ <child>
+ <object class="GtkImage" id="reveal_icon">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon_name">pan-down-symbolic</property>
+ </object>
+ </child>
+ <style>
+ <class name="flat"/>
+ </style>
+ </object>
+ <packing>
+ <property name="top_attach">0</property>
+ <property name="left_attach">4</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/pgp/seahorse-pgp-subkey-list-box.c b/pgp/seahorse-pgp-subkey-list-box.c
new file mode 100644
index 00000000..d2ff687b
--- /dev/null
+++ b/pgp/seahorse-pgp-subkey-list-box.c
@@ -0,0 +1,464 @@
+/*
+ * Seahorse
+ *
+ * Copyright (C) 2021 Niels De Graef
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include "seahorse-gpgme-expires-dialog.h"
+#include "seahorse-gpgme-key-op.h"
+#include "seahorse-gpgme-revoke-dialog.h"
+#include "seahorse-pgp-key.h"
+#include "seahorse-pgp-subkey-list-box.h"
+#include "seahorse-pgp-subkey.h"
+
+#include <glib/gi18n.h>
+
+struct _SeahorsePgpSubkeyListBox {
+ GtkListBox parent_instance;
+
+ SeahorsePgpKey *key;
+};
+
+enum {
+ PROP_0,
+ PROP_KEY,
+ N_PROPS
+};
+static GParamSpec *obj_props[N_PROPS] = { NULL, };
+
+G_DEFINE_TYPE (SeahorsePgpSubkeyListBox, seahorse_pgp_subkey_list_box, GTK_TYPE_LIST_BOX)
+
+static void
+seahorse_pgp_subkey_list_box_set_property (GObject *object,
+ unsigned int prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ SeahorsePgpSubkeyListBox *self = SEAHORSE_PGP_SUBKEY_LIST_BOX (object);
+
+ switch (prop_id) {
+ case PROP_KEY:
+ g_set_object (&self->key, g_value_dup_object (value));
+ break;
+ }
+}
+
+static void
+seahorse_pgp_subkey_list_box_get_property (GObject *object,
+ unsigned int prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ SeahorsePgpSubkeyListBox *self = SEAHORSE_PGP_SUBKEY_LIST_BOX (object);
+
+ switch (prop_id) {
+ case PROP_KEY:
+ g_value_set_object (value, seahorse_pgp_subkey_list_box_get_key (self));
+ break;
+ }
+}
+
+static GtkWidget *
+create_subkey_row (void *item,
+ void *user_data)
+{
+ SeahorsePgpSubkey *subkey = SEAHORSE_PGP_SUBKEY (item);
+
+ return g_object_new (SEAHORSE_PGP_TYPE_SUBKEY_LIST_BOX_ROW,
+ "subkey", subkey,
+ NULL);
+}
+
+static void
+seahorse_pgp_subkey_list_box_constructed (GObject *obj)
+{
+ SeahorsePgpSubkeyListBox *self = SEAHORSE_PGP_SUBKEY_LIST_BOX (obj);
+
+ G_OBJECT_CLASS (seahorse_pgp_subkey_list_box_parent_class)->constructed (obj);
+
+ gtk_list_box_bind_model (GTK_LIST_BOX (self),
+ seahorse_pgp_key_get_subkeys (self->key),
+ create_subkey_row,
+ self,
+ NULL);
+}
+
+static void
+seahorse_pgp_subkey_list_box_init (SeahorsePgpSubkeyListBox *self)
+{
+ GtkStyleContext *style_context;
+
+ style_context = gtk_widget_get_style_context (GTK_WIDGET (self));
+ gtk_style_context_add_class (style_context, "content");
+}
+
+static void
+seahorse_pgp_subkey_list_box_finalize (GObject *obj)
+{
+ SeahorsePgpSubkeyListBox *self = SEAHORSE_PGP_SUBKEY_LIST_BOX (obj);
+
+ g_clear_object (&self->key);
+
+ G_OBJECT_CLASS (seahorse_pgp_subkey_list_box_parent_class)->finalize (obj);
+}
+
+static void
+seahorse_pgp_subkey_list_box_class_init (SeahorsePgpSubkeyListBoxClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->get_property = seahorse_pgp_subkey_list_box_get_property;
+ gobject_class->set_property = seahorse_pgp_subkey_list_box_set_property;
+ gobject_class->constructed = seahorse_pgp_subkey_list_box_constructed;
+ gobject_class->finalize = seahorse_pgp_subkey_list_box_finalize;
+
+ obj_props[PROP_KEY] =
+ g_param_spec_object ("key", "Pgp Key", "The key to list subkeys for",
+ SEAHORSE_PGP_TYPE_KEY,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (gobject_class, N_PROPS, obj_props);
+}
+
+GtkWidget *
+seahorse_pgp_subkey_list_box_new (SeahorsePgpKey *key)
+{
+ return g_object_new (SEAHORSE_PGP_TYPE_SUBKEY_LIST_BOX,
+ "selection-mode", GTK_SELECTION_NONE,
+ "key", key,
+ NULL);
+}
+
+SeahorsePgpKey *
+seahorse_pgp_subkey_list_box_get_key (SeahorsePgpSubkeyListBox *self)
+{
+ g_return_val_if_fail (SEAHORSE_PGP_IS_SUBKEY_LIST_BOX (self), NULL);
+ return self->key;
+}
+
+/* SeahorsePhpSubkeyListBoxRow */
+
+struct _SeahorsePgpSubkeyListBoxRow {
+ GtkListBoxRow parent_instance;
+
+ SeahorsePgpSubkey *subkey;
+
+ GSimpleActionGroup *action_group;
+
+ GtkWidget *status_box;
+ GtkWidget *keyid_label;
+ GtkWidget *usages_box;
+ GtkWidget *revealer;
+ GtkWidget *reveal_icon;
+ GtkWidget *algo_label;
+ GtkWidget *expires_label;
+ GtkWidget *created_label;
+ GtkWidget *fingerprint_label;
+ GtkWidget *action_box;
+};
+
+enum {
+ ROW_PROP_0,
+ ROW_PROP_SUBKEY,
+ ROW_N_PROPS
+};
+static GParamSpec *row_props[ROW_N_PROPS] = { NULL, };
+
+G_DEFINE_TYPE (SeahorsePgpSubkeyListBoxRow, seahorse_pgp_subkey_list_box_row, GTK_TYPE_LIST_BOX_ROW)
+
+static GtkWindow *
+get_toplevel_window (SeahorsePgpSubkeyListBoxRow *row)
+{
+ GtkWidget *toplevel = NULL;
+
+ toplevel = gtk_widget_get_toplevel (GTK_WIDGET (row));
+ if (GTK_IS_WINDOW (toplevel))
+ return GTK_WINDOW (toplevel);
+
+ return NULL;
+}
+
+static void
+on_subkey_delete (GSimpleAction *action, GVariant *param, void *user_data)
+{
+ SeahorsePgpSubkeyListBoxRow *row = SEAHORSE_PGP_SUBKEY_LIST_BOX_ROW (user_data);
+ const char *fingerprint;
+ g_autofree char *message = NULL;
+ gpgme_error_t err;
+
+ g_return_if_fail (SEAHORSE_GPGME_IS_SUBKEY (row->subkey));
+
+ fingerprint = seahorse_pgp_subkey_get_fingerprint (row->subkey);
+ message = g_strdup_printf (_("Are you sure you want to permanently delete subkey %s?"), fingerprint);
+
+ if (!seahorse_delete_dialog_prompt (get_toplevel_window (row), message))
+ return;
+
+ err = seahorse_gpgme_key_op_del_subkey (SEAHORSE_GPGME_SUBKEY (row->subkey));
+ if (!GPG_IS_OK (err))
+ seahorse_gpgme_handle_error (err, _("Couldn’t delete subkey"));
+}
+
+static void
+on_subkey_revoke (GSimpleAction *action, GVariant *param, void *user_data)
+{
+ SeahorsePgpSubkeyListBoxRow *row = SEAHORSE_PGP_SUBKEY_LIST_BOX_ROW (user_data);
+ GtkWidget *dialog = NULL;
+
+ g_return_if_fail (SEAHORSE_GPGME_IS_SUBKEY (row->subkey));
+
+ dialog = seahorse_gpgme_revoke_dialog_new (SEAHORSE_GPGME_SUBKEY (row->subkey),
+ get_toplevel_window (row));
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+}
+
+static void
+on_subkey_change_expires (GSimpleAction *action, GVariant *param, void *user_data)
+{
+ SeahorsePgpSubkeyListBoxRow *row = SEAHORSE_PGP_SUBKEY_LIST_BOX_ROW (user_data);
+ GtkDialog *dialog;
+
+ g_return_if_fail (SEAHORSE_GPGME_IS_SUBKEY (row->subkey));
+
+ dialog = seahorse_gpgme_expires_dialog_new (SEAHORSE_GPGME_SUBKEY (row->subkey),
+ get_toplevel_window (row));
+ gtk_dialog_run (dialog);
+ gtk_widget_destroy (GTK_WIDGET (dialog));
+}
+
+static void
+on_subkey_toggle_reveal (GSimpleAction *action, GVariant *param, void *user_data)
+{
+ SeahorsePgpSubkeyListBoxRow *row = SEAHORSE_PGP_SUBKEY_LIST_BOX_ROW (user_data);
+ gboolean reveal;
+ const char *icon_name;
+
+ reveal = !gtk_revealer_get_reveal_child (GTK_REVEALER (row->revealer));
+ gtk_revealer_set_reveal_child (GTK_REVEALER (row->revealer), reveal);
+
+ icon_name = reveal? "pan-up-symbolic" : "pan-down-symbolic";
+ gtk_image_set_from_icon_name (GTK_IMAGE (row->reveal_icon),
+ icon_name,
+ GTK_ICON_SIZE_BUTTON);
+}
+
+static const GActionEntry SUBKEY_ACTIONS[] = {
+ { "toggle-reveal", on_subkey_toggle_reveal },
+ { "delete", on_subkey_delete },
+ { "revoke", on_subkey_revoke },
+ { "change-expires", on_subkey_change_expires },
+};
+
+static void
+update_row (SeahorsePgpSubkeyListBoxRow *row)
+{
+ unsigned int flags;
+ g_auto(GStrv) usages = NULL, descriptions = NULL;
+ g_autofree char *algo_str = NULL;
+ GDateTime *expires, *created;
+ g_autofree char *expires_str = NULL, *created_str = NULL;
+ SeahorsePgpKey *parent_key;
+
+ /* Start with the flags, since these can largely affect what we show */
+ flags = seahorse_pgp_subkey_get_flags (row->subkey);
+ if (flags & SEAHORSE_FLAG_REVOKED) {
+ GAction *action;
+
+ gtk_widget_show (row->status_box);
+ gtk_widget_set_tooltip_text (row->status_box, _("Subkey was revoked"));
+
+ action = g_action_map_lookup_action (G_ACTION_MAP (row->action_group),
+ "revoke");
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (action), FALSE);
+ } else if (flags & SEAHORSE_FLAG_EXPIRED) {
+ gtk_widget_show (row->status_box);
+ gtk_widget_set_tooltip_text (row->status_box, _("Subkey has expired"));
+ } else if (flags & SEAHORSE_FLAG_DISABLED) {
+ gtk_widget_show (row->status_box);
+ gtk_widget_set_tooltip_text (row->status_box, _("Subkey is disabled"));
+ } else if (flags & SEAHORSE_FLAG_IS_VALID) {
+ gtk_widget_hide (row->status_box);
+ }
+
+ /* Set the key id */
+ gtk_label_set_text (GTK_LABEL (row->keyid_label),
+ seahorse_pgp_subkey_get_keyid (row->subkey));
+
+ /* Add the usage tags */
+ usages = seahorse_pgp_subkey_get_usages (row->subkey, &descriptions);
+ for (unsigned i = 0; i < g_strv_length (usages); i++) {
+ GtkWidget *label;
+
+ label = gtk_label_new (usages[i]);
+ gtk_widget_set_tooltip_text (label, descriptions[i]);
+ gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
+ gtk_widget_show (label);
+ gtk_box_pack_start (GTK_BOX (row->usages_box), label, FALSE, FALSE, 0);
+ gtk_style_context_add_class (gtk_widget_get_style_context (label),
+ "pgp-subkey-usage-label");
+ }
+
+ /* Expiration date */
+ expires = seahorse_pgp_subkey_get_expires (row->subkey);
+ expires_str = expires? g_date_time_format (expires, "Expires on %x")
+ : g_strdup (_("Never expires"));
+ gtk_label_set_text (GTK_LABEL (row->expires_label), expires_str);
+
+ /* Stuff that is hidden by default (but can be shown with the revealer) */
+
+ /* Full fingerprint */
+ gtk_label_set_text (GTK_LABEL (row->fingerprint_label),
+ seahorse_pgp_subkey_get_fingerprint (row->subkey));
+
+ /* Translators: first part is the algorithm, second part is the length,
+ * e.g. "RSA" (2048 bit) */
+ algo_str = g_strdup_printf (_("%s (%d bit)"),
+ seahorse_pgp_subkey_get_algorithm (row->subkey),
+ seahorse_pgp_subkey_get_length (row->subkey));
+ gtk_label_set_text (GTK_LABEL (row->algo_label), algo_str);
+
+ /* Creation date */
+ created = seahorse_pgp_subkey_get_created (row->subkey);
+ created_str = created? g_date_time_format (created, "%x") : g_strdup (_("Unknown"));
+ gtk_label_set_text (GTK_LABEL (row->created_label), created_str);
+
+ parent_key = seahorse_pgp_subkey_get_parent_key (SEAHORSE_PGP_SUBKEY (row->subkey));
+ if (seahorse_object_get_usage (SEAHORSE_OBJECT (parent_key)) != SEAHORSE_USAGE_PRIVATE_KEY)
+ gtk_widget_hide (row->action_box);
+}
+
+static void
+seahorse_pgp_subkey_list_box_row_set_property (GObject *object,
+ unsigned int prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ SeahorsePgpSubkeyListBoxRow *row = SEAHORSE_PGP_SUBKEY_LIST_BOX_ROW (object);
+
+ switch (prop_id) {
+ case ROW_PROP_SUBKEY:
+ g_set_object (&row->subkey, g_value_dup_object (value));
+ break;
+ }
+}
+
+static void
+seahorse_pgp_subkey_list_box_row_get_property (GObject *object,
+ unsigned int prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ SeahorsePgpSubkeyListBoxRow *row = SEAHORSE_PGP_SUBKEY_LIST_BOX_ROW (object);
+
+ switch (prop_id) {
+ case ROW_PROP_SUBKEY:
+ g_value_set_object (value, seahorse_pgp_subkey_list_box_row_get_subkey (row));
+ break;
+ }
+}
+
+static void
+on_subkey_notify (GObject *object, GParamSpec *pspec, void *user_data)
+{
+ SeahorsePgpSubkeyListBoxRow *row = SEAHORSE_PGP_SUBKEY_LIST_BOX_ROW (user_data);
+
+ update_row (row);
+}
+
+static void
+seahorse_pgp_subkey_list_box_row_constructed (GObject *obj)
+{
+ SeahorsePgpSubkeyListBoxRow *row = SEAHORSE_PGP_SUBKEY_LIST_BOX_ROW (obj);
+
+ G_OBJECT_CLASS (seahorse_pgp_subkey_list_box_row_parent_class)->constructed (obj);
+
+ g_signal_connect_object (row->subkey, "notify",
+ G_CALLBACK (on_subkey_notify), row, 0);
+ update_row (row);
+}
+
+static void
+seahorse_pgp_subkey_list_box_row_init (SeahorsePgpSubkeyListBoxRow *row)
+{
+ GtkStyleContext *style_context;
+
+ gtk_widget_init_template (GTK_WIDGET (row));
+ style_context = gtk_widget_get_style_context (GTK_WIDGET (row));
+ gtk_style_context_add_class (style_context, "pgp-subkey-row");
+
+ row->action_group = g_simple_action_group_new ();
+ g_action_map_add_action_entries (G_ACTION_MAP (row->action_group),
+ SUBKEY_ACTIONS,
+ G_N_ELEMENTS (SUBKEY_ACTIONS),
+ row);
+ gtk_widget_insert_action_group (GTK_WIDGET (row),
+ "subkey",
+ G_ACTION_GROUP (row->action_group));
+}
+
+static void
+seahorse_pgp_subkey_list_box_row_finalize (GObject *obj)
+{
+ SeahorsePgpSubkeyListBoxRow *row = SEAHORSE_PGP_SUBKEY_LIST_BOX_ROW (obj);
+
+ g_clear_object (&row->subkey);
+ g_clear_object (&row->action_group);
+
+ G_OBJECT_CLASS (seahorse_pgp_subkey_list_box_row_parent_class)->finalize (obj);
+}
+
+static void
+seahorse_pgp_subkey_list_box_row_class_init (SeahorsePgpSubkeyListBoxRowClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+ gobject_class->get_property = seahorse_pgp_subkey_list_box_row_get_property;
+ gobject_class->set_property = seahorse_pgp_subkey_list_box_row_set_property;
+ gobject_class->constructed = seahorse_pgp_subkey_list_box_row_constructed;
+ gobject_class->finalize = seahorse_pgp_subkey_list_box_row_finalize;
+
+ row_props[ROW_PROP_SUBKEY] =
+ g_param_spec_object ("subkey", "PGP subkey", "The subkey this row shows",
+ SEAHORSE_PGP_TYPE_SUBKEY,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (gobject_class, ROW_N_PROPS, row_props);
+
+ /* GtkWidget template */
+ gtk_widget_class_set_template_from_resource (widget_class,
"/org/gnome/Seahorse/seahorse-pgp-subkey-list-box-row.ui");
+
+ gtk_widget_class_bind_template_child (widget_class, SeahorsePgpSubkeyListBoxRow, status_box);
+ gtk_widget_class_bind_template_child (widget_class, SeahorsePgpSubkeyListBoxRow, keyid_label);
+ gtk_widget_class_bind_template_child (widget_class, SeahorsePgpSubkeyListBoxRow, usages_box);
+ gtk_widget_class_bind_template_child (widget_class, SeahorsePgpSubkeyListBoxRow, revealer);
+ gtk_widget_class_bind_template_child (widget_class, SeahorsePgpSubkeyListBoxRow, reveal_icon);
+ gtk_widget_class_bind_template_child (widget_class, SeahorsePgpSubkeyListBoxRow, algo_label);
+ gtk_widget_class_bind_template_child (widget_class, SeahorsePgpSubkeyListBoxRow, expires_label);
+ gtk_widget_class_bind_template_child (widget_class, SeahorsePgpSubkeyListBoxRow, created_label);
+ gtk_widget_class_bind_template_child (widget_class, SeahorsePgpSubkeyListBoxRow, fingerprint_label);
+ gtk_widget_class_bind_template_child (widget_class, SeahorsePgpSubkeyListBoxRow, action_box);
+}
+
+SeahorsePgpSubkey *
+seahorse_pgp_subkey_list_box_row_get_subkey (SeahorsePgpSubkeyListBoxRow *row)
+{
+ g_return_val_if_fail (SEAHORSE_PGP_IS_SUBKEY_LIST_BOX_ROW (row), NULL);
+ return row->subkey;
+}
diff --git a/pgp/seahorse-pgp-subkey-list-box.h b/pgp/seahorse-pgp-subkey-list-box.h
new file mode 100644
index 00000000..63ff170a
--- /dev/null
+++ b/pgp/seahorse-pgp-subkey-list-box.h
@@ -0,0 +1,42 @@
+/*
+ * Seahorse
+ *
+ * Copyright (C) 2021 Niels De Graef
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+#include "seahorse-common.h"
+#include "seahorse-pgp-types.h"
+
+#define SEAHORSE_PGP_TYPE_SUBKEY_LIST_BOX (seahorse_pgp_subkey_list_box_get_type ())
+G_DECLARE_FINAL_TYPE (SeahorsePgpSubkeyListBox, seahorse_pgp_subkey_list_box,
+ SEAHORSE_PGP, SUBKEY_LIST_BOX,
+ GtkListBox)
+
+GtkWidget * seahorse_pgp_subkey_list_box_new (SeahorsePgpKey *key);
+
+SeahorsePgpKey * seahorse_pgp_subkey_list_box_get_key (SeahorsePgpSubkeyListBox *self);
+
+#define SEAHORSE_PGP_TYPE_SUBKEY_LIST_BOX_ROW (seahorse_pgp_subkey_list_box_row_get_type ())
+G_DECLARE_FINAL_TYPE (SeahorsePgpSubkeyListBoxRow, seahorse_pgp_subkey_list_box_row,
+ SEAHORSE_PGP, SUBKEY_LIST_BOX_ROW,
+ GtkListBoxRow)
+
+SeahorsePgpSubkey * seahorse_pgp_subkey_list_box_row_get_subkey (SeahorsePgpSubkeyListBoxRow *self);
diff --git a/pgp/seahorse-pgp-subkey.c b/pgp/seahorse-pgp-subkey.c
index e4e6fdd0..dbc55c66 100644
--- a/pgp/seahorse-pgp-subkey.c
+++ b/pgp/seahorse-pgp-subkey.c
@@ -29,6 +29,7 @@
enum {
PROP_0,
+ PROP_PARENT_KEY,
PROP_INDEX,
PROP_KEYID,
PROP_FLAGS,
@@ -43,6 +44,7 @@ enum {
static GParamSpec *obj_props[N_PROPS] = { NULL, };
typedef struct _SeahorsePgpSubkeyPrivate {
+ SeahorsePgpKey *parent_key;
unsigned int index;
char *keyid;
unsigned int flags;
@@ -56,6 +58,28 @@ typedef struct _SeahorsePgpSubkeyPrivate {
G_DEFINE_TYPE_WITH_PRIVATE (SeahorsePgpSubkey, seahorse_pgp_subkey, G_TYPE_OBJECT);
+SeahorsePgpKey *
+seahorse_pgp_subkey_get_parent_key (SeahorsePgpSubkey *self)
+{
+ SeahorsePgpSubkeyPrivate *priv = seahorse_pgp_subkey_get_instance_private (self);
+
+ g_return_val_if_fail (SEAHORSE_PGP_IS_SUBKEY (self), NULL);
+ return priv->parent_key;
+}
+
+void
+seahorse_pgp_subkey_set_parent_key (SeahorsePgpSubkey *self,
+ SeahorsePgpKey *parent_key)
+{
+ SeahorsePgpSubkeyPrivate *priv = seahorse_pgp_subkey_get_instance_private (self);
+
+ g_return_if_fail (SEAHORSE_PGP_IS_SUBKEY (self));
+ g_return_if_fail (SEAHORSE_PGP_IS_KEY (parent_key));
+
+ priv->parent_key = parent_key;
+ g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_PARENT_KEY]);
+}
+
unsigned int
seahorse_pgp_subkey_get_index (SeahorsePgpSubkey *self)
{
@@ -157,40 +181,62 @@ seahorse_pgp_subkey_set_length (SeahorsePgpSubkey *self, unsigned int length)
*/
char *
seahorse_pgp_subkey_get_usage (SeahorsePgpSubkey *self)
+{
+ g_auto(GStrv) usages = NULL;
+
+ g_return_val_if_fail (SEAHORSE_PGP_IS_SUBKEY (self), NULL);
+
+ usages = seahorse_pgp_subkey_get_usages (self, NULL);
+ return g_strjoinv (", ", usages);
+}
+
+/**
+ * seahorse_pgp_subkey_get_usages:
+ * @self: A #SeahorsePgpSubkey
+ * @decriptions: (transfer full) (array zero-terminated=1) (optional):
+ * The descriptions of the subkey's usages
+ *
+ * Returns: (transfer full) (array zero-terminated=1): the subkey's usages,
+ * for example: { "Encrypt" , "Sign" , "Certify", %NULL }
+ */
+char **
+seahorse_pgp_subkey_get_usages (SeahorsePgpSubkey *self, char ***descriptions)
{
typedef struct {
unsigned int flag;
const char *name;
+ const char *description;
} FlagNames;
const FlagNames flag_names[] = {
- { SEAHORSE_FLAG_CAN_ENCRYPT, N_("Encrypt") },
- { SEAHORSE_FLAG_CAN_SIGN, N_("Sign") },
- { SEAHORSE_FLAG_CAN_CERTIFY, N_("Certify") },
- { SEAHORSE_FLAG_CAN_AUTHENTICATE, N_("Authenticate") }
+ { SEAHORSE_FLAG_CAN_ENCRYPT, N_("Encrypt"), N_("This subkey can be used for encryption") },
+ { SEAHORSE_FLAG_CAN_SIGN, N_("Sign"), N_("This subkey can be used to create data signatures") },
+ { SEAHORSE_FLAG_CAN_CERTIFY, N_("Certify"), N_("This subkey can be used to create certificates") },
+ { SEAHORSE_FLAG_CAN_AUTHENTICATE, N_("Authenticate"), N_("This subkey can be used for
authentication") }
};
SeahorsePgpSubkeyPrivate *priv = seahorse_pgp_subkey_get_instance_private (self);
- GString *str;
- gboolean previous;
- unsigned int i;
+ g_autoptr(GPtrArray) names = NULL, descs = NULL;
g_return_val_if_fail (SEAHORSE_PGP_IS_SUBKEY (self), NULL);
- str = g_string_new (NULL);
- previous = FALSE;
+ names = g_ptr_array_new_with_free_func (g_free);
+ descs = g_ptr_array_new_with_free_func (g_free);
- for (i = 0; i < G_N_ELEMENTS (flag_names); i++) {
+ for (unsigned i = 0; i < G_N_ELEMENTS (flag_names); i++) {
if (priv->flags & flag_names[i].flag) {
- if (previous)
- g_string_append (str, ", ");
-
- previous = TRUE;
- g_string_append (str, _(flag_names[i].name));
+ g_ptr_array_add (names, g_strdup (_(flag_names[i].name)));
+ g_ptr_array_add (descs, g_strdup (_(flag_names[i].description)));
}
}
- return g_string_free (str, FALSE);
+ g_ptr_array_add (names, NULL);
+ g_ptr_array_add (descs, NULL);
+
+ if (descriptions)
+ *descriptions = (char**) g_ptr_array_free (g_steal_pointer (&descs), FALSE);
+
+ return (char **) g_ptr_array_free (g_steal_pointer (&names), FALSE);
}
/**
@@ -413,6 +459,9 @@ seahorse_pgp_subkey_get_property (GObject *object,
SeahorsePgpSubkey *self = SEAHORSE_PGP_SUBKEY (object);
switch (prop_id) {
+ case PROP_PARENT_KEY:
+ g_value_set_object (value, seahorse_pgp_subkey_get_parent_key (self));
+ break;
case PROP_INDEX:
g_value_set_uint (value, seahorse_pgp_subkey_get_index (self));
break;
@@ -452,6 +501,9 @@ seahorse_pgp_subkey_set_property (GObject *object,
SeahorsePgpSubkey *self = SEAHORSE_PGP_SUBKEY (object);
switch (prop_id) {
+ case PROP_PARENT_KEY:
+ seahorse_pgp_subkey_set_parent_key (self, g_value_get_object (value));
+ break;
case PROP_INDEX:
seahorse_pgp_subkey_set_index (self, g_value_get_uint (value));
break;
@@ -513,6 +565,11 @@ seahorse_pgp_subkey_class_init (SeahorsePgpSubkeyClass *klass)
gobject_class->set_property = seahorse_pgp_subkey_set_property;
gobject_class->get_property = seahorse_pgp_subkey_get_property;
+ obj_props[PROP_PARENT_KEY] =
+ g_param_spec_object ("parent-key", "Parent Key", "Key this subkey belongs to",
+ SEAHORSE_PGP_TYPE_KEY,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
obj_props[PROP_INDEX] =
g_param_spec_uint ("index", "Index", "PGP subkey index",
0, G_MAXUINT, 0,
diff --git a/pgp/seahorse-pgp-subkey.h b/pgp/seahorse-pgp-subkey.h
index 47dbc830..ed5f81a4 100644
--- a/pgp/seahorse-pgp-subkey.h
+++ b/pgp/seahorse-pgp-subkey.h
@@ -22,6 +22,7 @@
#include <glib-object.h>
#include "seahorse-common.h"
+#include "pgp/seahorse-pgp-key.h"
#define SEAHORSE_PGP_TYPE_SUBKEY (seahorse_pgp_subkey_get_type ())
G_DECLARE_DERIVABLE_TYPE (SeahorsePgpSubkey, seahorse_pgp_subkey,
@@ -34,6 +35,11 @@ struct _SeahorsePgpSubkeyClass {
SeahorsePgpSubkey* seahorse_pgp_subkey_new (void);
+SeahorsePgpKey * seahorse_pgp_subkey_get_parent_key (SeahorsePgpSubkey *self);
+
+void seahorse_pgp_subkey_set_parent_key (SeahorsePgpSubkey *self,
+ SeahorsePgpKey *parent_key);
+
unsigned int seahorse_pgp_subkey_get_index (SeahorsePgpSubkey *self);
void seahorse_pgp_subkey_set_index (SeahorsePgpSubkey *self,
@@ -61,6 +67,9 @@ void seahorse_pgp_subkey_set_length (SeahorsePgpSubkey *se
char * seahorse_pgp_subkey_get_usage (SeahorsePgpSubkey *self);
+char ** seahorse_pgp_subkey_get_usages (SeahorsePgpSubkey *self,
+ char ***descriptions);
+
GDateTime * seahorse_pgp_subkey_get_created (SeahorsePgpSubkey *self);
void seahorse_pgp_subkey_set_created (SeahorsePgpSubkey *self,
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 15cf5bae..67b76914 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -75,6 +75,8 @@ pgp/seahorse-pgp-key-properties.c
pgp/seahorse-pgp-private-key-properties.ui
pgp/seahorse-pgp-public-key-properties.ui
pgp/seahorse-pgp-subkey.c
+pgp/seahorse-pgp-subkey-list-box.c
+pgp/seahorse-pgp-subkey-list-box-row.ui
pgp/seahorse-revoke.ui
pgp/seahorse-server-source.c
pgp/seahorse-transfer.c
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]