From: Philip Withnall Date: Tue, 6 Dec 2011 23:09:14 +0000 (+0000) Subject: Bug 665692 — Use constructors correctly X-Git-Tag: FOLKS_0_6_6~2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=2247cdd5f71a65f330343da2438e68fb8a3ecfd3;p=platform%2Fupstream%2Ffolks.git Bug 665692 — Use constructors correctly In order to allow libfolks to be used from introspected languages (such as Python) properly, we need to correctly use the GObject construction process, rather than generating code which does all object initialisation inside a *_new() function. This involves moving lots of code into construct{} blocks. There are some complications; mostly the need for various private variables to now be exposed as construct-only properties. Most of them should've been anyway. Other complications arose from the fact that moving code to a construct{} block can subtly change the execution order of the code if the Object() call lists properties which are non-construct properties (e.g. the “alias” property of a Persona). The setters for these properties will now be called _after_ the construct{} code, whereas previously they would've been called beforehand. This rears its head in Tpf.Persona, but hopefully nowhere else. Closes: bgo#665692 --- diff --git a/NEWS b/NEWS index 879c982..17e0d0a 100644 --- a/NEWS +++ b/NEWS @@ -8,6 +8,24 @@ Bugs fixed: * Bug 665039 — Crash in folks_backends_sw_backend_add_service * Bug 665728 — TpfPersonaStore: prepare() isn't mutually exclusive inside a single thread +* Bug 665692 — Use constructors correctly + +API changes: +* Add Edsf.PersonaStore.source +* Make Edsf.Persona.contact writeable on construct (previously private setter) +* Make Edsf.Persona.contact_id writeable on construct (previously private + setter) +* Add Swf.PersonaStore.service +* Make Swf.Persona.lsw_contact writeable on construct (previously private + setter) +* Add Trf.Persona.tracker_id +* Add Trf.Persona.cursor +* Make AbstractFieldDetails.value writeable on construct (previously just a + normal setter) +* Make AbstractFieldDetails.parameters writeable on construct (previously just a + normal setter) +* Add ObjectCache.type_id +* Add ObjectCache.id Overview of changes from libfolks 0.6.4.1 to libfolks 0.6.5 ============================================================= diff --git a/backends/eds/eds-backend.vala b/backends/eds/eds-backend.vala index 9886222..b1f3b12 100644 --- a/backends/eds/eds-backend.vala +++ b/backends/eds/eds-backend.vala @@ -61,6 +61,11 @@ public class Folks.Backends.Eds.Backend : Folks.Backend */ public Backend () { + Object (); + } + + construct + { this._persona_stores = new HashMap (); this._persona_stores_ro = this._persona_stores.read_only_view; } diff --git a/backends/eds/lib/edsf-persona-store.vala b/backends/eds/lib/edsf-persona-store.vala index 6f3dc84..41982a5 100644 --- a/backends/eds/lib/edsf-persona-store.vala +++ b/backends/eds/lib/edsf-persona-store.vala @@ -42,7 +42,6 @@ public class Edsf.PersonaStore : Folks.PersonaStore private E.BookClient _addressbook; private E.BookClientView _ebookview; private E.SourceList? _source_list = null; - private E.Source _source; private string _query_str; /* The timeout after which we consider a property change to have failed if we @@ -192,6 +191,16 @@ public class Edsf.PersonaStore : Folks.PersonaStore } /** + * The EDS {@link E.Source} associated with this persona store. + * + * @since UNRELEASED + */ + public E.Source source + { + get; construct; + } + + /** * Create a new PersonaStore. * * Create a new persona store to store the {@link Persona}s for the contacts @@ -203,12 +212,17 @@ public class Edsf.PersonaStore : Folks.PersonaStore public PersonaStore (E.Source s) { string eds_uid = s.peek_uid (); - Object (id: eds_uid, display_name: eds_uid); - this._source = s; + Object (id: eds_uid, + display_name: eds_uid, + source: s); + } + + construct + { this._personas = new HashMap (); this._personas_ro = this._personas.read_only_view; this._query_str = "(contains \"x-evolution-any-field\" \"\")"; - this._source.changed.connect (this._source_changed_cb); + this.source.changed.connect (this._source_changed_cb); this._notify_if_default (); } @@ -550,7 +564,7 @@ public class Edsf.PersonaStore : Folks.PersonaStore this._source_list.changed.connect (this._source_list_changed_cb); /* Connect to the address book. */ - this._addressbook = new E.BookClient (this._source); + this._addressbook = new E.BookClient (this.source); this._addressbook.notify["readonly"].connect ( this._address_book_notify_read_only_cb); @@ -1989,7 +2003,7 @@ public class Edsf.PersonaStore : Folks.PersonaStore */ private void _update_trust_level () { - unowned SourceGroup? group = (SourceGroup?) this._source.peek_group (); + unowned SourceGroup? group = (SourceGroup?) this.source.peek_group (); if (group != null) { var base_uri = group.peek_base_uri (); @@ -2025,7 +2039,7 @@ public class Edsf.PersonaStore : Folks.PersonaStore E.BookClient.get_sources (out sources); var default_source = sources.peek_default_source (); if (default_source != null && - this._source.peek_uid () == default_source.peek_uid ()) + this.source.peek_uid () == default_source.peek_uid ()) { is_default = true; } diff --git a/backends/eds/lib/edsf-persona.vala b/backends/eds/lib/edsf-persona.vala index 17a31f3..a295b8d 100644 --- a/backends/eds/lib/edsf-persona.vala +++ b/backends/eds/lib/edsf-persona.vala @@ -140,13 +140,15 @@ public class Edsf.Persona : Folks.Persona, private bool _is_favourite; + private E.Contact _contact; /* should be set on construct */ + /** * The e-d-s contact represented by this Persona */ public E.Contact contact { - get; - private set; + get { return this._contact; } + construct { this._contact = value; } } /** @@ -371,7 +373,7 @@ public class Edsf.Persona : Folks.Persona, * * @since 0.6.0 */ - public string contact_id { get; private set; } + public string contact_id { get; construct; } private string _full_name = ""; /** @@ -703,16 +705,20 @@ public class Edsf.Persona : Folks.Persona, if (full_name == null) full_name = ""; - debug ("Creating new Edsf.Persona with IID '%s'", iid); - Object (display_id: full_name, uid: uid, iid: iid, store: store, - is_user: is_user); + is_user: is_user, + contact_id: contact_id, + contact: contact); + } + + construct + { + debug ("Creating new Edsf.Persona with IID '%s'", this.iid); this._gender = Gender.UNSPECIFIED; - this.contact_id = contact_id; this._phone_numbers = new HashSet ( (GLib.HashFunc) PhoneFieldDetails.hash, (GLib.EqualFunc) PhoneFieldDetails.equal); @@ -747,7 +753,7 @@ public class Edsf.Persona : Folks.Persona, (GLib.EqualFunc) RoleFieldDetails.equal); this._roles_ro = this._roles.read_only_view; - this._update (contact); + this._update (this._contact); } /** @@ -805,12 +811,15 @@ public class Edsf.Persona : Folks.Persona, /** * Update attribs of the persona. */ - internal void _update (E.Contact contact) + internal void _update (E.Contact updated_contact) { - this.contact = contact; - this.freeze_notify (); + /* We get a new E.Contact instance from EDS containing all the updates, + * so replace our existing contact with it. */ + this._contact = updated_contact; + this.notify_property ("contact"); + this._update_names (); this._update_avatar (); this._update_urls (); diff --git a/backends/eds/lib/memory-icon.vala b/backends/eds/lib/memory-icon.vala index 544339f..5a06e0d 100644 --- a/backends/eds/lib/memory-icon.vala +++ b/backends/eds/lib/memory-icon.vala @@ -41,6 +41,10 @@ internal class Edsf.MemoryIcon : Object, Icon, LoadableIcon */ public MemoryIcon (string? image_type, uint8[] image_data) { + /* Note: To be correct, these should both be properties of the object + * and this constructor should just call Object(…). However, this is an + * internal class, so we can skip all the pain of making a uint8[] object + * for this class only. */ this._image_data = image_data; this._image_type = image_type; } diff --git a/backends/key-file/kf-backend.vala b/backends/key-file/kf-backend.vala index 73fc11d..912c176 100644 --- a/backends/key-file/kf-backend.vala +++ b/backends/key-file/kf-backend.vala @@ -82,6 +82,11 @@ public class Folks.Backends.Kf.Backend : Folks.Backend */ public Backend () { + Object (); + } + + construct + { this._persona_stores = new HashMap (); this._persona_stores_ro = this._persona_stores.read_only_view; } diff --git a/backends/key-file/kf-persona-store.vala b/backends/key-file/kf-persona-store.vala index b33f5e2..616c27a 100644 --- a/backends/key-file/kf-persona-store.vala +++ b/backends/key-file/kf-persona-store.vala @@ -34,7 +34,6 @@ public class Folks.Backends.Kf.PersonaStore : Folks.PersonaStore { private HashMap _personas; private Map _personas_ro; - private File _file; private GLib.KeyFile _key_file; private unowned Cancellable _save_key_file_cancellable = null; private bool _is_prepared = false; @@ -144,6 +143,15 @@ public class Folks.Backends.Kf.PersonaStore : Folks.PersonaStore } /** + * File containing the persona store data. + * + * This must be in GLib key file format. + * + * @since UNRELEASED + */ + public File file { get; construct; } + + /** * Create a new PersonaStore. * * Create a new persona store to expose the {@link Persona}s provided by the @@ -154,10 +162,13 @@ public class Folks.Backends.Kf.PersonaStore : Folks.PersonaStore var id = key_file.get_basename (); Object (id: id, - display_name: id); + display_name: id, + file: key_file); + } + construct + { this.trust_level = PersonaStoreTrust.FULL; - this._file = key_file; this._personas = new HashMap (); this._personas_ro = this._personas.read_only_view; } @@ -178,7 +189,7 @@ public class Folks.Backends.Kf.PersonaStore : Folks.PersonaStore { this._prepare_pending = true; - var filename = this._file.get_path (); + var filename = this.file.get_path (); this._key_file = new GLib.KeyFile (); /* Load or create the file */ @@ -191,7 +202,7 @@ public class Folks.Backends.Kf.PersonaStore : Folks.PersonaStore { uint8 *contents = null; - yield this._file.load_contents_async (null, out contents, + yield this.file.load_contents_async (null, out contents, null); var contents_s = (string) contents; @@ -218,7 +229,7 @@ public class Folks.Backends.Kf.PersonaStore : Folks.PersonaStore } /* Ensure the parent directory tree exists for the new file */ - File parent_dir = this._file.get_parent (); + File parent_dir = this.file.get_parent (); try { @@ -245,7 +256,7 @@ public class Folks.Backends.Kf.PersonaStore : Folks.PersonaStore try { /* Create the file */ - FileOutputStream stream = yield this._file.create_async ( + FileOutputStream stream = yield this.file.create_async ( FileCreateFlags.PRIVATE, Priority.DEFAULT); yield stream.close_async (Priority.DEFAULT); } @@ -271,8 +282,7 @@ public class Folks.Backends.Kf.PersonaStore : Folks.PersonaStore var added_personas = new HashSet (); foreach (var persona_id in groups) { - Persona persona = new Kf.Persona (this._key_file, persona_id, - this); + Persona persona = new Kf.Persona (persona_id, this); this._personas.set (persona.iid, persona); added_personas.add (persona); } @@ -379,7 +389,7 @@ public class Folks.Backends.Kf.PersonaStore : Folks.PersonaStore /* Create a new persona and set its addresses property to update the * key file */ - Persona persona = new Kf.Persona (this._key_file, persona_id, this); + Persona persona = new Kf.Persona (persona_id, this); this._personas.set (persona.iid, persona); try @@ -409,12 +419,17 @@ public class Folks.Backends.Kf.PersonaStore : Folks.PersonaStore return persona; } + internal unowned KeyFile get_key_file () + { + return this._key_file; + } + internal async void save_key_file () { var key_file_data = this._key_file.to_data (); var cancellable = new Cancellable (); - debug ("Saving key file '%s'.", this._file.get_path ()); + debug ("Saving key file '%s'.", this.file.get_path ()); /* There's no point in having two competing file write operations. * We can ensure that only one is running by just checking if a @@ -435,7 +450,7 @@ public class Folks.Backends.Kf.PersonaStore : Folks.PersonaStore * Vala <= 0.10, it returned the character length). FIXME: We need to * take this into account until we depend explicitly on * Vala >= 0.11. */ - yield this._file.replace_contents_async (key_file_data, + yield this.file.replace_contents_async (key_file_data, key_file_data.length, null, false, FileCreateFlags.PRIVATE, cancellable); } @@ -446,7 +461,7 @@ public class Folks.Backends.Kf.PersonaStore : Folks.PersonaStore /* Translators: the first parameter is a filename, the second is * an error message. */ warning (_("Could not write updated key file '%s': %s"), - this._file.get_path (), e.message); + this.file.get_path (), e.message); } } diff --git a/backends/key-file/kf-persona.vala b/backends/key-file/kf-persona.vala index 488e8f3..854d14c 100644 --- a/backends/key-file/kf-persona.vala +++ b/backends/key-file/kf-persona.vala @@ -33,7 +33,6 @@ public class Folks.Backends.Kf.Persona : Folks.Persona, ImDetails, WebServiceDetails { - private unowned GLib.KeyFile _key_file; private HashMultiMap _im_addresses; private HashMultiMap _web_service_addresses; private string _alias = ""; /* must not be null */ @@ -99,7 +98,8 @@ public class Folks.Backends.Kf.Persona : Folks.Persona, debug ("Setting alias of Kf.Persona '%s' to '%s'.", this.uid, alias); - this._key_file.set_string (this.display_id, "__alias", alias); + unowned KeyFile key_file = ((Kf.PersonaStore) this.store).get_key_file (); + key_file.set_string (this.display_id, "__alias", alias); yield ((Kf.PersonaStore) this.store).save_key_file (); this._alias = alias; @@ -124,12 +124,14 @@ public class Folks.Backends.Kf.Persona : Folks.Persona, public async void change_im_addresses ( MultiMap im_addresses) throws PropertyError { + unowned KeyFile key_file = ((Kf.PersonaStore) this.store).get_key_file (); + /* Remove the current IM addresses from the key file */ foreach (var protocol1 in this._im_addresses.get_keys ()) { try { - this._key_file.remove_key (this.display_id, protocol1); + key_file.remove_key (this.display_id, protocol1); } catch (KeyFileError e1) { @@ -178,7 +180,7 @@ public class Folks.Backends.Kf.Persona : Folks.Persona, string[] addrs = (string[]) normalised_addresses.to_array (); addrs.length = normalised_addresses.size; - this._key_file.set_string_list (this.display_id, protocol2, addrs); + key_file.set_string_list (this.display_id, protocol2, addrs); } /* Get the PersonaStore to save the key file */ @@ -207,12 +209,14 @@ public class Folks.Backends.Kf.Persona : Folks.Persona, MultiMap web_service_addresses) throws PropertyError { + unowned KeyFile key_file = ((Kf.PersonaStore) this.store).get_key_file (); + /* Remove the current web service addresses from the key file */ foreach (var web_service1 in this._web_service_addresses.get_keys ()) { try { - this._key_file.remove_key (this.display_id, + key_file.remove_key (this.display_id, "web-service." + web_service1); } catch (KeyFileError e) @@ -238,7 +242,7 @@ public class Folks.Backends.Kf.Persona : Folks.Persona, foreach (var ws_fd1 in ws_fds) addrs += ws_fd1.value; - this._key_file.set_string_list (this.display_id, + key_file.set_string_list (this.display_id, "web-service." + web_service2, addrs); foreach (var ws_fd2 in ws_fds) @@ -258,7 +262,7 @@ public class Folks.Backends.Kf.Persona : Folks.Persona, * Create a new persona for the {@link PersonaStore} `store`, representing * the Persona given by the group `uid` in the key file `key_file`. */ - public Persona (KeyFile key_file, string id, Folks.PersonaStore store) + public Persona (string id, Folks.PersonaStore store) { var iid = store.id + ":" + id; var uid = this.build_uid ("key-file", store.id, id); @@ -268,11 +272,13 @@ public class Folks.Backends.Kf.Persona : Folks.Persona, uid: uid, store: store, is_user: false); + } - debug ("Adding key-file Persona '%s' (IID '%s', group '%s')", uid, iid, - id); + construct + { + debug ("Adding key-file Persona '%s' (IID '%s', group '%s')", this.uid, + this.iid, this.display_id); - this._key_file = key_file; this._im_addresses = new HashMultiMap ( null, null, ImFieldDetails.hash, (EqualFunc) ImFieldDetails.equal); this._web_service_addresses = @@ -282,16 +288,17 @@ public class Folks.Backends.Kf.Persona : Folks.Persona, (GLib.EqualFunc) WebServiceFieldDetails.equal); /* Load the IM addresses from the key file */ + unowned KeyFile key_file = ((Kf.PersonaStore) this.store).get_key_file (); + try { - var keys = this._key_file.get_keys (this.display_id); + var keys = key_file.get_keys (this.display_id); foreach (unowned string key in keys) { /* Alias */ if (key == "__alias") { - this._alias = this._key_file.get_string (this.display_id, - key); + this._alias = key_file.get_string (this.display_id, key); if (this._alias == null) { @@ -308,7 +315,7 @@ public class Folks.Backends.Kf.Persona : Folks.Persona, decomposed_key[0] == "web-service") { unowned string web_service = decomposed_key[1]; - var web_service_addresses = this._key_file.get_string_list ( + var web_service_addresses = key_file.get_string_list ( this.display_id, web_service); foreach (var web_service_address in web_service_addresses) @@ -322,7 +329,7 @@ public class Folks.Backends.Kf.Persona : Folks.Persona, /* IM addresses */ unowned string protocol = key; - var im_addresses = this._key_file.get_string_list ( + var im_addresses = key_file.get_string_list ( this.display_id, protocol); foreach (var im_address in im_addresses) diff --git a/backends/libsocialweb/lib/swf-persona-store.vala b/backends/libsocialweb/lib/swf-persona-store.vala index c078d76..ba3b872 100644 --- a/backends/libsocialweb/lib/swf-persona-store.vala +++ b/backends/libsocialweb/lib/swf-persona-store.vala @@ -39,7 +39,6 @@ public class Swf.PersonaStore : Folks.PersonaStore private bool _is_prepared = false; private bool _prepare_pending = false; private bool _is_quiescent = false; - private ClientService _service; private ClientContactView _contact_view; /* No writeable properties @@ -150,6 +149,14 @@ public class Swf.PersonaStore : Folks.PersonaStore } /** + * The libsocialweb {@link SocialWebClient.ClientService} associated with the + * persona store. + * + * @since UNRELEASED + */ + public ClientService service { get; construct; } + + /** * Create a new PersonaStore. * * Create a new persona store to store the {@link Persona}s for the contacts @@ -157,11 +164,14 @@ public class Swf.PersonaStore : Folks.PersonaStore */ public PersonaStore (ClientService service) { - Object (display_name: service.get_display_name(), - id: service.get_name ()); + Object (display_name: service.get_display_name (), + id: service.get_name (), + service: service); + } + construct + { this.trust_level = PersonaStoreTrust.PARTIAL; - this._service = service; this._personas = new HashMap (); this._personas_ro = this._personas.read_only_view; } @@ -219,7 +229,7 @@ public class Swf.PersonaStore : Folks.PersonaStore * async call to return. See: bgo#665039. */ this.ref (); - this._service.get_static_capabilities ( + this.service.get_static_capabilities ( (service, caps, error) => { if (caps == null) @@ -244,7 +254,7 @@ public class Swf.PersonaStore : Folks.PersonaStore /* Take another ref for this async call. */ this.ref (); - this._service.contacts_query_open_view + this.service.contacts_query_open_view ("people", parameters, (query, contact_view) => { /* The D-Bus call could return an error. In this @@ -325,7 +335,7 @@ public class Swf.PersonaStore : Folks.PersonaStore { foreach (var contact in contacts) { - if (this._service.get_name () != contact.service) + if (this.service.get_name () != contact.service) { continue; } @@ -341,7 +351,7 @@ public class Swf.PersonaStore : Folks.PersonaStore var removed_personas = new HashSet (); foreach (var contact in contacts) { - if (this._service.get_name () != contact.service) + if (this.service.get_name () != contact.service) { continue; } diff --git a/backends/libsocialweb/lib/swf-persona.vala b/backends/libsocialweb/lib/swf-persona.vala index 929ecd4..f4fedce 100644 --- a/backends/libsocialweb/lib/swf-persona.vala +++ b/backends/libsocialweb/lib/swf-persona.vala @@ -185,7 +185,7 @@ public class Swf.Persona : Folks.Persona, public Contact lsw_contact { get { return this._lsw_contact; } - private set + construct { if (_lsw_contact != null && _lsw_contact != value) { @@ -253,7 +253,6 @@ public class Swf.Persona : Folks.Persona, public Persona (PersonaStore store, Contact contact) { var id = get_contact_id (contact); - var service = contact.service.dup(); var uid = this.build_uid (BACKEND_NAME, store.id, id); var iid = this._build_iid (store.id, id); @@ -261,13 +260,17 @@ public class Swf.Persona : Folks.Persona, uid: uid, iid: iid, store: store, - is_user: false); - this.lsw_contact = contact; + is_user: false, + lsw_contact: contact); + } + construct + { debug ("Creating new Sw.Persona '%s' for %s UID '%s': %p", - uid, store.display_name, id, this); + this.uid, this.store.display_name, this.display_id, this); - var facebook_jid = this._build_facebook_jid (store.id, id); + var facebook_jid = + this._build_facebook_jid (this.store.id, this.display_id); if (facebook_jid != null) { try @@ -286,10 +289,11 @@ public class Swf.Persona : Folks.Persona, } } + var service = this.lsw_contact.service.dup (); this._web_service_addresses.set (service, - new WebServiceFieldDetails (id)); + new WebServiceFieldDetails (this.display_id)); - update (contact); + this.update (this.lsw_contact); } ~Persona () diff --git a/backends/libsocialweb/sw-backend.vala b/backends/libsocialweb/sw-backend.vala index f4b60f4..e85dc67 100644 --- a/backends/libsocialweb/sw-backend.vala +++ b/backends/libsocialweb/sw-backend.vala @@ -59,6 +59,11 @@ public class Folks.Backends.Sw.Backend : Folks.Backend */ public Backend () { + Object (); + } + + construct + { this._persona_stores = new HashMap (); this._persona_stores_ro = this._persona_stores.read_only_view; } diff --git a/backends/telepathy/lib/tpf-logger.vala b/backends/telepathy/lib/tpf-logger.vala index a114913..80058e9 100644 --- a/backends/telepathy/lib/tpf-logger.vala +++ b/backends/telepathy/lib/tpf-logger.vala @@ -46,16 +46,23 @@ private interface LoggerIface : Object internal class Logger : GLib.Object { private static LoggerIface _logger; - private string _account_path; private uint _logger_watch_id; public signal void invalidated (); public signal void favourite_contacts_changed (string[] added, string[] removed); + /** + * D-Bus object path of the {@link TelepathyGLib.Account} to watch for + * favourite contacts. + * + * @since UNRELEASED + */ + public string account_path { get; construct; } + public Logger (string account_path) { - this._account_path = account_path; + Object (account_path: account_path); } ~Logger () diff --git a/backends/telepathy/lib/tpf-persona-store-cache.vala b/backends/telepathy/lib/tpf-persona-store-cache.vala index 352a5f5..4e88945 100644 --- a/backends/telepathy/lib/tpf-persona-store-cache.vala +++ b/backends/telepathy/lib/tpf-persona-store-cache.vala @@ -45,7 +45,12 @@ using Folks; */ internal class Tpf.PersonaStoreCache : Folks.ObjectCache { - private weak PersonaStore _store; + /** + * The {@link Tpf.PersonaStore} associated with this cache. + * + * @since UNRELEASED + */ + public weak PersonaStore store { get; construct; } /* Version number of the variant type returned by * get_serialised_object_type(). This must be modified whenever that variant @@ -55,9 +60,9 @@ internal class Tpf.PersonaStoreCache : Folks.ObjectCache internal PersonaStoreCache (PersonaStore store) { - base ("tpf-persona-stores", store.id); - - this._store = store; + Object (type_id: "tpf-persona-stores", + id: store.id, + store: store); } protected override VariantType? get_serialised_object_type ( diff --git a/backends/telepathy/lib/tpf-persona-store.vala b/backends/telepathy/lib/tpf-persona-store.vala index 76caec8..d5c2dde 100644 --- a/backends/telepathy/lib/tpf-persona-store.vala +++ b/backends/telepathy/lib/tpf-persona-store.vala @@ -250,9 +250,12 @@ public class Tpf.PersonaStore : Folks.PersonaStore Object (account: account, display_name: account.display_name, id: account.get_object_path ()); + } + construct + { debug ("Creating new Tpf.PersonaStore %p ('%s') for TpAccount %p.", - this, this.id, account); + this, this.id, this.account); this._debug = Debug.dup (); this._debug.print_status.connect (this._debug_print_status); diff --git a/backends/telepathy/lib/tpf-persona.vala b/backends/telepathy/lib/tpf-persona.vala index b25ee32..bfe1783 100644 --- a/backends/telepathy/lib/tpf-persona.vala +++ b/backends/telepathy/lib/tpf-persona.vala @@ -40,12 +40,6 @@ public class Tpf.Persona : Folks.Persona, PresenceDetails, UrlDetails { - private HashSet _groups; - private Set _groups_ro; - private bool _is_favourite; - private string _alias; /* must never be null */ - private string _full_name; /* must never be null */ - private HashMultiMap _im_addresses; private const string[] _linkable_properties = { "im-addresses" }; private const string[] _always_writeable_properties = { @@ -101,6 +95,8 @@ public class Tpf.Persona : Folks.Persona, set { this.change_structured_name.begin (value); } /* not writeable */ } + private string _full_name = ""; /* must never be null */ + /** * {@inheritDoc} * @@ -276,6 +272,8 @@ public class Tpf.Persona : Folks.Persona, } } + private string _alias = ""; /* must never be null */ + /** * An alias for the Persona. * @@ -309,6 +307,8 @@ public class Tpf.Persona : Folks.Persona, this.notify_property ("alias"); } + private bool _is_favourite = false; + /** * Whether this Persona is a user-defined favourite. * @@ -343,7 +343,10 @@ public class Tpf.Persona : Folks.Persona, this.notify_property ("is-favourite"); } - private HashSet _email_addresses; + private HashSet _email_addresses = + new HashSet ( + (GLib.HashFunc) EmailFieldDetails.hash, + (GLib.EqualFunc) EmailFieldDetails.equal); private Set _email_addresses_ro; /** @@ -370,6 +373,11 @@ public class Tpf.Persona : Folks.Persona, this._email_addresses, "email"); } + private HashMultiMap _im_addresses = + new HashMultiMap (null, null, + (GLib.HashFunc) ImFieldDetails.hash, + (GLib.EqualFunc) ImFieldDetails.equal); + /** * A mapping of IM protocol to an (unordered) set of IM addresses. * @@ -382,6 +390,9 @@ public class Tpf.Persona : Folks.Persona, set { this.change_im_addresses.begin (value); } } + private HashSet _groups = new HashSet (); + private Set _groups_ro; + /** * A mapping of group ID to whether the contact is a member. * @@ -464,7 +475,10 @@ public class Tpf.Persona : Folks.Persona, */ public Contact? contact { get; construct; } - private HashSet _phone_numbers; + private HashSet _phone_numbers = + new HashSet ( + (GLib.HashFunc) PhoneFieldDetails.hash, + (GLib.EqualFunc) PhoneFieldDetails.equal); private Set _phone_numbers_ro; /** @@ -491,7 +505,9 @@ public class Tpf.Persona : Folks.Persona, this._phone_numbers, "tel"); } - private HashSet _urls; + private HashSet _urls = new HashSet ( + (GLib.HashFunc) UrlFieldDetails.hash, + (GLib.EqualFunc) UrlFieldDetails.equal); private Set _urls_ro; /** @@ -570,8 +586,7 @@ public class Tpf.Persona : Folks.Persona, var account = this._account_for_connection (connection); var uid = this.build_uid (store.type_id, store.id, id); - Object (alias: contact.get_alias (), - contact: contact, + Object (contact: contact, display_id: id, /* FIXME: This IID format should be moved out to the ImDetails * interface along with the code in @@ -582,10 +597,28 @@ public class Tpf.Persona : Folks.Persona, store: store, is_user: contact.handle == connection.self_handle); + debug ("Created new Tpf.Persona '%s' for service-specific UID '%s': %p", + uid, id, this); + } + + construct + { + this._groups_ro = this._groups.read_only_view; + this._email_addresses_ro = this._email_addresses.read_only_view; + this._phone_numbers_ro = this._phone_numbers.read_only_view; + this._urls_ro = this._urls.read_only_view; + + /* Contact can be null if we've been created from the cache. All the code + * below this point is for non-cached personas. */ + if (this.contact == null) + { + return; + } - this._full_name = ""; + /* Set our alias. */ + this._alias = this.contact.get_alias (); - contact.notify["alias"].connect ((s, p) => + this.contact.notify["alias"].connect ((s, p) => { /* Tp guarantees that aliases are always non-null. */ assert (this.contact.alias != null); @@ -597,19 +630,13 @@ public class Tpf.Persona : Folks.Persona, } }); - debug ("Creating new Tpf.Persona '%s' for service-specific UID '%s': %p", - uid, id, this); - this._is_constructed = true; - /* Set our single IM address */ - this._im_addresses = new HashMultiMap ( - null, null, - (GLib.HashFunc) ImFieldDetails.hash, - (GLib.EqualFunc) ImFieldDetails.equal); + var connection = this.contact.connection; + var account = this._account_for_connection (connection); try { - var im_addr = ImDetails.normalise_im_address (id, + var im_addr = ImDetails.normalise_im_address (this.display_id, account.get_protocol ()); var im_fd = new ImFieldDetails (im_addr); this._im_addresses.set (account.get_protocol (), im_fd); @@ -620,38 +647,21 @@ public class Tpf.Persona : Folks.Persona, warning (e.message); } - /* Groups */ - this._groups = new HashSet (); - this._groups_ro = this._groups.read_only_view; - - this._email_addresses = new HashSet ( - (GLib.HashFunc) EmailFieldDetails.hash, - (GLib.EqualFunc) EmailFieldDetails.equal); - this._email_addresses_ro = this._email_addresses.read_only_view; - this._phone_numbers = new HashSet ( - (GLib.HashFunc) PhoneFieldDetails.hash, - (GLib.EqualFunc) PhoneFieldDetails.equal); - this._phone_numbers_ro = this._phone_numbers.read_only_view; - this._urls = new HashSet ( - (GLib.HashFunc) UrlFieldDetails.hash, - (GLib.EqualFunc) UrlFieldDetails.equal); - this._urls_ro = this._urls.read_only_view; - - contact.notify["avatar-file"].connect ((s, p) => + this.contact.notify["avatar-file"].connect ((s, p) => { this._contact_notify_avatar (); }); this._contact_notify_avatar (); - contact.notify["presence-message"].connect ((s, p) => + this.contact.notify["presence-message"].connect ((s, p) => { this._contact_notify_presence_message (); }); - contact.notify["presence-type"].connect ((s, p) => + this.contact.notify["presence-type"].connect ((s, p) => { this._contact_notify_presence_type (); }); - contact.notify["presence-status"].connect ((s, p) => + this.contact.notify["presence-status"].connect ((s, p) => { this._contact_notify_presence_status (); }); @@ -659,7 +669,7 @@ public class Tpf.Persona : Folks.Persona, this._contact_notify_presence_type (); this._contact_notify_presence_status (); - contact.notify["contact-info"].connect ((s, p) => + this.contact.notify["contact-info"].connect ((s, p) => { this._contact_notify_contact_info (); }); @@ -701,6 +711,12 @@ public class Tpf.Persona : Folks.Persona, } } + /* Called after all construction-time properties have been set. */ + public override void constructed () + { + this._is_constructed = true; + } + private void _store_notify_supported_fields () { var tpf_store = this.store as Tpf.PersonaStore; @@ -901,13 +917,9 @@ public class Tpf.Persona : Folks.Persona, store: store, is_user: is_user); - debug ("Creating new Tpf.Persona '%s' from cache: %p", uid, this); + debug ("Created new Tpf.Persona '%s' from cache: %p", uid, this); // IM addresses - this._im_addresses = new HashMultiMap (null, null, - (GLib.HashFunc) ImFieldDetails.hash, - (GLib.EqualFunc) ImFieldDetails.equal); - var im_fd = new ImFieldDetails (im_address); this._im_addresses.set (protocol, im_fd); diff --git a/backends/telepathy/tp-backend.vala b/backends/telepathy/tp-backend.vala index 37c7481..3f770b1 100644 --- a/backends/telepathy/tp-backend.vala +++ b/backends/telepathy/tp-backend.vala @@ -57,6 +57,11 @@ public class Folks.Backends.Tp.Backend : Folks.Backend */ public Backend () { + Object (); + } + + construct + { this._persona_stores = new HashMap (); this._persona_stores_ro = this._persona_stores.read_only_view; } diff --git a/backends/tracker/lib/trf-persona-store.vala b/backends/tracker/lib/trf-persona-store.vala index 66f5a53..a326ef8 100644 --- a/backends/tracker/lib/trf-persona-store.vala +++ b/backends/tracker/lib/trf-persona-store.vala @@ -414,7 +414,12 @@ public class Trf.PersonaStore : Folks.PersonaStore */ public PersonaStore () { - Object (id: BACKEND_NAME, display_name: BACKEND_NAME); + Object (id: BACKEND_NAME, + display_name: BACKEND_NAME); + } + + construct + { this._personas = new HashMap (); this._personas_ro = this._personas.read_only_view; debug ("Initial query : \n%s\n", this._INITIAL_QUERY); @@ -1929,8 +1934,8 @@ public class Trf.PersonaStore : Folks.PersonaStore "FILTER (tracker:id(?p) = %s) " + "} "; - string query = query_t.printf (persona.tracker_id (), nickname, - persona.tracker_id ()); + string query = query_t.printf (persona.tracker_id, nickname, + persona.tracker_id); yield this._tracker_update (query, "change_nickname"); } @@ -1974,8 +1979,8 @@ public class Trf.PersonaStore : Folks.PersonaStore " ?p a nco:PersonContact . " + "FILTER (tracker:id(?p) = %s) } "; - string query = query_t.printf (persona.tracker_id (), prop_name, - prop_name, prop_value, persona.tracker_id ()); + string query = query_t.printf (persona.tracker_id, prop_name, + prop_name, prop_value, persona.tracker_id); yield this._tracker_update (query, callers_name); } @@ -2002,11 +2007,11 @@ public class Trf.PersonaStore : Folks.PersonaStore if (is_favourite) { - query = ins_q.printf (((Trf.Persona) persona).tracker_id ()); + query = ins_q.printf (((Trf.Persona) persona).tracker_id); } else { - query = del_q.printf (((Trf.Persona) persona).tracker_id ()); + query = del_q.printf (((Trf.Persona) persona).tracker_id); } yield this._tracker_update (query, "change_is_favourite"); @@ -2030,7 +2035,7 @@ public class Trf.PersonaStore : Folks.PersonaStore Set> properties, Trf.Attrib attrib) { string? query_name = null; - var p_id = ((Trf.Persona) persona).tracker_id (); + var p_id = ((Trf.Persona) persona).tracker_id; var builder = new Tracker.Sparql.Builder.update (); builder.insert_open (null); @@ -2110,7 +2115,7 @@ public class Trf.PersonaStore : Folks.PersonaStore " FILTER(tracker:id(?p) = %s) " + "} "; - var p_id = ((Trf.Persona) persona).tracker_id (); + var p_id = ((Trf.Persona) persona).tracker_id; string del_q = del_t.printf (p_id); var builder = new Tracker.Sparql.Builder.update (); @@ -2159,7 +2164,7 @@ public class Trf.PersonaStore : Folks.PersonaStore " FILTER(tracker:id(?p) = %s)" + "}"; - var p_id = ((Trf.Persona) persona).tracker_id (); + var p_id = ((Trf.Persona) persona).tracker_id; string del_q = del_t.printf (p_id); var builder = new Tracker.Sparql.Builder.update (); @@ -2203,7 +2208,7 @@ public class Trf.PersonaStore : Folks.PersonaStore " FILTER (tracker:id(?p) = %s) " + "} "; - var p_id = ((Trf.Persona) persona).tracker_id (); + var p_id = ((Trf.Persona) persona).tracker_id; TimeVal tv; bday.to_timeval (out tv); string query = q_t.printf (p_id, tv.to_iso8601 (), p_id); @@ -2230,7 +2235,7 @@ public class Trf.PersonaStore : Folks.PersonaStore " FILTER (tracker:id(?p) = %s) " + "} "; - var p_id = ((Trf.Persona) persona).tracker_id (); + var p_id = ((Trf.Persona) persona).tracker_id; string query; if (gender == Gender.UNSPECIFIED) @@ -2275,7 +2280,7 @@ public class Trf.PersonaStore : Folks.PersonaStore " FILTER(tracker:id(?c) = %s) " + "}"; - var p_id = ((Trf.Persona) persona).tracker_id (); + var p_id = ((Trf.Persona) persona).tracker_id; var image_urn = yield this._get_property (int.parse (p_id), Trf.OntologyDefs.NCO_PHOTO); @@ -2345,7 +2350,7 @@ public class Trf.PersonaStore : Folks.PersonaStore " FILTER (tracker:id(?p) = %s) " + "} "; - var p_id = ((Trf.Persona) persona).tracker_id (); + var p_id = ((Trf.Persona) persona).tracker_id; string query = query_d.printf (p_id); if (sname != null) @@ -2376,7 +2381,7 @@ public class Trf.PersonaStore : Folks.PersonaStore " FILTER (tracker:id(?p) = %s) " + "} "; - var p_id = ((Trf.Persona) persona).tracker_id (); + var p_id = ((Trf.Persona) persona).tracker_id; string query = query_t.printf (p_id, full_name, p_id); yield this._tracker_update (query, "_set_full_name"); } @@ -2388,7 +2393,7 @@ public class Trf.PersonaStore : Folks.PersonaStore private async void _set_attrib_set (Folks.Persona persona, Set attribs, Trf.Attrib what) { - var p_id = ((Trf.Persona) persona).tracker_id (); + var p_id = ((Trf.Persona) persona).tracker_id; unowned string? related_attrib = null; unowned string? related_prop = null; @@ -2664,7 +2669,7 @@ public class Trf.PersonaStore : Folks.PersonaStore private async string _urn_from_persona (Folks.Persona persona) { - var id = ((Trf.Persona) persona).tracker_id (); + var id = ((Trf.Persona) persona).tracker_id; return yield this._urn_from_tracker_id (id); } diff --git a/backends/tracker/lib/trf-persona.vala b/backends/tracker/lib/trf-persona.vala index 45c674a..a03d197 100644 --- a/backends/tracker/lib/trf-persona.vala +++ b/backends/tracker/lib/trf-persona.vala @@ -537,17 +537,25 @@ public class Trf.Persona : Folks.Persona, } } - debug ("Creating new Trf.Persona with iid '%s'", iid); - Object (display_id: fullname, uid: uid, iid: iid, store: store, - is_user: is_user); + is_user: is_user, + tracker_id: tracker_id, + /* Ideally we wouldn't have to do this, since passing iterators + * around is ugly. However, we can't fix the Tracker backend to + * not pass Cursors from PersonaStore to Personas without breaking + * API. */ + cursor: cursor); + } + + construct + { + debug ("Creating new Trf.Persona with iid '%s'", this.iid); this._gender = Gender.UNSPECIFIED; - this._full_name = fullname; - this._tracker_id = tracker_id; + this._full_name = ""; this._structured_name = null; this._phone_numbers = new HashSet ( (GLib.HashFunc) PhoneFieldDetails.hash, @@ -577,10 +585,8 @@ public class Trf.Persona : Folks.Persona, this._local_ids_ro = this._local_ids.read_only_view; /* Set the initial property values if we have a results cursor. */ - if (cursor != null) + if (this._cursor != null) { - this._cursor = cursor; - this._update_names (); this._update_avatar (); this._update_im_addresses (); @@ -597,9 +603,30 @@ public class Trf.Persona : Folks.Persona, } } - internal string tracker_id () + /** + * ID of the {@link Trf.Persona} in Tracker. + * + * @since UNRELEASED + */ + public string tracker_id + { + get { return this._tracker_id; } + construct { this._tracker_id = value; } + } + + /** + * A {@link Sparql.Cursor} representing the persona in a set of query results. + * + * This is an internal (read: horrible) API which shouldn't be used by client + * code. It's only exposed publicly due to the design of libfolks’ Tracker + * backend. + * + * @since UNRELEASED + */ + public Sparql.Cursor? cursor { - return this._tracker_id; + get { return this._cursor; } + construct { this._cursor = value; } } /** diff --git a/backends/tracker/tr-backend.vala b/backends/tracker/tr-backend.vala index 40ab4df..44bca1a 100644 --- a/backends/tracker/tr-backend.vala +++ b/backends/tracker/tr-backend.vala @@ -56,6 +56,11 @@ public class Folks.Backends.Tr.Backend : Folks.Backend */ public Backend () { + Object (); + } + + construct + { this._persona_stores = new HashMap (); this._persona_stores_ro = this._persona_stores.read_only_view; } diff --git a/folks/abstract-field-details.vala b/folks/abstract-field-details.vala index 555a7e7..a0819af 100644 --- a/folks/abstract-field-details.vala +++ b/folks/abstract-field-details.vala @@ -98,7 +98,7 @@ public abstract class Folks.AbstractFieldDetails : Object public virtual T @value { get { return this._value; } - set { this._value = value; } + construct set { this._value = value; } } /** @@ -148,7 +148,7 @@ public abstract class Folks.AbstractFieldDetails : Object public virtual MultiMap parameters { get { return this._parameters; } - set + construct set { if (value == null) this._parameters.clear (); diff --git a/folks/avatar-cache.vala b/folks/avatar-cache.vala index 4be9ef3..3dc0e39 100644 --- a/folks/avatar-cache.vala +++ b/folks/avatar-cache.vala @@ -40,6 +40,11 @@ public class Folks.AvatarCache : Object */ private AvatarCache () { + Object (); + } + + construct + { this._cache_directory = File.new_for_path (Environment.get_user_cache_dir ()) .get_child ("folks") diff --git a/folks/backend-store.vala b/folks/backend-store.vala index c71a676..9832bd4 100644 --- a/folks/backend-store.vala +++ b/folks/backend-store.vala @@ -130,6 +130,11 @@ public class Folks.BackendStore : Object { private BackendStore () { + Object (); + } + + construct + { /* Treat this as a library init function */ var debug_no_colour = Environment.get_variable ("FOLKS_DEBUG_NO_COLOUR"); this._debug = diff --git a/folks/debug.vala b/folks/debug.vala index cb8f652..060401a 100644 --- a/folks/debug.vala +++ b/folks/debug.vala @@ -255,7 +255,11 @@ public class Folks.Debug : Object private Debug () { /* Private constructor for singleton */ + Object (); + } + construct + { this._domains_handled = new HashSet (); /* Install a log handler for log messages emitted as a result of diff --git a/folks/individual-aggregator.vala b/folks/individual-aggregator.vala index b349ce4..2956174 100644 --- a/folks/individual-aggregator.vala +++ b/folks/individual-aggregator.vala @@ -273,6 +273,11 @@ public class Folks.IndividualAggregator : Object */ public IndividualAggregator () { + Object (); + } + + construct + { this._stores = new HashMap (); this._individuals = new HashMap (); this._individuals_ro = this._individuals.read_only_view; diff --git a/folks/individual.vala b/folks/individual.vala index 0eae4b5..a101133 100644 --- a/folks/individual.vala +++ b/folks/individual.vala @@ -99,24 +99,19 @@ public class Folks.Individual : Object, UrlDetails, WebServiceDetails { - private bool _is_favourite; - private string _alias; - private HashSet _groups; - private Set _groups_ro; /* Stores the Personas contained in this Individual. */ - private HashSet _persona_set; + private HashSet _persona_set = + new HashSet (direct_hash, direct_equal); /* Read-only view of the above set */ private Set _persona_set_ro; /* Mapping from PersonaStore -> number of Personas from that store contained * in this Individual. There shouldn't be any entries with a number < 1. * This is used for working out when to disconnect from store signals. */ - private HashMap _stores; + private HashMap _stores = + new HashMap (null, null); /* The number of Personas in this Individual which have * Persona.is_user == true. Iff this is > 0, Individual.is_user == true. */ private uint _persona_user_count = 0; - private HashMultiMap _im_addresses; - private HashMultiMap _web_service_addresses; - private string _nickname = ""; /** * The trust level of the Individual. @@ -282,6 +277,8 @@ public class Folks.Individual : Object, */ public signal void removed (Individual? replacement_individual); + private string _alias = ""; + /** * {@inheritDoc} */ @@ -370,6 +367,8 @@ public class Folks.Individual : Object, set { this.change_full_name.begin (value); } /* not writeable */ } + private string _nickname = ""; + /** * {@inheritDoc} */ @@ -451,7 +450,9 @@ public class Folks.Individual : Object, set { this.change_gender.begin (value); } /* not writeable */ } - private HashSet _urls; + private HashSet _urls = new HashSet ( + (GLib.HashFunc) UrlFieldDetails.hash, + (GLib.EqualFunc) UrlFieldDetails.equal); private Set _urls_ro; /** @@ -464,7 +465,10 @@ public class Folks.Individual : Object, set { this.change_urls.begin (value); } /* not writeable */ } - private HashSet _phone_numbers; + private HashSet _phone_numbers = + new HashSet ( + (GLib.HashFunc) PhoneFieldDetails.hash, + (GLib.EqualFunc) PhoneFieldDetails.equal); private Set _phone_numbers_ro; /** @@ -477,7 +481,10 @@ public class Folks.Individual : Object, set { this.change_phone_numbers.begin (value); } /* not writeable */ } - private HashSet _email_addresses; + private HashSet _email_addresses = + new HashSet ( + (GLib.HashFunc) EmailFieldDetails.hash, + (GLib.EqualFunc) EmailFieldDetails.equal); private Set _email_addresses_ro; /** @@ -490,7 +497,9 @@ public class Folks.Individual : Object, set { this.change_email_addresses.begin (value); } /* not writeable */ } - private HashSet _roles; + private HashSet _roles = new HashSet ( + (GLib.HashFunc) RoleFieldDetails.hash, + (GLib.EqualFunc) RoleFieldDetails.equal); private Set _roles_ro; /** @@ -503,7 +512,7 @@ public class Folks.Individual : Object, set { this.change_roles.begin (value); } /* not writeable */ } - private HashSet _local_ids; + private HashSet _local_ids = new HashSet (); private Set _local_ids_ro; /** @@ -540,7 +549,9 @@ public class Folks.Individual : Object, set { this.change_calendar_event_id.begin (value); } /* not writeable */ } - private HashSet _notes; + private HashSet _notes = new HashSet ( + (GLib.HashFunc) NoteFieldDetails.hash, + (GLib.EqualFunc) NoteFieldDetails.equal); private Set _notes_ro; /** @@ -553,7 +564,10 @@ public class Folks.Individual : Object, set { this.change_notes.begin (value); } /* not writeable */ } - private HashSet _postal_addresses; + private HashSet _postal_addresses = + new HashSet ( + (GLib.HashFunc) PostalAddressFieldDetails.hash, + (GLib.EqualFunc) PostalAddressFieldDetails.equal); private Set _postal_addresses_ro; /** @@ -566,6 +580,8 @@ public class Folks.Individual : Object, set { this.change_postal_addresses.begin (value); } /* not writeable */ } + private bool _is_favourite = false; + /** * Whether this Individual is a user-defined favourite. * @@ -638,6 +654,9 @@ public class Folks.Individual : Object, this.notify_property ("is-favourite"); } + private HashSet _groups = new HashSet (); + private Set _groups_ro; + /** * {@inheritDoc} */ @@ -696,6 +715,10 @@ public class Folks.Individual : Object, this._update_groups (); } + private HashMultiMap _im_addresses = + new HashMultiMap ( + null, null, ImFieldDetails.hash, (EqualFunc) ImFieldDetails.equal); + /** * {@inheritDoc} */ @@ -706,6 +729,11 @@ public class Folks.Individual : Object, set { this.change_im_addresses.begin (value); } /* not writeable */ } + private HashMultiMap _web_service_addresses = + new HashMultiMap (null, null, + (GLib.HashFunc) WebServiceFieldDetails.hash, + (GLib.EqualFunc) WebServiceFieldDetails.equal); + /** * {@inheritDoc} */ @@ -889,49 +917,23 @@ public class Folks.Individual : Object, */ public Individual (Set? personas) { + Object (personas: personas); + } + + construct + { debug ("Creating new Individual with %u Personas: %p", - (personas != null ? personas.size : 0), this); + (this.personas != null ? this.personas.size : 0), this); - this._im_addresses = new HashMultiMap ( - null, null, ImFieldDetails.hash, (EqualFunc) ImFieldDetails.equal); - this._web_service_addresses = - new HashMultiMap ( - null, null, - (GLib.HashFunc) WebServiceFieldDetails.hash, - (GLib.EqualFunc) WebServiceFieldDetails.equal); - this._persona_set = - new HashSet (direct_hash, direct_equal); this._persona_set_ro = this._persona_set.read_only_view; - this._stores = new HashMap (null, null); - this._gender = Gender.UNSPECIFIED; - this._urls = new HashSet ( - (GLib.HashFunc) UrlFieldDetails.hash, - (GLib.EqualFunc) UrlFieldDetails.equal); this._urls_ro = this._urls.read_only_view; - this._phone_numbers = new HashSet ( - (GLib.HashFunc) PhoneFieldDetails.hash, - (GLib.EqualFunc) PhoneFieldDetails.equal); this._phone_numbers_ro = this._phone_numbers.read_only_view; - this._email_addresses = new HashSet ( - (GLib.HashFunc) EmailFieldDetails.hash, - (GLib.EqualFunc) EmailFieldDetails.equal); this._email_addresses_ro = this._email_addresses.read_only_view; - this._roles = new HashSet ( - (GLib.HashFunc) RoleFieldDetails.hash, - (GLib.EqualFunc) RoleFieldDetails.equal); this._roles_ro = this._roles.read_only_view; - this._local_ids = new HashSet (); this._local_ids_ro = this._local_ids.read_only_view; - this._postal_addresses = new HashSet ( - (GLib.HashFunc) PostalAddressFieldDetails.hash, - (GLib.EqualFunc) PostalAddressFieldDetails.equal); this._postal_addresses_ro = this._postal_addresses.read_only_view; - this._notes = new HashSet ( - (GLib.HashFunc) NoteFieldDetails.hash, - (GLib.EqualFunc) NoteFieldDetails.equal); this._notes_ro = this._notes.read_only_view; - - this.personas = personas; + this._groups_ro = this._groups.read_only_view; } ~Individual () @@ -1151,13 +1153,6 @@ public class Folks.Individual : Object, { var new_groups = new HashSet (); - /* this._groups is null during initial construction */ - if (this._groups == null) - { - this._groups = new HashSet (); - this._groups_ro = this._groups.read_only_view; - } - /* FIXME: this should partition the personas by store (maybe we should * keep that mapping in general in this class), and execute * "groups-changed" on the store (with the set of personas), to allow the diff --git a/folks/note-details.vala b/folks/note-details.vala index 9acb2f3..838191a 100644 --- a/folks/note-details.vala +++ b/folks/note-details.vala @@ -69,12 +69,9 @@ public class Folks.NoteFieldDetails : AbstractFieldDetails MultiMap? parameters = null, string? uid = null) { - this.value = value; - if (parameters != null) - this.parameters = parameters; - - /* These are kept the same value now */ - this.id = uid; + Object (value: value, + id: uid, + parameters: parameters); } /** diff --git a/folks/object-cache.vala b/folks/object-cache.vala index 9ead921..de06200 100644 --- a/folks/object-cache.vala +++ b/folks/object-cache.vala @@ -50,8 +50,6 @@ public abstract class Folks.ObjectCache : Object * are used (for version numbers). */ private static const size_t _HEADER_WIDTH = 8; /* bytes */ - private string _type_id; - private string _id; private File _cache_directory; private File _cache_file; @@ -108,6 +106,31 @@ public abstract class Folks.ObjectCache : Object uint8 object_version); /** + * A string identifying the type of object being cached. + * + * This has to be suitable for use as a directory name; i.e. lower case, + * hyphen-separated tokens. + * + * @since UNRELEASED + */ + public string type_id { get; construct; } + + /** + * A string identifying the particular cache instance. + * + * This will form the file name of the cache file, but will be escaped + * beforehand, so can be an arbitrary non-empty string. + * + * @since UNRELEASED + */ + public string id + { + get { return this._id; } + construct { assert (value != ""); this._id = value; } + } + private string _id; + + /** * Create a new cache instance using the given type ID and ID. This is * protected as the `type_id` will typically be set statically by subclasses. * @@ -123,20 +146,22 @@ public abstract class Folks.ObjectCache : Object */ protected ObjectCache (string type_id, string id) { - assert (id != ""); - - this._type_id = type_id; - this._id = id; + Object (type_id: type_id, + id: id); + } + construct + { debug ("Creating object cache for type ID '%s' with ID '%s'.", - type_id, id); + this.type_id, this.id); this._cache_directory = File.new_for_path (Environment.get_user_cache_dir ()) .get_child ("folks") - .get_child (type_id); + .get_child (this.type_id); this._cache_file = - this._cache_directory.get_child (Uri.escape_string (id, "", false)); + this._cache_directory.get_child (Uri.escape_string (this.id, + "", false)); } /** @@ -159,7 +184,7 @@ public abstract class Folks.ObjectCache : Object public async Set? load_objects (Cancellable? cancellable = null) { debug ("Loading cache (type ID '%s', ID '%s') from file '%s'.", - this._type_id, this._id, this._cache_file.get_path ()); + this.type_id, this._id, this._cache_file.get_path ()); // Read in the file uint8[] data; @@ -247,11 +272,11 @@ public abstract class Folks.ObjectCache : Object // Unpack the stored data var type_id = variant.get_child_value (0).get_string (); - if (type_id != this._type_id) + if (type_id != this.type_id) { warning ("Cache file '%s' had type ID '%s', but '%s' was expected." + "The file was deleted.", this._cache_file.get_path (), type_id, - this._type_id); + this.type_id); yield this.clear_cache (); return null; @@ -303,7 +328,7 @@ public abstract class Folks.ObjectCache : Object Cancellable? cancellable = null) { debug ("Storing cache (type ID '%s', ID '%s') to file '%s'.", - this._type_id, this._id, this._cache_file.get_path ()); + this.type_id, this._id, this._cache_file.get_path ()); var child_type = this.get_serialised_object_type (uint8.MAX); assert (child_type != null); // uint8.MAX should always be supported @@ -321,7 +346,7 @@ public abstract class Folks.ObjectCache : Object var object_version = this.get_serialised_object_version (); var variant = new Variant.tuple ({ - new Variant.string (this._type_id), // Type ID + new Variant.string (this.type_id), // Type ID new Variant.string (this._id), // ID new Variant.array (child_type, children) // Array of objects }); @@ -387,7 +412,7 @@ public abstract class Folks.ObjectCache : Object public async void clear_cache () { debug ("Clearing cache (type ID '%s', ID '%s'); deleting file '%s'.", - this._type_id, this._id, this._cache_file.get_path ()); + this.type_id, this._id, this._cache_file.get_path ()); try { diff --git a/folks/phone-details.vala b/folks/phone-details.vala index 120b7a7..f71f34f 100644 --- a/folks/phone-details.vala +++ b/folks/phone-details.vala @@ -66,9 +66,8 @@ public class Folks.PhoneFieldDetails : AbstractFieldDetails public PhoneFieldDetails (string value, MultiMap? parameters = null) { - this.value = value; - if (parameters != null) - this.parameters = parameters; + Object (value: value, + parameters: parameters); } /** diff --git a/folks/postal-address-details.vala b/folks/postal-address-details.vala index 3cd3bd9..6a6c8cc 100644 --- a/folks/postal-address-details.vala +++ b/folks/postal-address-details.vala @@ -259,13 +259,14 @@ public class Folks.PostalAddressFieldDetails : public PostalAddressFieldDetails (PostalAddress value, MultiMap? parameters = null) { - this.value = value; - if (parameters != null) - this.parameters = parameters; - - /* We keep these sync'd both directions */ - this.id = this.value.uid; + /* We keep id and value.uid synchronised in both directions. */ + Object (value: value, + parameters: parameters, + id: value.uid); + } + construct + { /* Keep the PostalAddress.uid sync'd to our id */ this.value.notify["uid"].connect ((s, p) => { diff --git a/folks/potential-match.vala b/folks/potential-match.vala index 44ac2d2..82e2e13 100644 --- a/folks/potential-match.vala +++ b/folks/potential-match.vala @@ -83,21 +83,17 @@ public class Folks.PotentialMatch : Object * * @since 0.5.1 */ - public static Set known_email_aliases = null; + public static Set known_email_aliases = + new Gee.HashSet (str_hash, str_equal); private static double _DIST_THRESHOLD = 0.70; private const string _SEPARATORS = "._-+"; - public PotentialMatch () + static construct { - if (this.known_email_aliases == null) - { - this.known_email_aliases = new Gee.HashSet (str_hash, - str_equal); - this.known_email_aliases.add ("admin"); - this.known_email_aliases.add ("abuse"); - this.known_email_aliases.add ("webmaster"); - } + PotentialMatch.known_email_aliases.add ("admin"); + PotentialMatch.known_email_aliases.add ("abuse"); + PotentialMatch.known_email_aliases.add ("webmaster"); } /** @@ -265,7 +261,7 @@ public class Folks.PotentialMatch : Object if (fd_a.value == fd_b.value) { - if (this.known_email_aliases.contains + if (PotentialMatch.known_email_aliases.contains (email_split_a[0]) == true) { if (this._result < MatchResult.HIGH) diff --git a/folks/role-details.vala b/folks/role-details.vala index c1fd042..a910c92 100644 --- a/folks/role-details.vala +++ b/folks/role-details.vala @@ -177,13 +177,14 @@ public class Folks.RoleFieldDetails : AbstractFieldDetails public RoleFieldDetails (Role value, MultiMap? parameters = null) { - this.value = value; - if (parameters != null) - this.parameters = parameters; - - /* We keep these sync'd both directions */ - this.id = this.value.uid; + /* We keep id and value.uid synchronised in both directions. */ + Object (value: value, + parameters: parameters, + id: value.uid); + } + construct + { /* Keep the Role.uid sync'd to our id */ this.value.notify["uid"].connect ((s, p) => { diff --git a/folks/url-details.vala b/folks/url-details.vala index 494b843..501588d 100644 --- a/folks/url-details.vala +++ b/folks/url-details.vala @@ -86,9 +86,8 @@ public class Folks.UrlFieldDetails : AbstractFieldDetails public UrlFieldDetails (string value, MultiMap? parameters = null) { - this.value = value; - if (parameters != null) - this.parameters = parameters; + Object (value: value, + parameters: parameters); } /** diff --git a/folks/web-service-details.vala b/folks/web-service-details.vala index 3b6f405..4717183 100644 --- a/folks/web-service-details.vala +++ b/folks/web-service-details.vala @@ -47,9 +47,8 @@ public class Folks.WebServiceFieldDetails : AbstractFieldDetails public WebServiceFieldDetails (string value, MultiMap? parameters = null) { - this.value = value; - if (parameters != null) - this.parameters = parameters; + Object (value: value, + parameters: parameters); } /**