- The corresponding C function folks_backend_store_dup_enabled_backends()
has been renamed folks_backend_store_get_enabled_backends(), and no longer
returns an owned variable.
+* Individual.personas now has type Set<Persona>
Overview of changes from libfolks 0.4.0 to libfolks 0.5.0
=========================================================
* in the `final_individual`. */
HashSet<Individual> candidate_inds = new HashSet<Individual> ();
- GLib.List<Persona> final_personas = new GLib.List<Persona> ();
+ var final_personas = new HashSet<Persona> ();
Individual final_individual = null;
debug ("Aggregating persona '%s' on '%s'.", persona.uid, persona.iid);
}
}
- /* Ensure the original persona makes it into the final persona */
- final_personas.prepend (persona);
+ /* Ensure the original persona makes it into the final individual */
+ final_personas.add (persona);
if (candidate_inds.size > 0 && this._linking_enabled == true)
{
* Individuals so that the Individuals themselves are removed. */
foreach (var individual in candidate_inds)
{
- /* FIXME: It would be faster to prepend a reversed copy of
- * `individual.personas`, then reverse the entire
- * `final_personas` list afterwards, but Vala won't let us.
- * We also have to reference each of `individual.personas`
- * manually, since copy() doesn't do that for us. */
- individual.personas.foreach ((p) =>
- {
- ((Persona) p).ref ();
- });
-
- final_personas.concat (individual.personas.copy ());
+ final_personas.add_all (individual.personas);
}
}
else if (candidate_inds.size > 0)
final_individual = new Individual (final_personas);
debug (" Created new individual '%s' with personas:",
final_individual.id);
- final_personas.foreach ((i) =>
+ foreach (var p in final_personas)
{
- var final_persona = (Persona) i;
+ var final_persona = (Persona) p;
debug (" %s (is user: %s, IID: %s)", final_persona.uid,
final_persona.is_user ? "yes" : "no", final_persona.iid);
});
}
}
- });
+ }
/* Remove the old Individuals. This has to be done here, as we need
* the final_individual. */
}
/* If the individual has 0 personas, we've already signaled removal */
- if (i.personas.length () > 0)
+ if (i.personas.size > 0)
this.individuals_changed (null, i_list, null, null, 0);
this.individuals.remove (i.id);
}
if (parent != null && persona != null)
{
- var personas = parent.personas.copy ();
-
- personas.append (persona);
- parent.personas = personas;
+ parent.personas.add (persona);
}
return persona;
*/
public async void remove_individual (Individual individual) throws GLib.Error
{
- /* We have to iterate manually since using foreach() requires a sync
- * lambda function, meaning we can't yield on the remove_persona() call.
- *
- * Furthermore, removing personas changes the persona list so we need to
- * make a copy first */
- var personas = individual.personas.copy ();
- unowned GLib.List<unowned Persona> i;
+ /* Removing personas changes the persona set so we need to make a copy
+ * first */
+ var personas = new HashSet<Persona> ();
+ foreach (var p in individual.personas)
+ {
+ personas.add (p);
+ }
- for (i = personas; i != null; i = i.next)
+ foreach (var persona in personas)
{
- var persona = (Persona) i.data;
yield persona.store.remove_persona (persona);
}
}
return;
}
- /* Remove all the Personas from writeable PersonaStores
- * We have to iterate manually since using foreach() requires a sync
- * lambda function, meaning we can't yield on the remove_persona() call */
debug ("Unlinking Individual '%s', deleting Personas:", individual.id);
- /* We have to take a copy of the Persona list before removing the
+ /* Remove all the Personas from writeable PersonaStores.
+ *
+ * We have to take a copy of the Persona list before removing the
* Personas, as _personas_changed_cb() (which is called as a result of
* calling _writeable_store.remove_persona()) messes around with Persona
* lists. */
- var personas = individual.personas.copy ();
- foreach (var p in personas)
- p.ref ();
+ var personas = new HashSet<Persona> ();
+ foreach (var p in individual.personas)
+ {
+ personas.add (p);
+ }
foreach (var persona in personas)
{
/**
* The set of {@link Persona}s encapsulated by this Individual.
*
+ * No order is specified over the set of personas, as such an order may be
+ * different across each of the properties implemented by the personas (e.g.
+ * should they be ordered by presence, name, star sign, etc.?).
+ *
* Changing the set of personas may cause updates to the aggregated properties
* provided by the Individual, resulting in property notifications for them.
*
* {@link IndividualAggregator.link_personas} or
* {@link IndividualAggregator.unlink_individual}, which will ensure the link
* changes are written to the appropriate backend.
+ *
+ * @since UNRELEASED
*/
- public GLib.List<Persona> personas
+ public Set<Persona> personas
{
get { return this._persona_set; }
set { this._set_personas (value, null); }
* @param personas a list of {@link Persona}s to initialise the
* {@link Individual} with, or `null`
* @return a new Individual
+ *
+ * @since UNRELEASED
*/
- public Individual (GLib.List<Persona>? personas)
+ public Individual (Set<Persona>? personas)
{
this._im_addresses = new HashMultiMap<string, string> ();
this._web_service_addresses = new HashMultiMap<string, string> ();
{
favourite = ((FavouriteDetails) p).is_favourite;
if (favourite == true)
- return;
+ break;
}
}
this.notify_property ("notes");
}
- private void _set_personas (GLib.List<Persona>? persona_list,
+ private void _set_personas (Set<Persona>? personas,
Individual? replacement_individual)
{
- var persona_set = new HashSet<Persona> (null, null);
GLib.List<Persona> added = null;
GLib.List<Persona> removed = null;
- /* Determine which Personas have been added */
- foreach (var p in persona_list)
+ /* Determine which Personas have been added. If personas == null, we
+ * assume it's an empty set. */
+ if (personas != null)
{
- if (!this._persona_set.contains (p))
+ foreach (var p in personas)
{
- /* Keep track of how many Personas are users */
- if (p.is_user)
- this._persona_user_count++;
+ if (!this._persona_set.contains (p))
+ {
+ /* Keep track of how many Personas are users */
+ if (p.is_user)
+ this._persona_user_count++;
- added.prepend (p);
+ added.prepend (p);
- this._persona_set.add (p);
- this._connect_to_persona (p);
+ this._persona_set.add (p);
+ this._connect_to_persona (p);
- /* Increment the Persona count for this PersonaStore */
- var store = p.store;
- var num_from_store = this._stores.get (store);
- if (num_from_store == 0)
- {
- this._stores.set (store, num_from_store + 1);
- }
- else
- {
- this._stores.set (store, 1);
+ /* Increment the Persona count for this PersonaStore */
+ var store = p.store;
+ var num_from_store = this._stores.get (store);
+ if (num_from_store == 0)
+ {
+ this._stores.set (store, num_from_store + 1);
+ }
+ else
+ {
+ this._stores.set (store, 1);
- store.removed.connect (this._store_removed_cb);
- store.personas_changed.connect (
- this._store_personas_changed_cb);
+ store.removed.connect (this._store_removed_cb);
+ store.personas_changed.connect (
+ this._store_personas_changed_cb);
+ }
}
}
-
- persona_set.add (p);
}
/* Determine which Personas have been removed */
{
var p = iter.get ();
- if (!persona_set.contains (p))
+ if (personas == null || !personas.contains (p))
{
/* Keep track of how many Personas are users */
if (p.is_user)
var id = parts[2];
if (!i.is_user &&
- i.personas.length () == 2 &&
+ i.personas.size == 2 &&
this._default_individuals.contains (id))
{
expected_individuals.add (id);
var parts = i.id.split (":");
var id = parts[2];
- unowned GLib.List<Persona> personas = i.personas;
+ var personas = i.personas;
/* We're not testing the user here */
- if (!i.is_user && personas.length () == 2)
+ if (!i.is_user && personas.size == 2)
{
assert (expected_individuals.remove (id));
- assert (personas.data.iid == personas.next.data.iid);
+
+ string iid = null;
+ foreach (var persona in personas)
+ {
+ if (iid != null)
+ {
+ assert (persona.iid == iid);
+ }
+ else
+ {
+ iid = persona.iid;
+ }
+ }
}
}
});
{
foreach (Individual i in removed)
{
- if (!i.is_user && i.personas.length () == 5)
+ if (!i.is_user && i.personas.size == 5)
{
if (i == individual1)
{
foreach (Individual i in added)
{
- if (!i.is_user && i.personas.length () == 5)
+ if (!i.is_user && i.personas.size == 5)
{
if (individual1 == null)
{
{
foreach (Individual i in removed)
{
- if (!i.is_user && i.personas.length () == 9)
+ if (!i.is_user && i.personas.size == 9)
{
if (i == individual1)
{
foreach (Individual i in added)
{
- if (!i.is_user && i.personas.length () == 9)
+ if (!i.is_user && i.personas.size == 9)
{
if (individual1 == null)
{
assert (aggregator.user == user_individual);
/* The user individual should comprise personas from the two accounts */
- assert (user_individual.personas.length () == 2);
- assert ((user_individual.personas.data.display_id == "me@example.com" &&
- user_individual.personas.next.data.display_id == "me2@example.com") ||
- (user_individual.personas.data.display_id == "me2@example.com" &&
- user_individual.personas.next.data.display_id == "me@example.com"));
+ assert (user_individual.personas.size == 2);
+
+ var display_ids = new HashSet<string> ();
+ foreach (var persona in user_individual.personas)
+ {
+ display_ids.add (persona.display_id);
+ }
+
+ assert (display_ids.contains ("me@example.com") &&
+ display_ids.contains ("me2@example.com"));
/* Clean up for the next test */
this._tp_backend.remove_account (account2_handle);
* personas for the user). */
foreach (Individual i in removed)
{
- assert (i.is_user || i.personas.length () == 1);
+ assert (i.is_user || i.personas.size == 1);
}
foreach (Individual i in added)
{
- assert (i.is_user || i.personas.length () == 1);
+ assert (i.is_user || i.personas.size == 1);
}
});
{
foreach (Individual i in added)
{
- assert (i.personas.length () == 1);
+ assert (i.personas.size == 1);
+
/* Using the display ID is a little hacky, since we strictly
* shouldn't assume anything about…but for the key-file backend,
* we know it's equal to the group name. */
- expected_individuals.remove (i.personas.data.display_id);
+ foreach (var persona in i.personas)
+ {
+ expected_individuals.remove (persona.display_id);
+ }
}
assert (removed == null);
assert (added.length () == 1);
assert (removed.length () == 2);
Individual i = added.nth_data (0);
- assert (i.personas.length () == 3);
+ assert (i.personas.size == 3);
debug ("individuals_changed: 1 individual containing %u personas",
- i.personas.length ());
+ i.personas.size);
main_loop.quit ();
});
/* Link personas */
- GLib.List<unowned Persona> personas1 = new GLib.List<unowned Persona> ();
- personas1.concat (individual_gathered[0].personas.copy ());
- GLib.List<unowned Persona> personas2 = new GLib.List<unowned Persona> ();
- personas2.concat (individual_gathered[1].personas.copy ());
- GLib.List<unowned Persona> personas = new GLib.List<unowned Persona>();
- personas.concat (personas1.copy ());
- personas.concat (personas2.copy ());
+ var personas = new GLib.List<unowned Persona>();
+
+ var personas1 = new GLib.List<unowned Persona> ();
+ foreach (var p1 in individual_gathered[0].personas)
+ {
+ personas.append (p1);
+ personas1.append (p1);
+ }
+
+ var personas2 = new GLib.List<unowned Persona> ();
+ foreach (var p2 in individual_gathered[1].personas)
+ {
+ personas.append (p2);
+ personas2.append (p2);
+ }
+
assert (personas.length () == 2);
+
Idle.add (() =>
{
aggregator.link_personas (personas);
/* the contact list this aggregator is based upon has exactly 1
* Tpf.Persona per Individual */
- var persona = i.personas.data;
+ Persona persona = null;
+ foreach (var p in i.personas)
+ {
+ persona = i;
+ break;
+ }
assert (persona is Tpf.Persona);
/* set the alias through Telepathy and wait for it to hit our
/* the contact list this aggregator is based upon has exactly 1
* Tpf.Persona per Individual */
- var persona = i.personas.data;
+ Persona persona = null;
+ foreach (var p in i.personas)
+ {
+ persona = i;
+ break;
+ }
assert (persona is Tpf.Persona);
/* set the alias through Telepathy and wait for it to hit our
* because if only one of its property is updated
* Individual won't fire a notification.
*/
- unowned Trf.Persona p = (Trf.Persona) i.personas.nth_data (0);
- if (p.structured_name != null)
+ foreach (var p in i.personas)
{
- p.notify["structured-name"].connect
- (this._notify_persona_sname);
+ if (p is NameDetails &&
+ ((NameDetails) p).structured_name != null)
+ {
+ p.notify["structured-name"].connect
+ (this._notify_persona_sname);
+ }
}
i.notify["full-name"].connect (this._notify_cb);
{
this._contact_added = true;
this._individual_id = i.id;
- var contact_id = i.personas.nth_data (0).iid.split (":")[1];
- this._tracker_backend.remove_contact (contact_id);
+ foreach (var persona in i.personas)
+ {
+ var contact_id = persona.iid.split (":")[1];
+ this._tracker_backend.remove_contact (contact_id);
+ }
}
}
if (i.full_name == this._persona_fullname)
{
this._individual_id = i.id;
- this._persona_id = i.personas.nth_data (0).iid;
+
+ /* Only examine the first persona */
+ foreach (var p in i.personas)
+ {
+ this._persona_id = p.iid;
+ break;
+ }
+
this._individual = i;
if (this._pstore.personas.lookup (this._persona_id) != null)
{
{
this._initial_alias_found = true;
- Trf.Persona p = (Trf.Persona)i.personas.nth_data (0);
-
- /*
- * We connect to the Persona's handler because
- * Individual won't forward the notification to us
- * unless it comes from a writeable store.
- */
- p.notify["alias"].connect (this._notify_alias_cb);
-
- /* FIXME:
- * it would be nice if we could just do:
- * i.alias = "foobar"
- * but we depend on:
- * https://bugzilla.gnome.org/show_bug.cgi?id=645441 */
- p.alias = this._modified_alias;
+ foreach (var p in i.personas)
+ {
+
+ /*
+ * We connect to the Persona's handler because
+ * Individual won't forward the notification to us
+ * unless it comes from a writeable store.
+ */
+ p.notify["alias"].connect (this._notify_alias_cb);
+
+ /* FIXME:
+ * it would be nice if we could just do:
+ * i.alias = "foobar"
+ * but we depend on:
+ * https://bugzilla.gnome.org/show_bug.cgi?id=645441 */
+ if (p is AliasDetails)
+ {
+ ((AliasDetails) p).alias = this._modified_alias;
+ }
+ }
}
}
}
{
i.notify["avatar"].connect (this._notify_avatar_cb);
- Trf.Persona p = (Trf.Persona)i.personas.nth_data (0);
- p.avatar = this._avatar;
+ foreach (var p in i.personas)
+ {
+ ((AvatarDetails) p).avatar = this._avatar;
+ }
}
}
t.from_iso8601 (this._birthday);
DateTime bday = new DateTime.from_timeval_utc (t);
- Trf.Persona p = (Trf.Persona)i.personas.nth_data (0);
- p.birthday = (owned) bday;
+ foreach (var p in i.personas)
+ {
+ ((BirthdayDetails) p).birthday = bday;
+ }
}
}
private void _reset_email_address (Individual i)
{
- Trf.Persona p = (Trf.Persona) i.personas.nth_data (0);
- if (this._has_email (p, this._email_1))
+ foreach (var p in i.personas)
{
- var emails1 = new HashSet<FieldDetails> ();
- var email_1 = new FieldDetails (this._email_1);
- emails1.add (email_1);
- p.email_addresses = emails1;
- p.notify["email-addresses"].connect (this._email_addresses_cb);
+ if (this._has_email ((Trf.Persona) p, this._email_1))
+ {
+ var emails1 = new HashSet<FieldDetails> ();
+ var email_1 = new FieldDetails (this._email_1);
+ emails1.add (email_1);
+ ((EmailDetails) p).email_addresses = emails1;
+ p.notify["email-addresses"].connect (this._email_addresses_cb);
+ }
}
}
emails.add (p1);
var p2 = new FieldDetails (this._email_2);
emails.add (p2);
- Trf.Persona p = (Trf.Persona)i.personas.nth_data (0);
- p.email_addresses = emails;
+
+ foreach (var p in i.personas)
+ {
+ ((EmailDetails) p).email_addresses = emails;
+ }
}
}
if (i.is_favourite == false)
{
this._c1_initially_not_favourite = true;
- Trf.Persona p = (Trf.Persona)i.personas.nth_data (0);
- p.is_favourite = true;
+
+ foreach (var p in i.personas)
+ {
+ ((FavouriteDetails) p).is_favourite = true;
+ }
+ }
+ }
+ else if (i.full_name == this._initial_fullname_2)
+ {
+ if (i.is_favourite == true)
+ {
+ this._c2_initially_favourite = true;
+
+ foreach (var p in i.personas)
+ {
+ ((FavouriteDetails) p).is_favourite = false;
+ }
}
}
- else if (i.full_name == this._initial_fullname_2)
- {
- if (i.is_favourite == true)
- {
- this._c2_initially_favourite = true;
- Trf.Persona p = (Trf.Persona)i.personas.nth_data (0);
- p.is_favourite = false;
- }
- }
}
assert (removed == null);
if (i.full_name == this._persona_fullname)
{
this._individual_id = i.id;
- Trf.Persona p = (Trf.Persona)i.personas.nth_data (0);
i.notify["full-name"].connect (this._notify_full_name_cb);
- p.full_name = this._modified_fullname;
+
+ foreach (var p in i.personas)
+ {
+ ((NameDetails) p).full_name = this._modified_fullname;
+ }
}
}
{
i.notify["gender"].connect (this._notify_gender_cb);
- Trf.Persona p = (Trf.Persona)i.personas.nth_data (0);
- p.gender = Gender.MALE;
+ foreach (var p in i.personas)
+ {
+ ((GenderDetails) p).gender = Gender.MALE;
+ }
}
}
im_addresses.set ("yahoo", "three@example.org");
im_addresses.set ("yahoo", "four@example.org");
- Trf.Persona p = (Trf.Persona)i.personas.nth_data (0);
- p.im_addresses = (owned) im_addresses;
+ foreach (var p in i.personas)
+ {
+ ((ImDetails) p).im_addresses = im_addresses;
+ }
}
}
var n = new Note ("some note");
notes.add ((owned) n);
- Trf.Persona p = (Trf.Persona)i.personas.nth_data (0);
- p.notes = (owned) notes;
+ foreach (var p in i.personas)
+ {
+ ((NoteDetails) p).notes = notes;
+ }
}
}
phones.add (p1);
var p2 = new FieldDetails (this._phone_2);
phones.add (p2);
- Trf.Persona p = (Trf.Persona)i.personas.nth_data (0);
- p.phone_numbers = phones;
+
+ foreach (var p in i.personas)
+ {
+ ((PhoneDetails) p).phone_numbers = phones;
+ }
}
}
addresses.add (pa);
- Trf.Persona p = (Trf.Persona)i.personas.nth_data (0);
- p.postal_addresses = (owned) addresses;
+ foreach (var p in i.personas)
+ {
+ ((PostalAddressDetails) p).postal_addresses = addresses;
+ }
}
}
var r = new Role ("some title", "some organisation");
roles.add ((owned) r);
- Trf.Persona p = (Trf.Persona)i.personas.nth_data (0);
- p.roles = (owned) roles;
+ foreach (var p in i.personas)
+ {
+ ((RoleDetails) p).roles = roles;
+ }
}
}
{
if (i.full_name == this._persona_fullname)
{
- Trf.Persona p = (Trf.Persona)i.personas.nth_data (0);
- p.notify["structured-name"].connect (this._notify_sname_cb);
- p.structured_name = this._sname;
+ foreach (var p in i.personas)
+ {
+ p.notify["structured-name"].connect (this._notify_sname_cb);
+ ((NameDetails) p).structured_name = this._sname;
+ }
}
}
p3.set_parameter ("type", "url");
urls.add (p3);
- Trf.Persona p = (Trf.Persona)i.personas.nth_data (0);
- p.urls = urls;
+ foreach (var p in i.personas)
+ {
+ ((UrlDetails) p).urls = urls;
+ }
}
}
bool show_personas)
{
Utils.print_line ("Individual '%s' with %u personas:",
- individual.id, individual.personas.length ());
+ individual.id, individual.personas.size);
/* List the Individual's properties */
unowned ParamSpec[] properties =
/* Overrides for various known properties */
if (object_type.is_a (typeof (Individual)) && prop_name == "personas")
{
- unowned GLib.List<Persona> personas =
- (GLib.List<Persona>) prop_value.get_pointer ();
- return "List of %u personas".printf (personas.length ());
+ Set<Persona> personas = (Set<Persona>) prop_value.get_object ();
+ return "List of %u personas".printf (personas.size);
}
else if (object_type.is_a (typeof (PersonaStore)) &&
prop_name == "personas")
/* FIXME: This can't be in the individual_id_completion_cb() function because
* Vala doesn't allow static local variables. Erk. */
- private static unowned GLib.List<Persona>? persona_uid_iter = null;
+ private static Iterator<Persona>? persona_uid_iter = null;
/* Complete an individual's ID, starting with @word. */
public static string? persona_uid_completion_cb (string word,
if (Utils.persona_uid_iter == null)
{
assert (individual != null);
- Utils.persona_uid_iter = individual.personas;
+ Utils.persona_uid_iter = individual.personas.iterator ();
}
- while (Utils.persona_uid_iter != null)
+ while (Utils.persona_uid_iter.next ())
{
- unowned Persona persona = (Persona) Utils.persona_uid_iter.data;
- Utils.persona_uid_iter = Utils.persona_uid_iter.next;
+ var persona = Utils.persona_uid_iter.get ();
if (persona.uid.has_prefix (word))
return persona.uid;
}
+
+ /* Clean up */
+ Utils.persona_uid_iter = null;
}
/* Clean up */