Support account deletion
authorTravis Reitter <travis.reitter@collabora.co.uk>
Mon, 17 May 2010 17:20:55 +0000 (10:20 -0700)
committerTravis Reitter <travis.reitter@collabora.co.uk>
Mon, 17 May 2010 21:18:58 +0000 (14:18 -0700)
folks/individual-aggregator.vala
folks/individual.vala
folks/persona-store.vala
folks/persona.vala
folks/tp-persona-store.vala
folks/tp-persona.vala

index 6b901f6..a5cecc4 100644 (file)
@@ -32,6 +32,7 @@ public class Folks.IndividualAggregator : Object
   public HashTable<Individual, uint> members { get; private set; }
 
   public signal void individuals_added (GLib.List<Individual> inds);
+  public signal void individuals_removed (GLib.List<Individual> inds);
   /* TODO: add a signal for "subcontact went offline/online"? Is that useful
    * enough to bother with? */
 
@@ -63,13 +64,38 @@ public class Folks.IndividualAggregator : Object
 
   private void account_enabled_cb (Account account)
     {
-      var store = new TpPersonaStore (account);
+      var store = this.stores.get (account.get_object_path (account));
+
+      if (store != null)
+        return;
 
       /* FIXME: cut this */
-      debug ("   adding account name: '%s'", store.account.get_display_name ());
+      debug ("   adding account name: '%s'", account.get_display_name ());
+
+      this.store_add_from_account (account);
+    }
+
+  private void store_add_from_account (Account account)
+    {
+      var store = new TpPersonaStore (account);
 
-      store.personas_added.connect (this.personas_added_cb);
       this.stores.set (account.get_object_path (account), store);
+      store.personas_added.connect (this.personas_added_cb);
+      store.removed.connect (this.store_removed_cb);
+    }
+
+  private void store_removed_cb (PersonaStore store)
+    {
+      var account = ((TpPersonaStore) store).account;
+
+      store.personas_added.disconnect (this.personas_added_cb);
+      store.removed.disconnect (this.store_removed_cb);
+
+      /* no need to remove this stores' personas from all the individuals, since
+       * they'll do that themselves (and emit their own 'removed' signal if
+       * necessary) */
+
+      this.stores.unset (account.get_object_path (account));
     }
 
   private void personas_added_cb (PersonaStore store,
@@ -96,6 +122,7 @@ public class Folks.IndividualAggregator : Object
         {
           if (this.members.lookup (i) == 0)
             {
+              i.removed.connect (this.individual_removed_cb);
               new_individuals.prepend (i);
               this.members.insert (i, 1);
             }
@@ -107,4 +134,11 @@ public class Folks.IndividualAggregator : Object
           this.individuals_added (new_individuals);
         }
     }
+
+  private void individual_removed_cb (Individual i)
+    {
+      var i_list = new GLib.List<Individual> ();
+      i_list.append (i);
+      this.individuals_removed (i_list);
+    }
 }
index a4aa56b..bcb788b 100644 (file)
  *       Travis Reitter <travis.reitter@collabora.co.uk>
  */
 
+using Gee;
 using GLib;
 using Folks.Alias;
 using Folks.Capabilities;
