[seahorse/pgp/uids-listbox: 14/15] uid-listbox: Create new widget for display UIDs
- From: Niels De Graef <nielsdg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [seahorse/pgp/uids-listbox: 14/15] uid-listbox: Create new widget for display UIDs
- Date: Tue, 17 Aug 2021 06:00:10 +0000 (UTC)
commit 46a2208742bb41d223871e5740bd6f66693d8f05
Author: Niels De Graef <nielsdegraef gmail com>
Date: Mon Aug 16 07:51:24 2021 +0200
uid-listbox: Create new widget for display UIDs
Rather than using a `GtkTreeView` that's shoveled together in
pgp-key-properties.c, create a widget that can contain all the logic
of UIDs (and their signatures) and present them in a clean fashion, also
using modern widgets like those provided by libhandy.
This will allow for a major cleanup of the PGP key properties dialog
common/util.vala | 9 +
data/seahorse.gresource.xml | 1 +
pgp/meson.build | 1 +
pgp/seahorse-pgp-uid-list-box-row.ui | 115 ++++++++
pgp/seahorse-pgp-uid-list-box.c | 550 +++++++++++++++++++++++++++++++++++
pgp/seahorse-pgp-uid-list-box.h | 36 +++
6 files changed, 712 insertions(+)
---
diff --git a/common/util.vala b/common/util.vala
index 78706572..06b78bec 100644
--- a/common/util.vala
+++ b/common/util.vala
@@ -4,6 +4,7 @@
* Copyright (C) 2003 Jacob Perkins
* Copyright (C) 2004-2005 Stefan Walter
* Copyright (C) 2011 Collabora Ltd.
+ * Copyright (C) 2020 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
@@ -46,4 +47,12 @@ namespace Seahorse.Util {
dialog.run();
dialog.destroy();
}
+
+ public void toggle_action (GLib.SimpleAction action,
+ GLib.Variant? variant,
+ void* user_data) {
+ var old_state = action.get_state();
+ var new_state = new GLib.Variant.boolean(!old_state.get_boolean());
+ action.change_state(new_state);
+ }
}
diff --git a/data/seahorse.gresource.xml b/data/seahorse.gresource.xml
index 32aa3b2d..ec3b45e2 100644
--- a/data/seahorse.gresource.xml
+++ b/data/seahorse.gresource.xml
@@ -39,6 +39,7 @@
<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>
+ <file alias="seahorse-pgp-uid-list-box-row.ui"
preprocess="xml-stripblanks">../pgp/seahorse-pgp-uid-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/pgp/meson.build b/pgp/meson.build
index 3346c5d6..9a9bf076 100644
--- a/pgp/meson.build
+++ b/pgp/meson.build
@@ -31,6 +31,7 @@ pgp_sources = files(
'seahorse-pgp-subkey.c',
'seahorse-pgp-subkey-list-box.c',
'seahorse-pgp-uid.c',
+ 'seahorse-pgp-uid-list-box.c',
'seahorse-transfer.c',
'seahorse-unknown.c',
'seahorse-unknown-source.c',
diff --git a/pgp/seahorse-pgp-uid-list-box-row.ui b/pgp/seahorse-pgp-uid-list-box-row.ui
new file mode 100644
index 00000000..3b9c313e
--- /dev/null
+++ b/pgp/seahorse-pgp-uid-list-box-row.ui
@@ -0,0 +1,115 @@
+<?xml version="1.0"?>
+<interface>
+ <requires lib="gtk+" version="3.24"/>
+ <menu id="actions_menu">
+ <section>
+ <item>
+ <attribute name="label" translatable="yes">Make _primary</attribute>
+ <attribute name="action">uid.make-primary</attribute>
+ </item>
+ <item>
+ <attribute name="label" translatable="yes">_Sign</attribute>
+ <attribute name="action">uid.sign</attribute>
+ </item>
+ <item>
+ <attribute name="label" translatable="yes">_Delete</attribute>
+ <attribute name="action">uid.delete</attribute>
+ </item>
+ </section>
+ </menu>
+ <template class="SeahorsePgpUidListBoxRow" parent="HdyExpanderRow">
+ <property name="visible">True</property>
+ <property name="focus-on-click">False</property>
+ <child type="action">
+ <object class="GtkMenuButton" id="actions_button">
+ <property name="visible">True</property>
+ <property name="valign">center</property>
+ <property name="halign">end</property>
+ <property name="margin-start">6</property>
+ <property name="menu-model">actions_menu</property>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="icon-name">open-menu-symbolic</property>
+ </object>
+ </child>
+ <style>
+ <class name="flat"/>
+ </style>
+ </object>
+ </child>
+ <child type="prefix">
+ <object class="GtkImage" id="avatar">
+ <property name="visible">True</property>
+ <property name="icon-name">avatar-default-symbolic</property>
+ <property name="icon-size">5</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="spacing">12</property>
+ <property name="margin">18</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <property name="orientation">horizontal</property>
+ <child>
+ <object class="GtkLabel" id="signed_by_label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="valign">center</property>
+ <property name="label" translatable="yes">Signatures</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkSwitch" id="trusted_switch">
+ <property name="visible">True</property>
+ <property name="action-name">uid.only-trusted</property>
+ <property name="tooltip-text" translatable="yes">Only display the signatures of people I
trust</property>
+ </object>
+ <packing>
+ <property name="pack_type">end</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="xalign">1</property>
+ <property name="label" translatable="yes">Only trusted</property>
+ <property name="tooltip-text" translatable="yes">Only display the signatures of people I
trust</property>
+ <property name="mnemonic-widget">trusted_switch</property>
+ </object>
+ <packing>
+ <property name="pack_type">end</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkListBox" id="signatures_list">
+ <property name="visible">True</property>
+ <property name="selection-mode">none</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible" bind-source="signatures_list" bind-property="visible"
bind-flags="bidirectional|sync-create|invert-boolean" />
+ <property name="label" translatable="yes">No signatures available</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/pgp/seahorse-pgp-uid-list-box.c b/pgp/seahorse-pgp-uid-list-box.c
new file mode 100644
index 00000000..b05a7dab
--- /dev/null
+++ b/pgp/seahorse-pgp-uid-list-box.c
@@ -0,0 +1,550 @@
+/*
+ * 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 "pgp/seahorse-pgp-uid-list-box.h"
+
+#include "seahorse-gpgme-key-op.h"
+#include "pgp/seahorse-pgp-backend.h"
+#include "pgp/seahorse-pgp-signature.h"
+#include "pgp/seahorse-gpgme-uid.h"
+#include "pgp/seahorse-gpgme-add-uid.h"
+#include "pgp/seahorse-gpgme-sign-dialog.h"
+#include "pgp/seahorse-unknown.h"
+#include "seahorse-gpgme-dialogs.h"
+
+#include <glib/gi18n.h>
+
+/* ListBox object */
+
+struct _SeahorsePgpUidListBox {
+ GtkListBox parent_instance;
+
+ SeahorsePgpKey *key;
+};
+
+enum {
+ PROP_0,
+ PROP_KEY,
+ N_PROPS
+};
+static GParamSpec *obj_props[N_PROPS] = { NULL, };
+
+G_DEFINE_TYPE (SeahorsePgpUidListBox, seahorse_pgp_uid_list_box, GTK_TYPE_LIST_BOX);
+
+static GtkWidget *
+create_row_for_uid (void *item, void *user_data)
+{
+ g_return_val_if_fail (SEAHORSE_PGP_IS_UID (item), NULL);
+
+ return g_object_new (SEAHORSE_PGP_TYPE_UID_LIST_BOX_ROW,
+ "uid", SEAHORSE_PGP_UID (item),
+ NULL);
+}
+
+static void
+seahorse_pgp_uid_list_box_constructed (GObject *object)
+{
+ SeahorsePgpUidListBox *self = SEAHORSE_PGP_UID_LIST_BOX (object);
+
+ G_OBJECT_CLASS (seahorse_pgp_uid_list_box_parent_class)->constructed (object);
+
+ gtk_list_box_bind_model (GTK_LIST_BOX (self),
+ seahorse_pgp_key_get_uids (self->key),
+ create_row_for_uid,
+ self,
+ NULL);
+}
+
+static void
+seahorse_pgp_uid_list_box_init (SeahorsePgpUidListBox *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_uid_list_box_get_property (GObject *object,
+ unsigned int prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ SeahorsePgpUidListBox *self = SEAHORSE_PGP_UID_LIST_BOX (object);
+
+ switch (prop_id) {
+ case PROP_KEY:
+ g_value_set_object (value, self->key);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+seahorse_pgp_uid_list_box_set_property (GObject *object,
+ unsigned int prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ SeahorsePgpUidListBox *self = SEAHORSE_PGP_UID_LIST_BOX (object);
+
+ switch (prop_id) {
+ case PROP_KEY:
+ self->key = g_value_get_object (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+seahorse_pgp_uid_list_box_class_init (SeahorsePgpUidListBoxClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->set_property = seahorse_pgp_uid_list_box_set_property;
+ gobject_class->get_property = seahorse_pgp_uid_list_box_get_property;
+ gobject_class->constructed = seahorse_pgp_uid_list_box_constructed;
+
+ obj_props[PROP_KEY] =
+ g_param_spec_object ("key", "PGP key", "The key to list the UIDs for",
+ SEAHORSE_PGP_TYPE_KEY,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT);
+
+ g_object_class_install_properties (gobject_class, N_PROPS, obj_props);
+}
+
+GtkWidget *
+seahorse_pgp_uid_list_box_new (SeahorsePgpKey *key)
+{
+ g_return_val_if_fail (SEAHORSE_PGP_IS_KEY (key), NULL);
+
+ /* XXX We should store the key and connect to ::notify */
+ return g_object_new (SEAHORSE_PGP_TYPE_UID_LIST_BOX,
+ "key", key,
+ "selection-mode", GTK_SELECTION_NONE,
+ NULL);
+}
+
+/* Row object */
+
+struct _SeahorsePgpUidListBoxRow {
+ HdyExpanderRow parent_instance;
+
+ SeahorsePgpUid *uid;
+
+ GSimpleActionGroup *actions;
+ GtkWidget *actions_button;
+
+ GtkWidget *signatures_list;
+ /* the key ids from the signature list that were discovered */
+ GList *discovered_keys;
+};
+
+enum {
+ ROW_PROP_0,
+ ROW_PROP_UID,
+ ROW_N_PROPS
+};
+
+G_DEFINE_TYPE (SeahorsePgpUidListBoxRow, seahorse_pgp_uid_list_box_row, HDY_TYPE_EXPANDER_ROW);
+
+static void
+update_actions (SeahorsePgpUidListBoxRow *row)
+{
+ SeahorsePgpKey *parent;
+ GListModel *uids;
+ g_autoptr(SeahorsePgpUid) primary_uid = NULL;
+ gboolean is_primary;
+ GAction *action;
+
+ /* Figure out if we're the primary UID and update the make-primary action */
+ parent = seahorse_pgp_uid_get_parent (row->uid);
+ uids = seahorse_pgp_key_get_uids (parent);
+ primary_uid = g_list_model_get_item (uids, 0);
+ is_primary = (primary_uid == row->uid);
+
+ action = g_action_map_lookup_action (G_ACTION_MAP (row->actions),
+ "make-primary");
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (action), !is_primary);
+
+ /* Don't allow deleting the last UID */
+ action = g_action_map_lookup_action (G_ACTION_MAP (row->actions), "delete");
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
+ g_list_model_get_n_items (uids) > 1);
+}
+
+static void
+on_only_trusted_changed (GSimpleAction *action,
+ GVariant *new_state,
+ void *user_data)
+{
+ SeahorsePgpUidListBoxRow *row = SEAHORSE_PGP_UID_LIST_BOX_ROW (user_data);
+ GListModel *signatures;
+ unsigned int n_signatures = 0;
+ unsigned int n_shown = 0;
+ gboolean only_trusted;
+
+ only_trusted = g_variant_get_boolean (new_state);
+
+ signatures = seahorse_pgp_uid_get_signatures (row->uid);
+ n_signatures = g_list_model_get_n_items (signatures);
+
+ /* For each signature, check if we know about the key*/
+ for (unsigned int i = 0; i < n_signatures; i++) {
+ g_autoptr(SeahorsePgpSignature) sig = NULL;
+ GtkListBoxRow *sig_row;
+ SeahorseObject *signer;
+ gboolean trusted = FALSE;
+ gboolean should_show;
+
+ sig = g_list_model_get_item (signatures, i);
+ sig_row = gtk_list_box_get_row_at_index (GTK_LIST_BOX (row->signatures_list), i);
+
+ signer = g_object_get_data (G_OBJECT (sig_row), "signer");
+ if (signer) {
+ if (seahorse_object_get_usage (signer) == SEAHORSE_USAGE_PRIVATE_KEY)
+ trusted = TRUE;
+ else if (seahorse_object_get_flags (signer) & SEAHORSE_FLAG_TRUSTED)
+ trusted = TRUE;
+ }
+
+ should_show = (trusted || !only_trusted);
+ gtk_widget_set_visible (GTK_WIDGET (sig_row), should_show);
+ if (should_show)
+ n_shown++;
+ }
+
+ g_simple_action_set_state (G_SIMPLE_ACTION (action), new_state);
+
+ /* Hide the signature list if there are no rows visible */
+ gtk_widget_set_visible (row->signatures_list, n_shown > 0);
+}
+
+static void
+on_uid_delete (GSimpleAction *action, GVariant *param, void *user_data)
+{
+ SeahorsePgpUidListBoxRow *row = SEAHORSE_PGP_UID_LIST_BOX_ROW (user_data);
+ GtkWidget *window;
+ g_autofree char *message = NULL;
+ gpgme_error_t gerr;
+
+ g_return_if_fail (SEAHORSE_GPGME_IS_UID (row->uid));
+
+ window = gtk_widget_get_toplevel (GTK_WIDGET (row));
+ message = g_strdup_printf (_("Are you sure you want to permanently delete the “%s” user ID?"),
+ seahorse_object_get_label (SEAHORSE_OBJECT (row->uid)));
+
+ if (!seahorse_delete_dialog_prompt (GTK_WINDOW (window), message))
+ return;
+
+ gerr = seahorse_gpgme_key_op_del_uid (SEAHORSE_GPGME_UID (row->uid));
+ if (!GPG_IS_OK (gerr))
+ seahorse_gpgme_handle_error (gerr, _("Couldn’t delete user ID"));
+}
+
+static void
+on_uid_make_primary_cb (GObject *source, GAsyncResult *res, void *user_data)
+{
+ GtkWidget *toplevel = GTK_WIDGET (user_data);
+ SeahorseGpgmeUid *uid = SEAHORSE_GPGME_UID (source);
+ g_autoptr(GError) error = NULL;
+
+ if (!seahorse_gpgme_key_op_make_primary_finish (uid, res, &error)) {
+ seahorse_util_show_error (toplevel,
+ _("Couldn’t change primary user ID"),
+ error->message);
+ }
+}
+
+static void
+on_uid_make_primary (GSimpleAction *action, GVariant *param, void *user_data)
+{
+ SeahorsePgpUidListBoxRow *row = SEAHORSE_PGP_UID_LIST_BOX_ROW (user_data);
+ GtkWidget *toplevel;
+
+ g_return_if_fail (SEAHORSE_GPGME_IS_UID (row->uid));
+
+ /* Don't pass the row itself as user_data, as that might be destroyed as
+ * part of the GListModel shuffle */
+ toplevel = gtk_widget_get_toplevel (GTK_WIDGET (row));
+
+ seahorse_gpgme_key_op_make_primary_async (SEAHORSE_GPGME_UID (row->uid),
+ NULL,
+ on_uid_make_primary_cb,
+ toplevel);
+}
+
+static void
+on_uid_sign (GSimpleAction *action, GVariant *param, void *user_data)
+{
+ SeahorsePgpUidListBoxRow *row = SEAHORSE_PGP_UID_LIST_BOX_ROW (user_data);
+ SeahorseGpgmeSignDialog *dialog;
+
+ g_return_if_fail (SEAHORSE_GPGME_IS_UID (row->uid));
+
+ dialog = seahorse_gpgme_sign_dialog_new (SEAHORSE_OBJECT (row->uid));
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (GTK_WIDGET (dialog));
+}
+
+static const GActionEntry UID_ACTION_ENTRIES[] = {
+ { "only-trusted", seahorse_util_toggle_action, NULL, "false", on_only_trusted_changed },
+ { "delete", on_uid_delete },
+ { "make-primary", on_uid_make_primary },
+ { "sign", on_uid_sign },
+ /* { "revoke", on_uid_revoke }, TODO */
+};
+
+static GtkWidget *
+create_row_for_signature (void *item, void *user_data)
+{
+ SeahorsePgpUidListBoxRow *row = SEAHORSE_PGP_UID_LIST_BOX_ROW (user_data);
+ SeahorsePgpSignature *signature = SEAHORSE_PGP_SIGNATURE (item);
+ GtkWidget *sig_row;
+ GtkWidget *box;
+ const char *sig_keyid;
+ GtkWidget *keyid_label;
+ g_autofree char *signer_name = NULL;
+ GtkWidget *signer_label;
+
+ sig_row = gtk_list_box_row_new ();
+ box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
+ gtk_widget_show (box);
+ gtk_container_add (GTK_CONTAINER (sig_row), box);
+
+ sig_keyid = seahorse_pgp_signature_get_keyid (signature);
+ keyid_label = gtk_label_new (sig_keyid);
+ gtk_widget_show (keyid_label);
+ gtk_box_pack_start (GTK_BOX (box), keyid_label, FALSE, FALSE, 0);
+
+ for (GList *l = row->discovered_keys; l; l = g_list_next (l)) {
+ if (SEAHORSE_PGP_IS_KEY (l->data)) {
+ SeahorsePgpKey *key = SEAHORSE_PGP_KEY (l->data);
+
+ if (seahorse_pgp_key_has_keyid (key, sig_keyid)) {
+ const char *name = seahorse_pgp_key_get_primary_name (key);
+ signer_name = g_strdup_printf ("(%s)", name);
+
+ g_object_set_data (G_OBJECT (sig_row), "signer", l->data);
+ break;
+ }
+ } else if (SEAHORSE_IS_UNKNOWN (l->data)) {
+ g_autofree char *keyid = NULL;
+ g_autofree char *label = NULL;
+
+ g_object_get (l->data, "identifier", &keyid, "label", &label, NULL);
+ if (seahorse_pgp_keyid_equal (sig_keyid, keyid)) {
+ signer_name = g_strdup_printf ("(%s)", label);
+ g_object_set_data (G_OBJECT (sig_row), "signer", l->data);
+ break;
+ }
+ }
+ }
+
+ if (!signer_name) {
+ /* Translators: (Unknown) signature name */
+ signer_name = g_strdup (_("(Unknown)"));
+ }
+
+ signer_label = gtk_label_new (signer_name);
+ gtk_widget_show (signer_label);
+ gtk_box_pack_start (GTK_BOX (box), signer_label, FALSE, FALSE, 0);
+
+ return sig_row;
+}
+
+static void
+on_row_expanded (GObject *object,
+ GParamSpec *pspec,
+ void *user_data)
+{
+ SeahorsePgpUidListBoxRow *row = SEAHORSE_PGP_UID_LIST_BOX_ROW (object);
+ gboolean expanded;
+ GListModel *signatures;
+ unsigned int n_signatures;
+ g_autofree char *signed_by_str = NULL;
+ g_autoptr(GCancellable) cancellable = NULL;
+ g_autoptr(GPtrArray) keyids = NULL;
+
+ /* Lazily discover keys by only loading when user actually expands the row
+ * (showing the signatures) and not reloading if already done earlier */
+ expanded = hdy_expander_row_get_expanded (HDY_EXPANDER_ROW (row));
+ if (!expanded || row->discovered_keys)
+ return;
+
+ signatures = seahorse_pgp_uid_get_signatures (row->uid);
+ n_signatures = g_list_model_get_n_items (signatures);
+
+ /* Discover the keys, so might be able to show their owner */
+ keyids = g_ptr_array_new ();
+ for (unsigned i = 0; i < n_signatures; i++) {
+ g_autoptr(SeahorsePgpSignature) sig = NULL;
+
+ sig = g_list_model_get_item (signatures, i);
+ g_ptr_array_add (keyids, (void *) seahorse_pgp_signature_get_keyid (sig));
+ }
+ g_ptr_array_add (keyids, NULL);
+
+ /* Pass it to the PGP backend for resolution/download, cancellable ties
+ * search scope together */
+ cancellable = g_cancellable_new ();
+ row->discovered_keys =
+ seahorse_pgp_backend_discover_keys (NULL,
+ (const char **) keyids->pdata,
+ cancellable);
+
+ /* Now build the list */
+ gtk_list_box_bind_model (GTK_LIST_BOX (row->signatures_list),
+ signatures,
+ create_row_for_signature,
+ row,
+ NULL);
+
+ gtk_widget_set_visible (row->signatures_list, n_signatures > 0);
+}
+
+static void
+update_row (SeahorsePgpUidListBoxRow *row)
+{
+ SeahorsePgpKey *parent_key;
+ gboolean is_editable;
+ g_autoptr(GString) title = NULL;
+ const char *comment, *email;
+
+ parent_key = seahorse_pgp_uid_get_parent (row->uid);
+ is_editable = seahorse_pgp_key_is_private_key (parent_key);
+
+ /* Put "name (comment)" as title */
+ title = g_string_new (seahorse_pgp_uid_get_name (row->uid));
+ comment = seahorse_pgp_uid_get_comment (row->uid);
+ if (comment && *comment)
+ g_string_append_printf (title, " (%s)", comment);
+ hdy_preferences_row_set_title (HDY_PREFERENCES_ROW (row), title->str);
+
+ /* Make a linkified version the email as subtitle */
+ email = seahorse_pgp_uid_get_email (row->uid);
+ if (email && *email)
+ hdy_expander_row_set_subtitle (HDY_EXPANDER_ROW (row), email);
+
+ /* Actions */
+ gtk_widget_set_visible (row->actions_button, is_editable);
+
+ if (is_editable) {
+ update_actions (row);
+ }
+
+ /* Signatures we do at another point, since we try to lazy-load them */
+}
+
+static void
+seahorse_pgp_uid_list_box_row_constructed (GObject *object)
+{
+ SeahorsePgpUidListBoxRow *row = SEAHORSE_PGP_UID_LIST_BOX_ROW (object);
+
+ G_OBJECT_CLASS (seahorse_pgp_uid_list_box_row_parent_class)->constructed (object);
+
+ update_row (row);
+}
+
+static void
+seahorse_pgp_uid_list_box_row_init (SeahorsePgpUidListBoxRow *row)
+{
+ gtk_widget_init_template (GTK_WIDGET (row));
+
+ row->actions = g_simple_action_group_new ();
+ g_action_map_add_action_entries (G_ACTION_MAP (row->actions),
+ UID_ACTION_ENTRIES,
+ G_N_ELEMENTS (UID_ACTION_ENTRIES),
+ row);
+
+ gtk_widget_insert_action_group (GTK_WIDGET (row),
+ "uid",
+ G_ACTION_GROUP (row->actions));
+
+ g_signal_connect (row, "notify::expanded", G_CALLBACK (on_row_expanded), NULL);
+}
+
+static void
+seahorse_pgp_uid_list_box_row_finalize (GObject *object)
+{
+ SeahorsePgpUidListBoxRow *row = SEAHORSE_PGP_UID_LIST_BOX_ROW (object);
+
+ g_clear_object (&row->uid);
+ g_clear_pointer (&row->discovered_keys, g_list_free);
+
+ G_OBJECT_CLASS (seahorse_pgp_uid_list_box_row_parent_class)->finalize (object);
+}
+
+static void
+seahorse_pgp_uid_list_box_row_get_property (GObject *object,
+ unsigned int prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ SeahorsePgpUidListBoxRow *row = SEAHORSE_PGP_UID_LIST_BOX_ROW (object);
+
+ switch (prop_id) {
+ case ROW_PROP_UID:
+ g_value_set_object (value, row->uid);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+seahorse_pgp_uid_list_box_row_set_property (GObject *object,
+ unsigned int prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ SeahorsePgpUidListBoxRow *row = SEAHORSE_PGP_UID_LIST_BOX_ROW (object);
+
+ switch (prop_id) {
+ case ROW_PROP_UID:
+ row->uid = g_value_dup_object (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+seahorse_pgp_uid_list_box_row_class_init (SeahorsePgpUidListBoxRowClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+ gobject_class->constructed = seahorse_pgp_uid_list_box_row_constructed;
+ gobject_class->finalize = seahorse_pgp_uid_list_box_row_finalize;
+ gobject_class->set_property = seahorse_pgp_uid_list_box_row_set_property;
+ gobject_class->get_property = seahorse_pgp_uid_list_box_row_get_property;
+
+ g_object_class_install_property (gobject_class, ROW_PROP_UID,
+ g_param_spec_object ("uid", "PGP uid", "The UID this row is showing",
+ SEAHORSE_PGP_TYPE_UID,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT));
+
+ gtk_widget_class_set_template_from_resource (widget_class,
"/org/gnome/Seahorse/seahorse-pgp-uid-list-box-row.ui");
+
+ gtk_widget_class_bind_template_child (widget_class, SeahorsePgpUidListBoxRow, actions_button);
+ gtk_widget_class_bind_template_child (widget_class, SeahorsePgpUidListBoxRow, signatures_list);
+}
diff --git a/pgp/seahorse-pgp-uid-list-box.h b/pgp/seahorse-pgp-uid-list-box.h
new file mode 100644
index 00000000..9079ad4b
--- /dev/null
+++ b/pgp/seahorse-pgp-uid-list-box.h
@@ -0,0 +1,36 @@
+/*
+ * 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 <gtk/gtk.h>
+
+#include "seahorse-pgp-uid.h"
+
+#define SEAHORSE_PGP_TYPE_UID_LIST_BOX (seahorse_pgp_uid_list_box_get_type ())
+G_DECLARE_FINAL_TYPE (SeahorsePgpUidListBox, seahorse_pgp_uid_list_box,
+ SEAHORSE_PGP, UID_LIST_BOX,
+ GtkListBox)
+
+#define SEAHORSE_PGP_TYPE_UID_LIST_BOX_ROW (seahorse_pgp_uid_list_box_row_get_type ())
+G_DECLARE_FINAL_TYPE (SeahorsePgpUidListBoxRow, seahorse_pgp_uid_list_box_row,
+ SEAHORSE_PGP, UID_LIST_BOX_ROW,
+ HdyExpanderRow)
+
+GtkWidget * seahorse_pgp_uid_list_box_new (SeahorsePgpKey *key);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]