[seahorse/pgp-key-listmodels] pgp: Expose a key's fields using GListModel




commit 00321de825cf406629c251f2148a8596667820e2
Author: Niels De Graef <nielsdegraef gmail com>
Date:   Sat Feb 20 16:40:38 2021 +0100

    pgp: Expose a key's fields using GListModel
    
    The current API mostly used `GList` (which is a linked list). This
    worked well enough for most use cases, but becomes a bit cumbersome to
    use with modern GTK APIs, which favor the adaptive `GListModel`. As
    such, this commit now exposes the keys, subkeys and UIDs of a PGP key
    using a `GListModel` instead of a `GList`.
    
    This also required some internal changes for the `SeahorseGpgmeKey`
    subclass, which kept a separate copy of UIDs (and had a lot of back and
    forth of vfunc calling between itself and its parent class). The new
    class is much simpler and doesn't seem to give any regressions.

 pgp/seahorse-gpgme-key-op.c       |  54 +++--
 pgp/seahorse-gpgme-key.c          | 210 +++++++----------
 pgp/seahorse-hkp-source.c         |  78 ++----
 pgp/seahorse-ldap-source.c        |  14 +-
 pgp/seahorse-pgp-key-properties.c | 187 +++++++++------
 pgp/seahorse-pgp-key.c            | 482 +++++++++++++++++++-------------------
 pgp/seahorse-pgp-key.h            |  40 ++--
 pgp/seahorse-pgp-types.h          |  36 +++
 pgp/seahorse-pgp-uid.h            |   2 +-
 9 files changed, 553 insertions(+), 550 deletions(-)
---
diff --git a/pgp/seahorse-gpgme-key-op.c b/pgp/seahorse-gpgme-key-op.c
index 1d3df151..276f6851 100644
--- a/pgp/seahorse-gpgme-key-op.c
+++ b/pgp/seahorse-gpgme-key-op.c
@@ -2337,15 +2337,12 @@ gpgme_error_t
 seahorse_gpgme_key_op_photos_load (SeahorseGpgmeKey *pkey)
 {
        /* Make sure there's enough room for the .jpg extension */
-       gchar image_path[]    = "/tmp/seahorse-photoid-XXXXXX\0\0\0\0";
-    
-       SeahorseEditParm *parms;
+    char image_path[]    = "/tmp/seahorse-photoid-XXXXXX\0\0\0\0";
+
        PhotoIdLoadParm photoid_load_parm;
        gpgme_error_t gerr;
        gpgme_key_t key;
-       const gchar *oldpath;
        const gchar *keyid;
-       gchar *path;
        gint fd;
 
        g_return_val_if_fail (SEAHORSE_GPGME_IS_KEY (pkey), GPG_E (GPG_ERR_WRONG_KEY_USAGE));
@@ -2377,27 +2374,32 @@ seahorse_gpgme_key_op_photos_load (SeahorseGpgmeKey *pkey)
                gerr = seahorse_gpg_op_num_uids (NULL, keyid, &(photoid_load_parm.num_uids));
                g_debug ("PhotoIDLoad Number of UIDs %i", photoid_load_parm.num_uids);
 
-               if (GPG_IS_OK (gerr)) {
-            
-                       setenv ("SEAHORSE_IMAGE_FILE", image_path, 1);
-                       oldpath = getenv("PATH");
-            
-                       path = g_strdup_printf ("%s:%s", EXECDIR, getenv ("PATH"));
-                       setenv ("PATH", path, 1);
-                       g_free (path);
-            
-                       parms = seahorse_edit_parm_new (PHOTO_ID_LOAD_START, photoid_load_action,
-                                                       photoid_load_transit, &photoid_load_parm);
-            
-                       /* generate list */
-                       gerr = edit_gpgme_key (NULL, key, parms);
-                       setenv ("PATH", oldpath, 1);
-
-                       if (GPG_IS_OK (gerr))
-                               seahorse_pgp_key_set_photos (SEAHORSE_PGP_KEY (pkey), 
photoid_load_parm.photos);
-               }
-               
-               seahorse_object_list_free (photoid_load_parm.photos);
+        if (GPG_IS_OK (gerr)) {
+            const char *oldpath;
+            g_autofree char *path = NULL;
+            SeahorseEditParm *parms;
+
+            setenv ("SEAHORSE_IMAGE_FILE", image_path, 1);
+            oldpath = getenv("PATH");
+
+            path = g_strdup_printf ("%s:%s", EXECDIR, oldpath);
+            setenv ("PATH", path, 1);
+
+            parms = seahorse_edit_parm_new (PHOTO_ID_LOAD_START, photoid_load_action,
+                                            photoid_load_transit, &photoid_load_parm);
+
+            /* generate list */
+            gerr = edit_gpgme_key (NULL, key, parms);
+            setenv ("PATH", oldpath, 1);
+
+            if (GPG_IS_OK (gerr)) {
+                for (GList *p = photoid_load_parm.photos; p; p = p->next) {
+                    seahorse_pgp_key_add_photo (SEAHORSE_PGP_KEY (pkey), p->data);
+                }
+            }
+        }
+
+        g_list_free_full (photoid_load_parm.photos, g_object_unref);
        }
 
        g_debug ("PhotoIDLoad Done");
diff --git a/pgp/seahorse-gpgme-key.c b/pgp/seahorse-gpgme-key.c
index 0fda7239..712d3196 100644
--- a/pgp/seahorse-gpgme-key.c
+++ b/pgp/seahorse-gpgme-key.c
@@ -32,7 +32,6 @@
 
 #include "seahorse-common.h"
 
-#include "libseahorse/seahorse-object-list.h"
 #include "libseahorse/seahorse-util.h"
 
 #include <glib/gi18n.h>
@@ -50,16 +49,14 @@ enum {
 struct _SeahorseGpgmeKey {
     SeahorsePgpKey parent_instance;
 
-    gpgme_key_t pubkey;           /* The public key */
+    gpgme_key_t pubkey;          /* The public key */
     gpgme_key_t seckey;          /* The secret key */
-    gboolean has_secret;        /* Whether we have a secret key or not */
+    gboolean has_secret;         /* Whether we have a secret key or not */
 
-    GList *uids;            /* We keep a copy of the uids. */
+    int list_mode;               /* What to load our public key as */
+    gboolean photos_loaded;      /* Photos were loaded */
 
-    int list_mode;                  /* What to load our public key as */
-    gboolean photos_loaded;        /* Photos were loaded */
-
-    gint block_loading;            /* Loading is blocked while this flag is set */
+    int block_loading;           /* Loading is blocked while this flag is set */
 };
 
 static void       seahorse_gpgme_key_deletable_iface       (SeahorseDeletableIface *iface);
@@ -157,18 +154,6 @@ require_key_private (SeahorseGpgmeKey *self)
     return self->seckey != NULL;
 }
 
-static gboolean
-require_key_uids (SeahorseGpgmeKey *self)
-{
-    return require_key_public (self, GPGME_KEYLIST_MODE_LOCAL);
-}
-
-static gboolean
-require_key_subkeys (SeahorseGpgmeKey *self)
-{
-    return require_key_public (self, GPGME_KEYLIST_MODE_LOCAL);
-}
-
 static void
 load_key_photos (SeahorseGpgmeKey *self)
 {
@@ -184,20 +169,12 @@ load_key_photos (SeahorseGpgmeKey *self)
         self->photos_loaded = TRUE;
 }
 