+using Folks.PersonaStore;
 using Folks.Presence;
 
 public class Folks.Individual : Object, Alias, Capabilities, Presence
 {
   private GLib.List<Persona> _personas;
+  private HashTable<PersonaStore, HashSet<Persona>> stores;
 
   /* XXX: should setting this push it down into the Persona (to foward along to
    * the actual store if possible?) */
@@ -34,6 +37,9 @@ public class Folks.Individual : Object, Alias, Capabilities, Presence
   public Folks.PresenceType presence_type { get; private set; }
   public string presence_message { get; private set; }
 
+  /* the last of this individuals personas has been removed, so it is invalid */
+  public signal void removed ();
+
   /* FIXME: set up specific functions, so we can update the alias, etc.
     * cache before notifying any users about the change
     *
@@ -53,6 +59,55 @@ public class Folks.Individual : Object, Alias, Capabilities, Presence
   public Individual (GLib.List<Persona>? personas)
     {
       Object (personas: personas);
+
+      this.stores = new HashTable<PersonaStore, HashSet<Persona>> (direct_hash,
+          direct_equal);
+      this.stores_update ();
+    }
+
+  private void stores_update ()
+    {
+      this._personas.foreach ((p) =>
+        {
+          var persona = (Persona) p;
+          var store_is_new = false;
+          var persona_set = this.stores.lookup (persona.store);
+          if (persona_set == null)
+            {
+              persona_set = new HashSet<Persona> (direct_hash, direct_equal);
+              store_is_new = true;
+            }
+
+          persona_set.add (persona);
+
+          if (store_is_new)
+            {
+              this.stores.insert (persona.store, persona_set);
+
+              persona.store.removed.connect (this.store_removed_cb);
+            }
+        });
+    }
+
+  private void store_removed_cb (PersonaStore store)
+    {
+      var persona_set = this.stores.lookup (store);
+
+      foreach (var persona in persona_set)
+        {
+          this._personas.remove (persona);
+        }
+
+      if (persona_set.size < 1)
+        this.stores.remove (store);
+
+      if (this._personas.length () < 1)
+        {
+          this.removed ();
+          return;
+        }
+
+      this.update_fields ();
     }
 
   private void update_fields ()
index 6b0ee62..fb050a5 100644 (file)
@@ -24,6 +24,10 @@ using Folks.Persona;
 public abstract class Folks.PersonaStore : Object
 {
   public abstract signal void personas_added (GLib.List<Persona> personas);
+  public abstract signal void personas_removed (GLib.List<Persona> personas);
+
+  /* the backing store itself was deleted and its personas are now invalid */
+  public abstract signal void removed ();
 
   public abstract HashTable<string, Persona> personas { get; }
 }
index 6295497..8a585d0 100644 (file)
@@ -21,6 +21,7 @@
 using GLib;
 using Folks.Alias;
 using Folks.Capabilities;
+using Folks.PersonaStore;
 using Folks.Presence;
 
 public abstract class Folks.Persona : Object, Alias, Capabilities, Presence
@@ -39,4 +40,6 @@ public abstract class Folks.Persona : Object, Alias, Capabilities, Presence
   public string iid { get; construct; }
   /* universal ID (eg, "foo@xmpp.example.org") */
   public string uid { get; construct; }
+
+  public PersonaStore store { get; construct; }
 }
index 60584bf..519da8b 100644 (file)
@@ -52,7 +52,16 @@ public class Folks.TpPersonaStore : PersonaStore
       this.channels = new HashMap<string, Channel> ();
       this.ll = new Lowlevel ();
 
+      this.account.invalidated.connect ((s, p) => {
+          this.removed ();
+          /* in case anyone still holds onto a ref for some reason, minimize the
+           * damage */
+          this._personas = null;
+          this.channels = null;
+          this.conn = null;
+      });
       this.account.status_changed.connect (this.account_status_changed_cb);
+
       Tp.ConnectionStatusReason reason;
       var status = this.account.get_connection_status (out reason);
       this.account_status_changed_cb (Tp.ConnectionStatus.DISCONNECTED,
@@ -195,21 +204,21 @@ public class Folks.TpPersonaStore : PersonaStore
           warning ("    %u", (uint) h);
         }
 
-      var persona_set = new HashSet<Persona> ();
+      var personas_new = new HashSet<Persona> ();
       for (var i = 0; i < n_contacts; i++)
         {
           Contact contact = contacts[i];
           Persona persona;
 
-          persona = new TpPersona (contact);
-          persona_set.add (persona);
+          persona = new TpPersona (contact, this);
+          personas_new.add (persona);
 
           this._personas.insert (persona.iid, persona);
         }
 
-      if (persona_set.size >= 1)
+      if (personas_new.size >= 1)
         {
-          GLib.List<Persona> personas = this.hash_set_to_list (persona_set);
+          GLib.List<Persona> personas = this.hash_set_to_list (personas_new);
           this.personas_added (personas);
         }
     }
index 3da970f..6b0aa0a 100644 (file)
@@ -39,7 +39,7 @@ public class Folks.TpPersona : Persona, Alias, Capabilities, Presence
 
   public Contact contact { get; construct; }
 
-  public TpPersona (Contact contact)
+  public TpPersona (Contact contact, PersonaStore store)
     {
       var uid = contact.get_identifier ();
       if (uid == null || uid == "")
@@ -64,6 +64,7 @@ public class Folks.TpPersona : Persona, Alias, Capabilities, Presence
               /* FIXME: we'll probably need to include the ID for the contact's
                * account in the iid */
               iid: uid,
-              uid: uid);
+              uid: uid,
+              store: store);
     }
 }