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? */
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,
{
if (this.members.lookup (i) == 0)
{
+ i.removed.connect (this.individual_removed_cb);
new_individuals.prepend (i);
this.members.insert (i, 1);
}
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);
+ }
}
* 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?) */
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
*
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 ()
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; }
}
using GLib;
using Folks.Alias;
using Folks.Capabilities;
+using Folks.PersonaStore;
using Folks.Presence;
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; }
}
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,
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);
}
}
public Contact contact { get; construct; }
- public TpPersona (Contact contact)
+ public TpPersona (Contact contact, PersonaStore store)
{
var uid = contact.get_identifier ();
if (uid == null || uid == "")
/* 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);
}
}