-static gboolean
-require_key_photos (SeahorseGpgmeKey *self)
-{
-    if (!self->photos_loaded)
-        load_key_photos (self);
-    return self->photos_loaded;
-}
-
 static void
 renumber_actual_uids (SeahorseGpgmeKey *self)
 {
     GArray *index_map;
-    GList *photos, *uids, *l;
-    guint index, i;
+    GListModel *photos;
+    GListModel *uids;
 
     g_assert (SEAHORSE_GPGME_IS_KEY (self));
 
@@ -210,26 +187,32 @@ renumber_actual_uids (SeahorseGpgmeKey *self)
 
     ++self->block_loading;
     photos = seahorse_pgp_key_get_photos (SEAHORSE_PGP_KEY (self));
-    uids = self->uids;
+    uids = seahorse_pgp_key_get_uids (SEAHORSE_PGP_KEY (self));
     --self->block_loading;
 
     /* First we build a bitmap of where all the photo uid indexes are */
     index_map = g_array_new (FALSE, TRUE, sizeof (gboolean));
-    for (l = photos; l; l = g_list_next (l)) {
-        index = seahorse_gpgme_photo_get_index (l->data);
+    for (guint i = 0; i < g_list_model_get_n_items (photos); i++) {
+        g_autoptr(SeahorseGpgmePhoto) photo = g_list_model_get_item (photos, i);
+        guint index;
+
+        index = seahorse_gpgme_photo_get_index (photo);
         if (index >= index_map->len)
             g_array_set_size (index_map, index + 1);
         g_array_index (index_map, gboolean, index) = TRUE;
     }
 
     /* Now for each UID we add however many photo indexes are below the gpgme index */
-    for (l = uids; l; l = g_list_next (l)) {
-        index = seahorse_gpgme_uid_get_gpgme_index (l->data);
-        for (i = 0; i < index_map->len && i < index; ++i) {
-            if(g_array_index (index_map, gboolean, index))
+    for (guint i = 0; i < g_list_model_get_n_items (uids); i++) {
+        g_autoptr(SeahorseGpgmeUid) uid = g_list_model_get_item (uids, i);
+        guint index;
+
+        index = seahorse_gpgme_uid_get_gpgme_index (uid);
+        for (guint j = 0; j < index_map->len && j < index; ++j) {
+            if (g_array_index (index_map, gboolean, index))
                 ++index;
         }
-        seahorse_gpgme_uid_set_actual_index (l->data, index + 1);
+        seahorse_gpgme_uid_set_actual_index (uid, index + 1);
     }
 
     g_array_free (index_map, TRUE);
@@ -238,20 +221,20 @@ renumber_actual_uids (SeahorseGpgmeKey *self)
 static void
 realize_uids (SeahorseGpgmeKey *self)
 {
+    GListModel *uids;
+    guint n_uids;
     gpgme_user_id_t guid;
-    SeahorseGpgmeUid *uid;
-    GList *results = NULL;
+    g_autoptr(GPtrArray) results = NULL;
     gboolean changed = FALSE;
-    GList *uids;
 
-    uids = self->uids;
+    uids = seahorse_pgp_key_get_uids (SEAHORSE_PGP_KEY (self));
+    n_uids = g_list_model_get_n_items (uids);
     guid = self->pubkey ? self->pubkey->uids : NULL;
+    results = g_ptr_array_new_with_free_func (g_object_unref);
 
     /* Look for out of sync or missing UIDs */
-    while (uids != NULL) {
-        g_return_if_fail (SEAHORSE_GPGME_IS_UID (uids->data));
-        uid = SEAHORSE_GPGME_UID (uids->data);
-        uids = g_list_next (uids);
+    for (guint i = 0; i < n_uids; i++) {
+        g_autoptr(SeahorseGpgmeUid) uid = g_list_model_get_item (uids, i);
 
         /* Bring this UID up to date */
         if (guid && seahorse_gpgme_uid_is_same (uid, guid)) {
@@ -259,45 +242,55 @@ realize_uids (SeahorseGpgmeKey *self)
                 g_object_set (uid, "pubkey", self->pubkey, "userid", guid, NULL);
                 changed = TRUE;
             }
-            results = seahorse_object_list_append (results, uid);
+            g_ptr_array_add (results, g_steal_pointer (&uid));
             guid = guid->next;
         }
     }
 
     /* Add new UIDs */
     while (guid != NULL) {
-        uid = seahorse_gpgme_uid_new (self, guid);
+        g_autoptr(SeahorseGpgmeUid) uid = seahorse_gpgme_uid_new (self, guid);
         changed = TRUE;
-        results = seahorse_object_list_append (results, uid);
-        g_object_unref (uid);
+        g_ptr_array_add (results, g_steal_pointer (&uid));
         guid = guid->next;
     }
 
-    if (changed)
-        seahorse_pgp_key_set_uids (SEAHORSE_PGP_KEY (self), results);
-    seahorse_object_list_free (results);
+    if (!changed)
+        return;
+
+    /* Don't use remove_uid() and add_uid(), or we can get into an inconsistent
+     * state where we have no UIDs at all, but do it atomically by splicing */
+    /* FIXME: we should do this cleanly, without casting to GListStore */
+    g_list_store_splice (G_LIST_STORE (uids), 0, n_uids, results->pdata, results->len);
 }
 
 static void
 realize_subkeys (SeahorseGpgmeKey *self)
 {
+    g_autoptr(GPtrArray) results = NULL;
+    GListModel *subkeys;
+    guint n_subkeys;
     gpgme_subkey_t gsubkey;
-    SeahorseGpgmeSubkey *subkey;
-    GList *list = NULL;
 
-    if (self->pubkey) {
+    results = g_ptr_array_new_with_free_func (g_object_unref);
+    subkeys = seahorse_pgp_key_get_subkeys (SEAHORSE_PGP_KEY (self));
+    n_subkeys = g_list_model_get_n_items (subkeys);
 
+    if (self->pubkey) {
         for (gsubkey = self->pubkey->subkeys; gsubkey; gsubkey = gsubkey->next) {
+            g_autoptr(SeahorseGpgmeSubkey) subkey = NULL;
+
             subkey = seahorse_gpgme_subkey_new (self->pubkey, gsubkey);
-            list = seahorse_object_list_prepend (list, subkey);
-            g_object_unref (subkey);
+            g_ptr_array_add (results, g_steal_pointer (&subkey));
         }
-
-        list = g_list_reverse (list);
     }
 
-    seahorse_pgp_key_set_subkeys (SEAHORSE_PGP_KEY (self), list);
-    seahorse_object_list_free (list);
+    /* Don't use remove/add_subkey(), or we can get into an inconsistent state
+     * where we have no subkeys at all, but do it atomically by splicing */
+    /* FIXME: we should do this cleanly, without casting to GListStore */
+    g_list_store_splice (G_LIST_STORE (subkeys),
+                         0, n_subkeys,
+                         results->pdata, results->len);
 }
 
 void
@@ -379,53 +372,6 @@ seahorse_gpgme_key_refresh (SeahorseGpgmeKey *self)
         load_key_photos (self);
 }
 
-static GList*
-seahorse_gpgme_key_get_uids (SeahorsePgpKey *base)
-{
-    SeahorseGpgmeKey *self = SEAHORSE_GPGME_KEY (base);
-    require_key_uids (self);
-    return SEAHORSE_PGP_KEY_CLASS (seahorse_gpgme_key_parent_class)->get_uids (base);
-}
-
-static void
-seahorse_gpgme_key_set_uids (SeahorsePgpKey *base, GList *uids)
-{
-    SeahorseGpgmeKey *self = SEAHORSE_GPGME_KEY (base);
-
-    SEAHORSE_PGP_KEY_CLASS (seahorse_gpgme_key_parent_class)->set_uids (base, uids);
-
-    /* Keep our own copy of the UID list */
-    seahorse_object_list_free (self->uids);
-    self->uids = seahorse_object_list_copy (uids);
-
-    renumber_actual_uids (self);
-}
-
-static GList*
-seahorse_gpgme_key_get_subkeys (SeahorsePgpKey *base)
-{
-    SeahorseGpgmeKey *self = SEAHORSE_GPGME_KEY (base);
-    require_key_subkeys (self);
-    return SEAHORSE_PGP_KEY_CLASS (seahorse_gpgme_key_parent_class)->get_subkeys (base);
-}
-
-static GList*
-seahorse_gpgme_key_get_photos (SeahorsePgpKey *base)
-{
-    SeahorseGpgmeKey *self = SEAHORSE_GPGME_KEY (base);
-    require_key_photos (self);
-    return SEAHORSE_PGP_KEY_CLASS (seahorse_gpgme_key_parent_class)->get_photos (base);
-}
-
-static void
-seahorse_gpgme_key_set_photos (SeahorsePgpKey *base, GList *photos)
-{
-    SeahorseGpgmeKey *self = SEAHORSE_GPGME_KEY (base);
-    self->photos_loaded = TRUE;
-    SEAHORSE_PGP_KEY_CLASS (seahorse_gpgme_key_parent_class)->set_photos (base, photos);
-    renumber_actual_uids (self);
-}
-
 static SeahorseDeleter *
 seahorse_gpgme_key_create_deleter (SeahorseDeletable *deletable)
 {
@@ -589,19 +535,50 @@ seahorse_gpgme_key_init (SeahorseGpgmeKey *self)
 {
 }
 
+static void
+on_photos_changed (GListModel *list,
+                   guint       position,
+                   guint       removed,
+                   guint       added,
+                   gpointer    user_data)
+{
+    SeahorseGpgmeKey *self = SEAHORSE_GPGME_KEY (user_data);
+
+    renumber_actual_uids (self);
+}
+
+static void
+on_uids_changed (GListModel *list,
+                 guint       position,
+                 guint       removed,
+                 guint       added,
+                 gpointer    user_data)
+{
+    SeahorseGpgmeKey *self = SEAHORSE_GPGME_KEY (user_data);
+
+    renumber_actual_uids (self);
+}
+
 static void
 seahorse_gpgme_key_object_constructed (GObject *object)
 {
     SeahorseGpgmeKey *self = SEAHORSE_GPGME_KEY (object);
+    GListModel *uids;
+    GListModel *photos;
 
     G_OBJECT_CLASS (seahorse_gpgme_key_parent_class)->constructed (object);
 
+    uids = seahorse_pgp_key_get_uids (SEAHORSE_PGP_KEY (self));
+    g_signal_connect (uids, "items-changed", G_CALLBACK (on_uids_changed), self);
+    photos = seahorse_pgp_key_get_photos (SEAHORSE_PGP_KEY (self));
+    g_signal_connect (photos, "items-changed", G_CALLBACK (on_photos_changed), self);
+
     seahorse_gpgme_key_realize (self);
 }
 
 static void
 seahorse_gpgme_key_get_property (GObject *object, guint prop_id,
-                               GValue *value, GParamSpec *pspec)
+                                 GValue *value, GParamSpec *pspec)
 {
     SeahorseGpgmeKey *self = SEAHORSE_GPGME_KEY (object);
 
@@ -623,7 +600,7 @@ seahorse_gpgme_key_get_property (GObject *object, guint prop_id,
 
 static void
 seahorse_gpgme_key_set_property (GObject *object, guint prop_id, const GValue *value,
-                               GParamSpec *pspec)
+                                 GParamSpec *pspec)
 {
     SeahorseGpgmeKey *self = SEAHORSE_GPGME_KEY (object);
 
@@ -648,9 +625,6 @@ seahorse_gpgme_key_object_dispose (GObject *obj)
         gpgme_key_unref (self->seckey);
     self->pubkey = self->seckey = NULL;
 
-    seahorse_object_list_free (self->uids);
-    self->uids = NULL;
-
     G_OBJECT_CLASS (seahorse_gpgme_key_parent_class)->dispose (obj);
 }
 
@@ -661,7 +635,6 @@ seahorse_gpgme_key_object_finalize (GObject *obj)
 
     g_assert (self->pubkey == NULL);
     g_assert (self->seckey == NULL);
-    g_assert (self->uids == NULL);
 
     G_OBJECT_CLASS (seahorse_gpgme_key_parent_class)->finalize (G_OBJECT (self));
 }
@@ -670,7 +643,6 @@ static void
 seahorse_gpgme_key_class_init (SeahorseGpgmeKeyClass *klass)
 {
     GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
-    SeahorsePgpKeyClass *pgp_class = SEAHORSE_PGP_KEY_CLASS (klass);
 
     gobject_class->constructed = seahorse_gpgme_key_object_constructed;
     gobject_class->dispose = seahorse_gpgme_key_object_dispose;
@@ -678,12 +650,6 @@ seahorse_gpgme_key_class_init (SeahorseGpgmeKeyClass *klass)
     gobject_class->set_property = seahorse_gpgme_key_set_property;
     gobject_class->get_property = seahorse_gpgme_key_get_property;
 
-    pgp_class->get_uids = seahorse_gpgme_key_get_uids;
-    pgp_class->set_uids = seahorse_gpgme_key_set_uids;
-    pgp_class->get_subkeys = seahorse_gpgme_key_get_subkeys;
-    pgp_class->get_photos = seahorse_gpgme_key_get_photos;
-    pgp_class->set_photos = seahorse_gpgme_key_set_photos;
-
     g_object_class_install_property (gobject_class, PROP_PUBKEY,
         g_param_spec_boxed ("pubkey", "GPGME Public Key", "GPGME Public Key that this object represents",
                             SEAHORSE_GPGME_BOXED_KEY,
diff --git a/pgp/seahorse-hkp-source.c b/pgp/seahorse-hkp-source.c
index 4b8a85a2..85d4e98e 100644
--- a/pgp/seahorse-hkp-source.c
+++ b/pgp/seahorse-hkp-source.c
@@ -33,7 +33,6 @@
 
 #include "seahorse-common.h"
 
-#include "libseahorse/seahorse-object-list.h"
 #include "libseahorse/seahorse-progress.h"
 #include "libseahorse/seahorse-util.h"
 
@@ -237,11 +236,7 @@ parse_hkp_index (const char *response)
     g_auto(GStrv) lines = NULL;
     SeahorsePgpKey *key = NULL;
     GList *keys = NULL;
-    GList *subkeys = NULL;
-    GList *uids = NULL;
     SeahorseFlags flags;
-    gboolean has_uid = FALSE;
-    char *uid_string;
     guint key_total = 0, key_count = 0;
 
     lines = g_strsplit (response, "\n", 0);
@@ -270,28 +265,19 @@ parse_hkp_index (const char *response)
         /* start a new key */
         /* pub:<keyid>:<algo>:<keylen>:<creationdate>:<expirationdate>:<flags> */
         } else if (g_ascii_strncasecmp (columns[0], "pub", 3) == 0) {
-            gchar *fingerprint, *fpr = NULL;
-            const gchar *algo;
-            SeahorsePgpSubkey *subkey;
-            glong created = 0, expired = 0;
+            const char *fpr;
+            g_autofree char *fingerprint = NULL;
+            const char *algo;
+            g_autoptr (SeahorsePgpSubkey) subkey = NULL;
+            long created = 0, expired = 0;
 
             key_count++;
 
             /* reset previous key */
             if (key) {
                 g_debug ("HKP Parse: previous key found");
-                if(has_uid) {
-                  seahorse_pgp_key_set_uids (SEAHORSE_PGP_KEY (key), uids);
-                  g_list_free_full (uids, g_object_unref);
-                  seahorse_pgp_key_set_subkeys (SEAHORSE_PGP_KEY (key), subkeys);
-                  g_list_free_full (subkeys, g_object_unref);
-                  seahorse_pgp_key_realize (SEAHORSE_PGP_KEY (key));
-                  keys = g_list_prepend (keys, key);
-                } else {
-                  g_debug("HKP Parse: no uid found");
-                }
-                uids = subkeys = NULL;
-                has_uid = FALSE;
+                seahorse_pgp_key_realize (SEAHORSE_PGP_KEY (key));
+                keys = g_list_prepend (keys, key);
                 key = NULL;
             }
 
@@ -302,9 +288,8 @@ parse_hkp_index (const char *response)
 
             /* Cut the length and fingerprint */
             fpr = columns[1];
-            if (fpr == NULL) {
+            if (fpr == NULL)
                 g_message ("couldn't find key fingerprint in line from server: %s", line);
-            }
 
             /* Check out the key type */
             switch (strtol(columns[2], NULL, 10)) {
@@ -319,19 +304,19 @@ parse_hkp_index (const char *response)
                 default:
                    break;
             }
-            g_debug("Algo: %s", algo);
+            g_debug ("Algo: %s", algo);
 
             /* set dates */
             /* created */
-            if (!columns[4]){
-                g_debug("HKP Parse: No created date for key on line: %s", line);
+            if (!columns[4]) {
+                g_debug ("HKP Parse: No created date for key on line: %s", line);
             } else {
-                created = strtol(columns[4], NULL, 10);
+                created = strtol (columns[4], NULL, 10);
             }
 
             /* expires (optional) */
-            if (columns[5]){
-                expired = strtol(columns[5], NULL, 10);
+            if (columns[5]) {
+                expired = strtol (columns[5], NULL, 10);
             }
 
             /* set flags (optional) */
@@ -351,28 +336,25 @@ parse_hkp_index (const char *response)
 
             fingerprint = seahorse_pgp_subkey_calc_fingerprint (fpr);
             seahorse_pgp_subkey_set_fingerprint (subkey, fingerprint);
-            g_free (fingerprint);
 
             seahorse_pgp_subkey_set_flags (subkey, flags);
-
             seahorse_pgp_subkey_set_created (subkey, created);
             seahorse_pgp_subkey_set_expires (subkey, expired);
             seahorse_pgp_subkey_set_length (subkey, strtol (columns[3], NULL, 10));
             seahorse_pgp_subkey_set_algorithm (subkey, algo);
-            subkeys = g_list_prepend (subkeys, subkey);
+            seahorse_pgp_key_add_subkey (key, subkey);
 
         /* A UID for the key */
         } else if (g_ascii_strncasecmp (columns[0], "uid", 3) == 0) {
-            SeahorsePgpUid *uid;
+            g_autoptr (SeahorsePgpUid) uid = NULL;
+            g_autofree char *uid_string = NULL;
 
             if (!key) {
                 g_debug("HKP Parse: Warning: seen uid line before keyline, skipping");
-                g_strfreev(columns);
                 continue;
             }
 
             g_debug("HKP Parse: handle uid");
-            has_uid = TRUE;
 
             if (!columns[0] || !columns[1] || !columns[2]) {
                 g_message ("HKP Parse: Invalid uid line from server: %s", line);
@@ -383,32 +365,18 @@ parse_hkp_index (const char *response)
             g_debug("HKP Parse: decoded uid string: %s", uid_string);
 
             uid = seahorse_pgp_uid_new (key, uid_string);
-            uids = g_list_prepend (uids, uid);
+            seahorse_pgp_key_add_uid (key, uid);
         }
     }
 
-    /* handle last entry */
-    if (key) {
-        if (has_uid) {
-            seahorse_pgp_key_set_uids (SEAHORSE_PGP_KEY (key), uids);
-            g_list_free_full (uids, g_object_unref);
-            seahorse_pgp_key_set_subkeys (SEAHORSE_PGP_KEY (key), subkeys);
-            g_list_free_full (subkeys, g_object_unref);
-            seahorse_pgp_key_realize (SEAHORSE_PGP_KEY (key));
-            keys = g_list_prepend (keys, key);
-        } else {
-            g_debug("HKP Parse: No UID found.");
-        }
-        uids = subkeys = NULL;
-        has_uid = FALSE;
-        key = NULL;
-    }
+    /* Make sure the keys are realized */
+    for (GList *k = keys; k; k = g_list_next (k))
+        seahorse_pgp_key_realize (SEAHORSE_PGP_KEY (k->data));
 
     if (key_total != 0 && key_total != key_count) {
-        g_message("HKP Parse; Warning: Issue during HKP parsing, only %d keys were parsed out of %d", 
key_count, key_total);
-
+        g_message ("HKP Parse; Warning: Issue during HKP parsing, only %d keys were parsed out of %d", 
key_count, key_total);
     } else {
-        g_debug("HKP Parse: %d keys parsed successfully", key_count);
+        g_debug ("HKP Parse: %d keys parsed successfully", key_count);
     }
 
     return keys;
diff --git a/pgp/seahorse-ldap-source.c b/pgp/seahorse-ldap-source.c
index 4d198241..5ceaad63 100644
--- a/pgp/seahorse-ldap-source.c
+++ b/pgp/seahorse-ldap-source.c
@@ -34,7 +34,6 @@
 
 #include "seahorse-common.h"
 
-#include "libseahorse/seahorse-object-list.h"
 #include "libseahorse/seahorse-progress.h"
 #include "libseahorse/seahorse-util.h"
 
@@ -744,11 +743,10 @@ search_parse_key_from_ldap_entry (SeahorseLDAPSource *self,
     length = get_int_attribute (ldap, res, "pgpkeysize");
 
     if (fpr && uidstr) {
-        SeahorsePgpSubkey *subkey;
+        g_autoptr (SeahorsePgpSubkey) subkey = NULL;
         g_autoptr(SeahorsePgpKey) key = NULL;
         g_autofree char *fingerprint = NULL;
-        SeahorsePgpUid *uid;
-        GList *list;
+        g_autoptr(SeahorsePgpUid) uid = NULL;
         guint flags;
 
         /* Build up a subkey */
@@ -774,14 +772,10 @@ search_parse_key_from_ldap_entry (SeahorseLDAPSource *self,
         uid = seahorse_pgp_uid_new (key, uidstr);
         if (revoked)
             seahorse_pgp_uid_set_validity (uid, SEAHORSE_VALIDITY_REVOKED);
+        seahorse_pgp_key_add_uid (key, uid);
 
         /* Now build them into a key */
-        list = g_list_prepend (NULL, uid);
-        seahorse_pgp_key_set_uids (key, list);
-        seahorse_object_list_free (list);
-        list = g_list_prepend (NULL, subkey);
-        seahorse_pgp_key_set_subkeys (key, list);
-        seahorse_object_list_free (list);
+        seahorse_pgp_key_add_subkey (key, subkey);
         g_object_set (key,
                       "object-flags", flags,
                       "place", self,
diff --git a/pgp/seahorse-pgp-key-properties.c b/pgp/seahorse-pgp-key-properties.c
index d1e4820d..b4ae1a10 100644
--- a/pgp/seahorse-pgp-key-properties.c
+++ b/pgp/seahorse-pgp-key-properties.c
@@ -376,19 +376,19 @@ names_populate (SeahorsePgpKeyProperties *self, GtkTreeStore *store, SeahorsePgp
     GObject *object;
     GtkTreeIter uiditer, sigiter;
     GList *keys, *l;
-    GList *uids, *u;
+    GListModel *uids;
     GList *sigs, *s;
 
     /* Insert all the fun-ness */
     uids = seahorse_pgp_key_get_uids (pkey);
 
-    for (u = uids; u; u = g_list_next (u)) {
-        SeahorsePgpUid *uid;
+    for (guint i = 0; i < g_list_model_get_n_items (uids); i++) {
+        g_autoptr(SeahorsePgpUid) uid = NULL;
         g_autoptr(GIcon) icon = NULL;
         g_autoptr(GPtrArray) keyids = NULL;
         g_autoptr(GCancellable) cancellable = NULL;
 
-        uid = SEAHORSE_PGP_UID (u->data);
+        uid = g_list_model_get_item (uids, i);
         icon = g_themed_icon_new ("avatar-default-symbolic");
         gtk_tree_store_append (store, &uiditer, NULL);
         gtk_tree_store_set (store, &uiditer,
@@ -585,10 +585,14 @@ set_photoid_state (SeahorsePgpKeyProperties *self)
     SeahorsePgpPhoto *photo;
     gboolean is_gpgme;
     GdkPixbuf *pixbuf;
-    GList *photos;
+    GListModel *photos;
+    guint n_photos;
+    g_autoptr(SeahorsePgpPhoto) first_photo = NULL;
+    g_autoptr(SeahorsePgpPhoto) last_photo = NULL;
 
     etype = seahorse_object_get_usage (SEAHORSE_OBJECT (self->key));
     photos = seahorse_pgp_key_get_photos (self->key);
+    n_photos = g_list_model_get_n_items (photos);
 
     photo = g_object_get_data (G_OBJECT (self), "current-photoid");
     g_return_if_fail (!photo || SEAHORSE_PGP_IS_PHOTO (photo));
@@ -597,22 +601,22 @@ set_photoid_state (SeahorsePgpKeyProperties *self)
     if (etype == SEAHORSE_USAGE_PRIVATE_KEY) {
         gtk_widget_set_visible (self->owner_photo_add_button, is_gpgme);
         gtk_widget_set_visible (self->owner_photo_primary_button,
-                                is_gpgme && photos && photos->next);
+                                is_gpgme && n_photos> 1);
         gtk_widget_set_visible (self->owner_photo_delete_button,
                                 is_gpgme && photo);
     }
 
     /* Display both of these when there is more than one photo id */
-    gtk_widget_set_visible (self->owner_photo_previous_button,
-                            photos && photos->next);
-    gtk_widget_set_visible (self->owner_photo_next_button,
-                            photos && photos->next);
+    gtk_widget_set_visible (self->owner_photo_previous_button, n_photos > 1);
+    gtk_widget_set_visible (self->owner_photo_next_button, n_photos > 1);
 
     /* Change sensitivity if first/last photo id */
+    first_photo = g_list_model_get_item (photos, 0);
+    last_photo = g_list_model_get_item (photos, MAX (n_photos - 1, 0));
     set_action_enabled (self, "photos.previous",
-                        photo && photos && photo != g_list_first (photos)->data);
+                        photo && photo != first_photo);
     set_action_enabled (self, "photos.next",
-                        photo && photos && photo != g_list_last (photos)->data);
+                        photo && photo != last_photo);
 
     pixbuf = photo ? seahorse_pgp_photo_get_pixbuf (photo) : NULL;
     if (pixbuf)
@@ -622,33 +626,51 @@ set_photoid_state (SeahorsePgpKeyProperties *self)
 static void
 do_photo_id (SeahorsePgpKeyProperties *self)
 {
-    GList *photos;
+    GListModel *photos;
+    g_autoptr(SeahorsePgpPhoto) first_photo = NULL;
 
     photos = seahorse_pgp_key_get_photos (self->key);
-    if (!photos)
-        g_object_set_data (G_OBJECT (self), "current-photoid", NULL);
-    else
+    first_photo = g_list_model_get_item (photos, 0);
+    if (first_photo)
         g_object_set_data_full (G_OBJECT (self), "current-photoid",
-                                g_object_ref (photos->data), g_object_unref);
+                                g_steal_pointer (&first_photo), g_object_unref);
+    else
+        g_object_set_data (G_OBJECT (self), "current-photoid", NULL);
 
     set_photoid_state (self);
 }
 
+static guint
+find_photo_index (GListModel *photos, SeahorsePgpPhoto *photo)
+{
+    for (guint i = 0; i < g_list_model_get_n_items (photos); i++) {
+        g_autoptr(SeahorsePgpPhoto) foto = g_list_model_get_item (photos, i);
+
+        if (photo == foto)
+            return i;
+    }
+
+    g_return_val_if_reached (0);
+}
+
 static void
 on_photos_next (GSimpleAction *action, GVariant *param, gpointer user_data)
 {
     SeahorsePgpKeyProperties *self = SEAHORSE_PGP_KEY_PROPERTIES (user_data);
     SeahorsePgpPhoto *photo;
-    GList *photos;
+    GListModel *photos;
 
     photos = seahorse_pgp_key_get_photos (self->key);
     photo = g_object_get_data (G_OBJECT (self), "current-photoid");
     if (photo) {
-        g_return_if_fail (SEAHORSE_PGP_IS_PHOTO (photo));
-        photos = g_list_find (photos, photo);
-        if (photos && photos->next)
+        guint index;
+        g_autoptr(SeahorsePgpPhoto) next = NULL;
+
+        index = find_photo_index (photos, photo);
+        next = g_list_model_get_item (photos, index + 1);
+        if (next)
             g_object_set_data_full (G_OBJECT (self), "current-photoid",
-                                    g_object_ref (photos->next->data),
+                                    g_steal_pointer (&next),
                                     g_object_unref);
     }
 
@@ -660,17 +682,22 @@ on_photos_previous (GSimpleAction *action, GVariant *param, gpointer user_data)
 {
     SeahorsePgpKeyProperties *self = SEAHORSE_PGP_KEY_PROPERTIES (user_data);
     SeahorsePgpPhoto *photo;
-    GList *photos;
+    GListModel *photos;
 
     photos = seahorse_pgp_key_get_photos (self->key);
     photo = g_object_get_data (G_OBJECT (self), "current-photoid");
     if (photo) {
-        g_return_if_fail (SEAHORSE_PGP_IS_PHOTO (photo));
-        photos = g_list_find (photos, photo);
-        if (photos && photos->prev)
+        guint index;
+
+        index = find_photo_index (photos, photo);
+        if (index > 0) {
+            g_autoptr(SeahorsePgpPhoto) prev = NULL;
+
+            prev = g_list_model_get_item (photos, index - 1);
             g_object_set_data_full (G_OBJECT (self), "current-photoid",
-                                    g_object_ref (photos->prev->data),
+                                    g_steal_pointer (&prev),
                                     g_object_unref);
+        }
     }
 
     set_photoid_state (self);
@@ -763,8 +790,9 @@ do_owner (SeahorsePgpKeyProperties *self)
     GtkListStore *store;
     GtkTreeIter iter;
     guint flags;
-    const gchar *label;
-    GList *uids, *l;
+    const char *label;
+    GListModel *uids;
+    g_autoptr(SeahorsePgpUid) primary_uid = NULL;
 
     flags = seahorse_object_get_flags (SEAHORSE_OBJECT (self->key));
 
@@ -799,17 +827,15 @@ do_owner (SeahorsePgpKeyProperties *self)
 
     /* Hide or show the uids area */
     uids = seahorse_pgp_key_get_uids (self->key);
+    primary_uid = g_list_model_get_item (uids, 0);
     if (self->uids_area != NULL)
-        gtk_widget_set_visible (self->uids_area, uids != NULL);
-    if (uids != NULL) {
+        gtk_widget_set_visible (self->uids_area, primary_uid != NULL);
+    if (primary_uid != NULL) {
         g_autofree gchar *title = NULL;
         g_autofree gchar *email_escaped = NULL;
         g_autofree gchar *email_label = NULL;
-        SeahorsePgpUid *uid;
 
-        uid = SEAHORSE_PGP_UID (uids->data);
-
-        label = seahorse_pgp_uid_get_name (uid);
+        label = seahorse_pgp_uid_get_name (primary_uid);
         gtk_label_set_text (self->owner_name_label, label);
 
         if (seahorse_object_get_usage (SEAHORSE_OBJECT (self->key)) != SEAHORSE_USAGE_PRIVATE_KEY) {
@@ -821,14 +847,14 @@ do_owner (SeahorsePgpKeyProperties *self)
         }
         gtk_window_set_title (GTK_WINDOW (self), title);
 
-        label = seahorse_pgp_uid_get_email (uid);
+        label = seahorse_pgp_uid_get_email (primary_uid);
         if (label && *label) {
             email_escaped = g_markup_escape_text (label, -1);
             email_label = g_strdup_printf ("<a href=\"mailto:%s\";>%s</a>", label, email_escaped);
             gtk_label_set_markup (self->owner_email_label, email_label);
         }
 
-        label = seahorse_pgp_uid_get_comment (uid);
+        label = seahorse_pgp_uid_get_comment (primary_uid);
         gtk_label_set_text (self->owner_comment_label, label);
 
         label = seahorse_object_get_identifier (SEAHORSE_OBJECT (self->key));
@@ -860,15 +886,16 @@ do_owner (SeahorsePgpKeyProperties *self)
                                                          "markup", UID_MARKUP, NULL);
         }
 
-        for (l = uids; l; l = g_list_next (l)) {
-            const gchar *markup;
+        for (guint i = 0; i < g_list_model_get_n_items (uids); i++) {
+            g_autoptr(SeahorsePgpUid) uid = g_list_model_get_item (uids, i);
+            const char *markup;
             g_autoptr(GIcon) icon = NULL;
 
-            markup = seahorse_object_get_markup (l->data);
+            markup = seahorse_object_get_markup (SEAHORSE_OBJECT (uid));
             icon = g_themed_icon_new ("avatar-default-symbolic");
             gtk_list_store_append (store, &iter);
             gtk_list_store_set (store, &iter,
-                                UID_OBJECT, l->data,
+                                UID_OBJECT, uid,
                                 UID_ICON, icon,
                                 UID_MARKUP, markup, -1);
         }
@@ -1031,15 +1058,17 @@ static void
 on_subkeys_change_expires (GSimpleAction *action, GVariant *param, gpointer user_data)
 {
     SeahorsePgpKeyProperties *self = SEAHORSE_PGP_KEY_PROPERTIES (user_data);
-    SeahorsePgpSubkey *subkey;
-    GList *subkeys;
+    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);
-        if (subkeys)
-            subkey = subkeys->data;
+        subkey = g_list_model_get_item (subkeys, 0);
+    } else {
+        g_object_ref (subkey);
     }
 
     g_return_if_fail (SEAHORSE_GPGME_IS_SUBKEY (subkey));
@@ -1132,14 +1161,17 @@ static void
 on_change_expires (GSimpleAction *action, GVariant *param, gpointer user_data)
 {
     SeahorsePgpKeyProperties *self = SEAHORSE_PGP_KEY_PROPERTIES (user_data);
-    GList *subkeys;
+    GListModel *subkeys;
+    g_autoptr(SeahorseGpgmeSubkey) subkey = NULL;
     GtkDialog *dialog;
 
     subkeys = seahorse_pgp_key_get_subkeys (self->key);
-    g_return_if_fail (subkeys);
+    g_return_if_fail (g_list_model_get_n_items (subkeys) > 0);
 
-    dialog = seahorse_gpgme_expires_dialog_new (SEAHORSE_GPGME_SUBKEY (subkeys->data),
-                                                GTK_WINDOW (self));
+    subkey = SEAHORSE_GPGME_SUBKEY (g_list_model_get_item (subkeys, 0));
+    g_return_if_fail (subkey);
+
+    dialog = seahorse_gpgme_expires_dialog_new (subkey, GTK_WINDOW (self));
     gtk_dialog_run (dialog);
     gtk_widget_destroy (GTK_WIDGET (dialog));
 }
@@ -1198,22 +1230,20 @@ setup_trust_combobox (SeahorsePgpKeyProperties *self)
 static void
 do_details (SeahorsePgpKeyProperties *self)
 {
-    SeahorsePgpSubkey *subkey;
     GtkListStore *store;
     GtkTreeModel *model;
     GtkTreeIter iter;
-    gchar dbuffer[G_ASCII_DTOSTR_BUF_SIZE];
-    g_autofree gchar *fp_label = NULL;
-    g_autofree gchar *created_str = NULL;
-    g_autofree gchar *expires_str = NULL;
-    const gchar *label;
-    gint trust;
-    GList *subkeys, *l;
+    char dbuffer[G_ASCII_DTOSTR_BUF_SIZE];
+    g_autofree char *fp_label = NULL;
+    g_autofree char *created_str = NULL;
+    g_autofree char *expires_str = NULL;
+    const char *label;
+    int trust;
+    GListModel *subkeys;
     gboolean valid;
 
     subkeys = seahorse_pgp_key_get_subkeys (self->key);
-    g_return_if_fail (subkeys && subkeys->data);
-    subkey = SEAHORSE_PGP_SUBKEY (subkeys->data);
+    g_return_if_fail (g_list_model_get_n_items (subkeys) > 0);
 
     label = seahorse_object_get_identifier (SEAHORSE_OBJECT (self->key));
     gtk_label_set_text (self->details_id_label, label);
@@ -1226,13 +1256,13 @@ do_details (SeahorsePgpKeyProperties *self)
     label = seahorse_pgp_key_get_algo (self->key);
     gtk_label_set_text (self->details_algo_label, label);
 
-    created_str = seahorse_util_get_display_date_string (seahorse_pgp_subkey_get_created (subkey));
+    created_str = seahorse_util_get_display_date_string (seahorse_pgp_key_get_created (self->key));
     gtk_label_set_text (self->details_created_label, created_str);
 
-    g_ascii_dtostr (dbuffer, G_ASCII_DTOSTR_BUF_SIZE, seahorse_pgp_subkey_get_length (subkey));
+    g_ascii_dtostr (dbuffer, G_ASCII_DTOSTR_BUF_SIZE, seahorse_pgp_key_get_length (self->key));
     gtk_label_set_text (self->details_strength_label, dbuffer);
 
-    gulong expires = seahorse_pgp_subkey_get_expires (subkey);
+    gulong expires = seahorse_pgp_key_get_length (self->key);
     if (!SEAHORSE_GPGME_IS_KEY (self->key))
         expires_str = NULL;
     else if (expires == 0)
@@ -1297,15 +1327,16 @@ do_details (SeahorsePgpKeyProperties *self)
                                                      "text", SUBKEY_LENGTH, NULL);
     }
 
-    for (l = subkeys; l; l = g_list_next (l)) {
-        const gchar *status = NULL;
-        g_autofree gchar *expiration_date = NULL;
-        g_autofree gchar *created_date = NULL;
-        g_autofree gchar *usage = 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;
         gulong expires;
         guint flags;
 
-        subkey = SEAHORSE_PGP_SUBKEY (l->data);
+        subkey = g_list_model_get_item (subkeys, i);
         expires = seahorse_pgp_subkey_get_expires (subkey);
         flags = seahorse_pgp_subkey_get_flags (subkey);
         status = "";
@@ -1424,8 +1455,9 @@ signatures_populate_model (SeahorsePgpKeyProperties *self, SeahorseObjectModel *
     GtkTreeIter iter;
     gboolean have_sigs = FALSE;
     g_autoptr(GPtrArray) rawids = NULL;
-    GList *keys, *l, *uids;
+    GListModel *uids;
     GList *sigs, *s;
+    GList *keys, *l;
 
     if (self->signatures_tree == NULL)
         return;
@@ -1434,8 +1466,9 @@ signatures_populate_model (SeahorsePgpKeyProperties *self, SeahorseObjectModel *
     uids = seahorse_pgp_key_get_uids (self->key);
 
     /* Build a list of all the keyids */
-    for (l = uids; l; l = g_list_next (l)) {
-        sigs = seahorse_pgp_uid_get_signatures (l->data);
+    for (guint i = 0; i < g_list_model_get_n_items (uids); i++) {
+        g_autoptr(SeahorsePgpUid) uid = g_list_model_get_item (uids, i);
+        sigs = seahorse_pgp_uid_get_signatures (uid);
         for (s = sigs; s; s = g_list_next (s)) {
             /* Never show self signatures, they're implied */
             if (seahorse_pgp_key_has_keyid (self->key,
@@ -1511,13 +1544,15 @@ trust_filter (GtkTreeModel *model, GtkTreeIter *iter, gpointer userdata)
 static gboolean
 key_have_signatures (SeahorsePgpKey *pkey, guint types)
 {
-    GList *uids, *u;
-    GList *sigs, *s;
+    GListModel *uids;
 
     uids = seahorse_pgp_key_get_uids (pkey);
-    for (u = uids; u; u = g_list_next (u)) {
-        sigs = seahorse_pgp_uid_get_signatures (u->data);
-        for (s = sigs; s; s = g_list_next (s)) {
+    for (guint i = 0; i < g_list_model_get_n_items (uids); i++) {
+        g_autoptr(SeahorsePgpUid) uid = g_list_model_get_item (uids, i);
+        GList *sigs;
+
+        sigs = seahorse_pgp_uid_get_signatures (uid);
+        for (GList *s = sigs; s; s = g_list_next (s)) {
             if (seahorse_pgp_signature_get_sigtype (s->data) & types)
                 return TRUE;
         }
diff --git a/pgp/seahorse-pgp-key.c b/pgp/seahorse-pgp-key.c
index 4767f420..463d16c4 100644
--- a/pgp/seahorse-pgp-key.c
+++ b/pgp/seahorse-pgp-key.c
@@ -20,6 +20,7 @@
 
 #include "seahorse-pgp-dialogs.h"
 #include "seahorse-pgp-key.h"
+#include "seahorse-pgp-photo.h"
 #include "seahorse-pgp-uid.h"
 #include "seahorse-pgp-subkey.h"
 
@@ -52,9 +53,9 @@ static void        seahorse_pgp_key_viewable_iface          (SeahorseViewableIfa
 
 typedef struct _SeahorsePgpKeyPrivate {
     char *keyid;
-    GList *uids;            /* All the UID objects */
-    GList *subkeys;         /* All the Subkey objects */
-    GList *photos;          /* List of photos */
+    GListModel *uids;            /* All the UID objects */
+    GListModel *subkeys;         /* All the Subkey objects */
+    GListModel *photos;          /* List of photos */
 } SeahorsePgpKeyPrivate;
 
 G_DEFINE_TYPE_WITH_CODE (SeahorsePgpKey, seahorse_pgp_key, SEAHORSE_TYPE_OBJECT,
@@ -97,31 +98,43 @@ seahorse_pgp_keyid_equal (gconstpointer v1,
 static const char*
 calc_short_name (SeahorsePgpKey *self)
 {
-    GList *uids = seahorse_pgp_key_get_uids (self);
-    return uids ? seahorse_pgp_uid_get_name (uids->data) : NULL;
+    SeahorsePgpKeyPrivate *priv = seahorse_pgp_key_get_instance_private (self);
+    g_autoptr(SeahorsePgpUid) uid = g_list_model_get_item (priv->uids, 0);
+
+    return uid ? seahorse_pgp_uid_get_name (uid) : NULL;
 }
 
 static char*
 calc_name (SeahorsePgpKey *self)
 {
-    GList *uids = seahorse_pgp_key_get_uids (self);
-    return uids ? seahorse_pgp_uid_calc_label (seahorse_pgp_uid_get_name (uids->data),
-                                               seahorse_pgp_uid_get_email (uids->data),
-                                               seahorse_pgp_uid_get_comment (uids->data)) : g_strdup ("");
+    SeahorsePgpKeyPrivate *priv = seahorse_pgp_key_get_instance_private (self);
+    g_autoptr(SeahorsePgpUid) uid = g_list_model_get_item (priv->uids, 0);
+
+    if (!uid)
+        return g_strdup ("");
+
+    return seahorse_pgp_uid_calc_label (seahorse_pgp_uid_get_name (uid),
+                                        seahorse_pgp_uid_get_email (uid),
+                                        seahorse_pgp_uid_get_comment (uid));
 }
 
 static char *
 calc_markup (SeahorsePgpKey *self)
 {
+    SeahorsePgpKeyPrivate *priv = seahorse_pgp_key_get_instance_private (self);
     guint flags = seahorse_object_get_flags (SEAHORSE_OBJECT (self));
-    GList *uids;
     GString *result;
+    g_autoptr(SeahorsePgpUid) uid = NULL;
     const char *name;
+    g_autofree char *name_escaped = NULL;
     const char *email;
     const char *comment;
+    g_autofree char *email_comment = NULL;
     const char *primary = NULL;
+    guint n_uids;
 
-    uids = seahorse_pgp_key_get_uids (self);
+    uid = g_list_model_get_item (priv->uids, 0);
+    n_uids = g_list_model_get_n_items (priv->uids);
 
     result = g_string_new ("<span");
     if (flags & SEAHORSE_FLAG_EXPIRED || flags & SEAHORSE_FLAG_REVOKED ||
@@ -131,45 +144,43 @@ calc_markup (SeahorsePgpKey *self)
         g_string_append (result, "  foreground='#555555'");
     g_string_append_c (result, '>');
 
-    /* The first name is the key name */
-    if (uids != NULL) {
-        g_autofree char *text = NULL;
+    if (!uid)
+        goto done;
 
-        name = seahorse_pgp_uid_get_name (uids->data);
-        text = g_markup_escape_text (name, -1);
-        g_string_append (result, text);
-        primary = name;
-    }
+    /* The first name is the key name */
+    name = seahorse_pgp_uid_get_name (uid);
+    name_escaped = g_markup_escape_text (name, -1);
+    g_string_append (result, name_escaped);
+    primary = name;
 
     g_string_append (result, "<span size='small' rise='0'>");
-    if (uids != NULL) {
-        g_autofree char *text = NULL;
 
-        email = seahorse_pgp_uid_get_email (uids->data);
-        if (email && !email[0])
-            email = NULL;
-        comment = seahorse_pgp_uid_get_comment (uids->data);
-        if (comment && !comment[0])
-            comment = NULL;
-        text = g_markup_printf_escaped ("\n%s%s%s%s%s",
-                                        email ? email : "",
-                                        email ? " " : "",
-                                        comment ? "'" : "",
-                                        comment ? comment : "",
-                                        comment ? "'" : "");
-        g_string_append (result, text);
-        uids = uids->next;
-    }
-
-    for (guint i = 0; uids != NULL; i++, uids = g_list_next (uids)) {
+    email = seahorse_pgp_uid_get_email (uid);
+    if (email && !email[0])
+        email = NULL;
+    comment = seahorse_pgp_uid_get_comment (uid);
+    if (comment && !comment[0])
+        comment = NULL;
+    email_comment = g_markup_printf_escaped ("\n%s%s%s%s%s",
+                                             email ? email : "",
+                                             email ? " " : "",
+                                             comment ? "'" : "",
+                                             comment ? comment : "",
+                                             comment ? "'" : "");
+    g_string_append (result, email_comment);
+
+    /* Now add the other keys */
+    for (guint i = 1; i < n_uids; i++) {
+        g_autoptr(SeahorsePgpUid) uid = NULL;
         g_autofree char *text = NULL;
 
+        uid = g_list_model_get_item (priv->uids, i);
         g_string_append_c (result, '\n');
 
-        // If we already have more than 5 UIDs, ellipsze the list.
-        // Otherwise we get huge rows in the list of GPG keys
+        /* If we have 5 UIDs or more, ellipsze the list.
+         * Otherwise we get huge rows in the list of GPG keys */
         if (i == 4) {
-            int n_others = g_list_length (uids);
+            int n_others = n_uids - i;
             g_autofree char *others_str = NULL;
 
             g_string_append_printf (result,
@@ -181,15 +192,15 @@ calc_markup (SeahorsePgpKey *self)
             break;
         }
 
-        name = seahorse_pgp_uid_get_name (uids->data);
+        name = seahorse_pgp_uid_get_name (uid);
         if (name && !name[0])
             name = NULL;
         if (g_strcmp0 (name, primary) == 0)
             name = NULL;
-        email = seahorse_pgp_uid_get_email (uids->data);
+        email = seahorse_pgp_uid_get_email (uid);
         if (email && !email[0])
             email = NULL;
-        comment = seahorse_pgp_uid_get_comment (uids->data);
+        comment = seahorse_pgp_uid_get_comment (uid);
         if (comment && !comment[0])
             comment = NULL;
         text = g_markup_printf_escaped ("%s%s%s%s%s%s%s",
@@ -201,11 +212,10 @@ calc_markup (SeahorsePgpKey *self)
                                         comment ? comment : "",
                                         comment ? "'" : "");
         g_string_append (result, text);
-        uids = uids->next;
     }
 
+done:
     g_string_append (result, "</span></span>");
-
     return g_string_free (result, FALSE);
 }
 
@@ -213,105 +223,22 @@ calc_markup (SeahorsePgpKey *self)
  * OBJECT
  */
 
-static GList*
-_seahorse_pgp_key_get_uids (SeahorsePgpKey *self)
-{
-    SeahorsePgpKeyPrivate *priv = seahorse_pgp_key_get_instance_private (self);
-
-    g_return_val_if_fail (SEAHORSE_PGP_IS_KEY (self), NULL);
-    return priv->uids;
-}
-
-static void
-_seahorse_pgp_key_set_uids (SeahorsePgpKey *self, GList *uids)
-{
-    SeahorsePgpKeyPrivate *priv = seahorse_pgp_key_get_instance_private (self);
-
-    g_return_if_fail (SEAHORSE_PGP_IS_KEY (self));
-
-    seahorse_object_list_free (priv->uids);
-    priv->uids = seahorse_object_list_copy (uids);
-
-    g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_UIDS]);
-}
-
-static GList*
-_seahorse_pgp_key_get_subkeys (SeahorsePgpKey *self)
-{
-    SeahorsePgpKeyPrivate *priv = seahorse_pgp_key_get_instance_private (self);
-
-    g_return_val_if_fail (SEAHORSE_PGP_IS_KEY (self), NULL);
-    return priv->subkeys;
-}
-
-static void
-_seahorse_pgp_key_set_subkeys (SeahorsePgpKey *self, GList *subkeys)
-{
-    SeahorsePgpKeyPrivate *priv = seahorse_pgp_key_get_instance_private (self);
-    const char *keyid = NULL;
-
-    g_return_if_fail (SEAHORSE_PGP_IS_KEY (self));
-    g_return_if_fail (subkeys);
-
-    keyid = seahorse_pgp_subkey_get_keyid (subkeys->data);
-    g_return_if_fail (keyid);
-
-    /* The keyid can't change */
-    if (priv->keyid) {
-        if (g_strcmp0 (priv->keyid, keyid) != 0) {
-            g_warning ("The keyid of a SeahorsePgpKey changed by "
-                       "setting a different subkey on it: %s != %s",
-                       priv->keyid, keyid);
-            return;
-        }
-
-    } else {
-        priv->keyid = g_strdup (keyid);
-    }
-
-    seahorse_object_list_free (priv->subkeys);
-    priv->subkeys = seahorse_object_list_copy (subkeys);
-
-    g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_SUBKEYS]);
-}
-
-static GList*
-_seahorse_pgp_key_get_photos (SeahorsePgpKey *self)
-{
-    SeahorsePgpKeyPrivate *priv = seahorse_pgp_key_get_instance_private (self);
-
-    g_return_val_if_fail (SEAHORSE_PGP_IS_KEY (self), NULL);
-    return priv->photos;
-}
-
-static void
-_seahorse_pgp_key_set_photos (SeahorsePgpKey *self, GList *photos)
-{
-    SeahorsePgpKeyPrivate *priv = seahorse_pgp_key_get_instance_private (self);
-
-    g_return_if_fail (SEAHORSE_PGP_IS_KEY (self));
-
-    seahorse_object_list_free (priv->photos);
-    priv->photos = seahorse_object_list_copy (photos);
-
-    g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_PHOTOS]);
-}
-
 void
 seahorse_pgp_key_realize (SeahorsePgpKey *self)
 {
+    SeahorsePgpKeyPrivate *priv = seahorse_pgp_key_get_instance_private (self);
+    g_autoptr(SeahorsePgpSubkey) subkey = NULL;
     const char *nickname, *keyid;
     const char *icon_name;
     g_autofree char *name = NULL;
     g_autofree char *markup = NULL;
     const char *identifier;
     SeahorseUsage usage;
-    GList *subkeys;
     g_autoptr(GIcon) icon = NULL;
 
-    subkeys = seahorse_pgp_key_get_subkeys (self);
-    if (subkeys) {
-        keyid = seahorse_pgp_subkey_get_keyid (subkeys->data);
+    subkey = g_list_model_get_item (priv->subkeys, 0);
+    if (subkey) {
+        keyid = seahorse_pgp_subkey_get_keyid (subkey);
         identifier = seahorse_pgp_key_calc_identifier (keyid);
     } else {
         identifier = "";
@@ -374,69 +301,166 @@ seahorse_pgp_key_calc_identifier (const char *keyid)
     return keyid;
 }
 
-GList*
+GListModel *
 seahorse_pgp_key_get_uids (SeahorsePgpKey *self)
 {
+    SeahorsePgpKeyPrivate *priv = seahorse_pgp_key_get_instance_private (self);
+
     g_return_val_if_fail (SEAHORSE_PGP_IS_KEY (self), NULL);
-    if (!SEAHORSE_PGP_KEY_GET_CLASS (self)->get_uids)
-        return NULL;
-    return SEAHORSE_PGP_KEY_GET_CLASS (self)->get_uids (self);
+    return priv->uids;
 }
 
 void
-seahorse_pgp_key_set_uids (SeahorsePgpKey *self, GList *uids)
+seahorse_pgp_key_add_uid (SeahorsePgpKey *self,
+                          SeahorsePgpUid *uid)
 {
+    SeahorsePgpKeyPrivate *priv = seahorse_pgp_key_get_instance_private (self);
+
     g_return_if_fail (SEAHORSE_PGP_IS_KEY (self));
-    g_return_if_fail (SEAHORSE_PGP_KEY_GET_CLASS (self)->set_uids);
-    SEAHORSE_PGP_KEY_GET_CLASS (self)->set_uids (self, uids);
+
+    /* Don't try to add a key which already exists */
+    for (guint i = 0; i < g_list_model_get_n_items (priv->uids); i++) {
+        g_autoptr(SeahorsePgpUid) _uid = NULL;
+
+        _uid = g_list_model_get_item (priv->uids, i);
+        if (uid == _uid)
+            return;
+    }
+
+    g_list_store_append (G_LIST_STORE (priv->uids), uid);
 }
 
-GList*
+void
+seahorse_pgp_key_remove_uid (SeahorsePgpKey *self,
+                             SeahorsePgpUid *uid)
+{
+    SeahorsePgpKeyPrivate *priv = seahorse_pgp_key_get_instance_private (self);
+
+    g_return_if_fail (SEAHORSE_PGP_IS_KEY (self));
+
+    for (guint i = 0; i < g_list_model_get_n_items (priv->uids); i++) {
+        g_autoptr(SeahorsePgpUid) _uid = NULL;
+
+        _uid = g_list_model_get_item (priv->uids, i);
+        if (uid == _uid) {
+            if (g_list_model_get_n_items (priv->uids) == 1)
+                g_warning ("Removing last UID");
+
+            g_list_store_remove (G_LIST_STORE (priv->uids), i);
+            break;
+        }
+    }
+}
+
+GListModel *
 seahorse_pgp_key_get_subkeys (SeahorsePgpKey *self)
 {
+    SeahorsePgpKeyPrivate *priv = seahorse_pgp_key_get_instance_private (self);
+
     g_return_val_if_fail (SEAHORSE_PGP_IS_KEY (self), NULL);
-    if (!SEAHORSE_PGP_KEY_GET_CLASS (self)->get_subkeys)
-        return NULL;
-    return SEAHORSE_PGP_KEY_GET_CLASS (self)->get_subkeys (self);
+    return priv->subkeys;
 }
 
 void
-seahorse_pgp_key_set_subkeys (SeahorsePgpKey *self, GList *subkeys)
+seahorse_pgp_key_add_subkey (SeahorsePgpKey    *self,
+                             SeahorsePgpSubkey *subkey)
 {
+    SeahorsePgpKeyPrivate *priv = seahorse_pgp_key_get_instance_private (self);
+
     g_return_if_fail (SEAHORSE_PGP_IS_KEY (self));
-    g_return_if_fail (SEAHORSE_PGP_KEY_GET_CLASS (self)->set_subkeys);
-    SEAHORSE_PGP_KEY_GET_CLASS (self)->set_subkeys (self, subkeys);
+
+    /* Don't try to add a key which already exists */
+    for (guint i = 0; i < g_list_model_get_n_items (priv->subkeys); i++) {
+        g_autoptr(SeahorsePgpSubkey) _subkey = NULL;
+
+        _subkey = g_list_model_get_item (priv->subkeys, i);
+        if (subkey == _subkey)
+            return;
+    }
+
+    g_list_store_append (G_LIST_STORE (priv->subkeys), subkey);
 }
 
-GList*
+void
+seahorse_pgp_key_remove_subkey (SeahorsePgpKey    *self,
+                                SeahorsePgpSubkey *subkey)
+{
+    SeahorsePgpKeyPrivate *priv = seahorse_pgp_key_get_instance_private (self);
+
+    g_return_if_fail (SEAHORSE_PGP_IS_KEY (self));
+
+    for (guint i = 0; i < g_list_model_get_n_items (priv->subkeys); i++) {
+        g_autoptr(SeahorsePgpSubkey) _subkey = NULL;
+
+        _subkey = g_list_model_get_item (priv->subkeys, i);
+        if (subkey == _subkey) {
+            g_list_store_remove (G_LIST_STORE (priv->subkeys), i);
+            break;
+        }
+    }
+}
+
+GListModel *
 seahorse_pgp_key_get_photos (SeahorsePgpKey *self)
 {
+    SeahorsePgpKeyPrivate *priv = seahorse_pgp_key_get_instance_private (self);
+
     g_return_val_if_fail (SEAHORSE_PGP_IS_KEY (self), NULL);
-    if (!SEAHORSE_PGP_KEY_GET_CLASS (self)->get_photos)
-        return NULL;
-    return SEAHORSE_PGP_KEY_GET_CLASS (self)->get_photos (self);
+    return priv->photos;
 }
 
 void
-seahorse_pgp_key_set_photos (SeahorsePgpKey *self, GList *photos)
+seahorse_pgp_key_add_photo (SeahorsePgpKey   *self,
+                            SeahorsePgpPhoto *photo)
 {
+    SeahorsePgpKeyPrivate *priv = seahorse_pgp_key_get_instance_private (self);
+
     g_return_if_fail (SEAHORSE_PGP_IS_KEY (self));
-    g_return_if_fail (SEAHORSE_PGP_KEY_GET_CLASS (self)->set_photos);
-    SEAHORSE_PGP_KEY_GET_CLASS (self)->set_photos (self, photos);
+
+    /* Don't try to add a key which already exists */
+    for (guint i = 0; i < g_list_model_get_n_items (priv->photos); i++) {
+        g_autoptr(SeahorsePgpPhoto) _photo = NULL;
+
+        _photo = g_list_model_get_item (priv->photos, i);
+        if (photo == _photo)
+            return;
+    }
+
+    g_list_store_append (G_LIST_STORE (priv->photos), photo);
 }
 
-const char*
+void
+seahorse_pgp_key_remove_photo (SeahorsePgpKey   *self,
+                               SeahorsePgpPhoto *photo)
+{
+    SeahorsePgpKeyPrivate *priv = seahorse_pgp_key_get_instance_private (self);
+
+    g_return_if_fail (SEAHORSE_PGP_IS_KEY (self));
+
+    for (guint i = 0; i < g_list_model_get_n_items (priv->photos); i++) {
+        g_autoptr(SeahorsePgpPhoto) _photo = NULL;
+
+        _photo = g_list_model_get_item (priv->photos, i);
+        if (photo == _photo) {
+            if (g_list_model_get_n_items (priv->photos) == 1)
+                g_warning ("Removing last PHOTO");
+
+            g_list_store_remove (G_LIST_STORE (priv->photos), i);
+            break;
+        }
+    }
+}
+
+const char *
 seahorse_pgp_key_get_fingerprint (SeahorsePgpKey *self)
 {
-    GList *subkeys;
+    SeahorsePgpKeyPrivate *priv = seahorse_pgp_key_get_instance_private (self);
+    g_autoptr(SeahorsePgpSubkey) subkey = NULL;
 
     g_return_val_if_fail (SEAHORSE_PGP_IS_KEY (self), NULL);
 
-    subkeys = seahorse_pgp_key_get_subkeys (self);
-    if (!subkeys)
-        return "";
-
-    return seahorse_pgp_subkey_get_fingerprint (subkeys->data);
+    subkey = g_list_model_get_item (priv->subkeys, 0);
+    return subkey? seahorse_pgp_subkey_get_fingerprint (subkey) : "";
 }
 
 SeahorseValidity
@@ -450,15 +474,25 @@ seahorse_pgp_key_get_validity (SeahorsePgpKey *self)
 gulong
 seahorse_pgp_key_get_expires (SeahorsePgpKey *self)
 {
-    GList *subkeys;
+    SeahorsePgpKeyPrivate *priv = seahorse_pgp_key_get_instance_private (self);
+    g_autoptr(SeahorsePgpSubkey) subkey = NULL;
 
     g_return_val_if_fail (SEAHORSE_PGP_IS_KEY (self), 0);
 
-    subkeys = seahorse_pgp_key_get_subkeys (self);
-    if (!subkeys)
-        return 0;
+    subkey = g_list_model_get_item (priv->subkeys, 0);
+    return subkey? seahorse_pgp_subkey_get_expires (subkey) : 0;
+}
+
+gulong
+seahorse_pgp_key_get_created (SeahorsePgpKey *self)
+{
+    SeahorsePgpKeyPrivate *priv = seahorse_pgp_key_get_instance_private (self);
+    g_autoptr(SeahorsePgpSubkey) subkey = NULL;
+
+    g_return_val_if_fail (SEAHORSE_PGP_IS_KEY (self), 0);
 
-    return seahorse_pgp_subkey_get_expires (subkeys->data);
+    subkey = g_list_model_get_item (priv->subkeys, 0);
+    return subkey? seahorse_pgp_subkey_get_created (subkey) : 0;
 }
 
 SeahorseValidity
@@ -472,65 +506,56 @@ seahorse_pgp_key_get_trust (SeahorsePgpKey *self)
 guint
 seahorse_pgp_key_get_length (SeahorsePgpKey *self)
 {
-    GList *subkeys;
+    SeahorsePgpKeyPrivate *priv = seahorse_pgp_key_get_instance_private (self);
+    g_autoptr(SeahorsePgpSubkey) subkey = NULL;
 
     g_return_val_if_fail (SEAHORSE_PGP_IS_KEY (self), 0);
 
-    subkeys = seahorse_pgp_key_get_subkeys (self);
-    if (!subkeys)
-        return 0;
-
-    return seahorse_pgp_subkey_get_length (subkeys->data);
+    subkey = g_list_model_get_item (priv->subkeys, 0);
+    return subkey? seahorse_pgp_subkey_get_length (subkey) : 0;
 }
 
-const char*
+const char *
 seahorse_pgp_key_get_algo (SeahorsePgpKey *self)
 {
-    GList *subkeys;
-
-    g_return_val_if_fail (SEAHORSE_PGP_IS_KEY (self), 0);
+    SeahorsePgpKeyPrivate *priv = seahorse_pgp_key_get_instance_private (self);
+    g_autoptr(SeahorsePgpSubkey) subkey = NULL;
 
-    subkeys = seahorse_pgp_key_get_subkeys (self);
-    if (!subkeys)
-        return NULL;
+    g_return_val_if_fail (SEAHORSE_PGP_IS_KEY (self), NULL);
 
-    return seahorse_pgp_subkey_get_algorithm (subkeys->data);
+    subkey = g_list_model_get_item (priv->subkeys, 0);
+    return subkey? seahorse_pgp_subkey_get_algorithm (subkey) : NULL;
 }
 
-const char*
+const char *
 seahorse_pgp_key_get_keyid (SeahorsePgpKey *self)
 {
-    GList *subkeys;
-
-    g_return_val_if_fail (SEAHORSE_PGP_IS_KEY (self), 0);
+    SeahorsePgpKeyPrivate *priv = seahorse_pgp_key_get_instance_private (self);
+    g_autoptr(SeahorsePgpSubkey) subkey = NULL;
 
-    subkeys = seahorse_pgp_key_get_subkeys (self);
-    if (!subkeys)
-        return NULL;
+    g_return_val_if_fail (SEAHORSE_PGP_IS_KEY (self), NULL);
 
-    return seahorse_pgp_subkey_get_keyid (subkeys->data);
+    subkey = g_list_model_get_item (priv->subkeys, 0);
+    return subkey? seahorse_pgp_subkey_get_keyid (subkey) : NULL;
 }
 
 gboolean
 seahorse_pgp_key_has_keyid (SeahorsePgpKey *self, const char *match)
 {
-    GList *subkeys;
-    SeahorsePgpSubkey *subkey;
+    SeahorsePgpKeyPrivate *priv = seahorse_pgp_key_get_instance_private (self);
     guint n_match;
 
     g_return_val_if_fail (SEAHORSE_PGP_IS_KEY (self), FALSE);
     g_return_val_if_fail (match, FALSE);
 
-    subkeys = seahorse_pgp_key_get_subkeys (self);
-    if (!subkeys)
-        return FALSE;
-
     n_match = strlen (match);
 
-    for (GList *l = subkeys; l && (subkey = SEAHORSE_PGP_SUBKEY (l->data)); l = g_list_next (l)) {
+    for (guint i = 0; i < g_list_model_get_n_items (priv->subkeys); i++) {
+        g_autoptr(SeahorsePgpSubkey) subkey = NULL;
         const char *keyid;
         guint n_keyid;
 
+        subkey = g_list_model_get_item (priv->subkeys, i);
         keyid = seahorse_pgp_subkey_get_keyid (subkey);
         g_return_val_if_fail (keyid, FALSE);
         n_keyid = strlen (keyid);
@@ -547,6 +572,11 @@ seahorse_pgp_key_has_keyid (SeahorsePgpKey *self, const char *match)
 static void
 seahorse_pgp_key_init (SeahorsePgpKey *self)
 {
+    SeahorsePgpKeyPrivate *priv = seahorse_pgp_key_get_instance_private (self);
+
+    priv->uids = G_LIST_MODEL (g_list_store_new (SEAHORSE_PGP_TYPE_UID));
+    priv->subkeys = G_LIST_MODEL (g_list_store_new (SEAHORSE_PGP_TYPE_SUBKEY));
+    priv->photos = G_LIST_MODEL (g_list_store_new (SEAHORSE_PGP_TYPE_SUBKEY));
 }
 
 static void
@@ -558,13 +588,13 @@ seahorse_pgp_key_get_property (GObject *object, guint prop_id,
 
     switch (prop_id) {
     case PROP_PHOTOS:
-        g_value_set_boxed (value, seahorse_pgp_key_get_photos (self));
+        g_value_set_object (value, seahorse_pgp_key_get_photos (self));
         break;
     case PROP_SUBKEYS:
-        g_value_set_boxed (value, seahorse_pgp_key_get_subkeys (self));
+        g_value_set_object (value, seahorse_pgp_key_get_subkeys (self));
         break;
     case PROP_UIDS:
-        g_value_set_boxed (value, seahorse_pgp_key_get_uids (self));
+        g_value_set_object (value, seahorse_pgp_key_get_uids (self));
         break;
     case PROP_FINGERPRINT:
         g_value_set_string (value, seahorse_pgp_key_get_fingerprint (self));
@@ -594,34 +624,15 @@ seahorse_pgp_key_get_property (GObject *object, guint prop_id,
     }
 }
 
-static void
-seahorse_pgp_key_set_property (GObject *object, guint prop_id, const GValue *value,
-                               GParamSpec *pspec)
-{
-    SeahorsePgpKey *self = SEAHORSE_PGP_KEY (object);
-
-    switch (prop_id) {
-    case PROP_UIDS:
-        seahorse_pgp_key_set_uids (self, g_value_get_boxed (value));
-        break;
-    case PROP_SUBKEYS:
-        seahorse_pgp_key_set_subkeys (self, g_value_get_boxed (value));
-        break;
-    case PROP_PHOTOS:
-        seahorse_pgp_key_set_photos (self, g_value_get_boxed (value));
-        break;
-    }
-}
-
 static void
 seahorse_pgp_key_object_dispose (GObject *obj)
 {
     SeahorsePgpKey *self = SEAHORSE_PGP_KEY (obj);
     SeahorsePgpKeyPrivate *priv = seahorse_pgp_key_get_instance_private (self);
 
-    g_clear_pointer (&priv->uids, seahorse_object_list_free);
-    g_clear_pointer (&priv->photos, seahorse_object_list_free);
-    g_clear_pointer (&priv->subkeys, seahorse_object_list_free);
+    g_clear_object (&priv->uids);
+    g_clear_object (&priv->subkeys);
+    g_clear_object (&priv->photos);
 
     G_OBJECT_CLASS (seahorse_pgp_key_parent_class)->dispose (obj);
 }
@@ -633,9 +644,6 @@ seahorse_pgp_key_object_finalize (GObject *obj)
     SeahorsePgpKeyPrivate *priv = seahorse_pgp_key_get_instance_private (self);
 
     g_free (priv->keyid);
-    g_assert (priv->uids == NULL);
-    g_assert (priv->photos == NULL);
-    g_assert (priv->subkeys == NULL);
 
     G_OBJECT_CLASS (seahorse_pgp_key_parent_class)->finalize (obj);
 }
@@ -647,30 +655,22 @@ seahorse_pgp_key_class_init (SeahorsePgpKeyClass *klass)
 
     gobject_class->dispose = seahorse_pgp_key_object_dispose;
     gobject_class->finalize = seahorse_pgp_key_object_finalize;
-    gobject_class->set_property = seahorse_pgp_key_set_property;
     gobject_class->get_property = seahorse_pgp_key_get_property;
 
-    klass->get_uids = _seahorse_pgp_key_get_uids;
-    klass->set_uids = _seahorse_pgp_key_set_uids;
-    klass->get_subkeys = _seahorse_pgp_key_get_subkeys;
-    klass->set_subkeys = _seahorse_pgp_key_set_subkeys;
-    klass->get_photos = _seahorse_pgp_key_get_photos;
-    klass->set_photos = _seahorse_pgp_key_set_photos;
-
     obj_props[PROP_PHOTOS] =
-        g_param_spec_boxed ("photos", "Key Photos", "Photos for the key",
-                            SEAHORSE_BOXED_OBJECT_LIST,
-                            G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+        g_param_spec_object ("photos", "Key Photos", "Photos for the key",
+                             G_TYPE_LIST_MODEL,
+                             G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
 
     obj_props[PROP_SUBKEYS] =
-        g_param_spec_boxed ("subkeys", "PGP subkeys", "PGP subkeys",
-                            SEAHORSE_BOXED_OBJECT_LIST,
-                            G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+        g_param_spec_object ("subkeys", "PGP subkeys", "PGP subkeys",
+                             G_TYPE_LIST_MODEL,
+                             G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
 
     obj_props[PROP_UIDS] =
-        g_param_spec_boxed ("uids", "PGP User Ids", "PGP User Ids",
-                            SEAHORSE_BOXED_OBJECT_LIST,
-                            G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+        g_param_spec_object ("uids", "PGP User Ids", "PGP User Ids",
+                             G_TYPE_LIST_MODEL,
+                             G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
 
     obj_props[PROP_FINGERPRINT] =
         g_param_spec_string ("fingerprint", "Fingerprint", "Unique fingerprint for this key",
diff --git a/pgp/seahorse-pgp-key.h b/pgp/seahorse-pgp-key.h
index 179688ad..7b106972 100644
--- a/pgp/seahorse-pgp-key.h
+++ b/pgp/seahorse-pgp-key.h
@@ -22,6 +22,7 @@
 #include <glib-object.h>
 
 #include "seahorse-common.h"
+#include "seahorse-pgp-types.h"
 
 enum {
     SKEY_PGPSIG_TRUSTED = 0x0001,
@@ -33,36 +34,35 @@ G_DECLARE_DERIVABLE_TYPE (SeahorsePgpKey, seahorse_pgp_key, SEAHORSE_PGP, KEY, S
 
 struct _SeahorsePgpKeyClass {
     SeahorseObjectClass parent_class;
-
-    /* virtual methods */
-    GList* (*get_uids) (SeahorsePgpKey *self);
-    void   (*set_uids) (SeahorsePgpKey *self, GList *uids);
-
-    GList* (*get_subkeys) (SeahorsePgpKey *self);
-    void   (*set_subkeys) (SeahorsePgpKey *self, GList *uids);
-
-    GList* (*get_photos) (SeahorsePgpKey *self);
-    void   (*set_photos) (SeahorsePgpKey *self, GList *uids);
 };
 
 SeahorsePgpKey *  seahorse_pgp_key_new                  (void);
 
 void              seahorse_pgp_key_realize              (SeahorsePgpKey *self);
 
-GList*            seahorse_pgp_key_get_subkeys          (SeahorsePgpKey *self);
+GListModel *      seahorse_pgp_key_get_subkeys          (SeahorsePgpKey *self);
+
+void              seahorse_pgp_key_add_subkey           (SeahorsePgpKey    *self,
+                                                         SeahorsePgpSubkey *subkey);
 
-void              seahorse_pgp_key_set_subkeys          (SeahorsePgpKey *self,
-                                                         GList *subkeys);
+void              seahorse_pgp_key_remove_subkey        (SeahorsePgpKey    *self,
+                                                         SeahorsePgpSubkey *subkey);
 
-GList*            seahorse_pgp_key_get_uids             (SeahorsePgpKey *self);
+GListModel *      seahorse_pgp_key_get_uids             (SeahorsePgpKey *self);
 
-void              seahorse_pgp_key_set_uids             (SeahorsePgpKey *self,
-                                                         GList *subkeys);
+void              seahorse_pgp_key_add_uid              (SeahorsePgpKey *self,
+                                                         SeahorsePgpUid *uid);
 
-GList*            seahorse_pgp_key_get_photos           (SeahorsePgpKey *self);
+void              seahorse_pgp_key_remove_uid           (SeahorsePgpKey *self,
+                                                         SeahorsePgpUid *uid);
 
-void              seahorse_pgp_key_set_photos           (SeahorsePgpKey *self,
-                                                         GList *subkeys);
+GListModel *      seahorse_pgp_key_get_photos           (SeahorsePgpKey *self);
+
+void              seahorse_pgp_key_add_photo            (SeahorsePgpKey *self,
+                                                         SeahorsePgpPhoto *photo);
+
+void              seahorse_pgp_key_remove_photo         (SeahorsePgpKey *self,
+                                                         SeahorsePgpPhoto *photo);
 
 const char*       seahorse_pgp_key_get_fingerprint      (SeahorsePgpKey *self);
 
@@ -70,6 +70,8 @@ SeahorseValidity  seahorse_pgp_key_get_validity         (SeahorsePgpKey *self);
 
 gulong            seahorse_pgp_key_get_expires          (SeahorsePgpKey *self);
 
+gulong            seahorse_pgp_key_get_created          (SeahorsePgpKey *self);
+
 SeahorseValidity  seahorse_pgp_key_get_trust            (SeahorsePgpKey *self);
 
 guint             seahorse_pgp_key_get_length           (SeahorsePgpKey *self);
diff --git a/pgp/seahorse-pgp-types.h b/pgp/seahorse-pgp-types.h
new file mode 100644
index 00000000..a74042d9
--- /dev/null
+++ b/pgp/seahorse-pgp-types.h
@@ -0,0 +1,36 @@
+/*
+ * Seahorse
+ *
+ * Copyright (C) 2020 Niels De Graef <nielsdegraef gmail com>
+ *
+ * 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, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Author: Niels De Graef <nielsdegraef gmail com>
+ */
+
+#pragma once
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+/* Common forward declarations */
+typedef struct _SeahorsePgpKey SeahorsePgpKey;
+typedef struct _SeahorsePgpSubkey SeahorsePgpSubkey;
+typedef struct _SeahorsePgpUid SeahorsePgpUid;
+typedef struct _SeahorsePgpPhoto SeahorsePgpPhoto;
+typedef struct _SeahorsePgpSignature SeahorsePgpSignature;
+
+G_END_DECLS
diff --git a/pgp/seahorse-pgp-uid.h b/pgp/seahorse-pgp-uid.h
index 26b90629..9c03db45 100644
--- a/pgp/seahorse-pgp-uid.h
+++ b/pgp/seahorse-pgp-uid.h
@@ -23,7 +23,7 @@
 
 #include "seahorse-common.h"
 
-#include "seahorse-pgp-key.h"
+#include "seahorse-pgp-types.h"
 
 #define SEAHORSE_PGP_TYPE_UID            (seahorse_pgp_uid_get_type ())
 G_DECLARE_DERIVABLE_TYPE (SeahorsePgpUid, seahorse_pgp_uid, SEAHORSE_PGP, UID, SeahorseObject)


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]