30
30
* A persona subclass which represents a single EDS contact.
32
* Each {@link Edsf.Persona} instance represents a single EDS {@link E.Contact}.
33
* When the contact is modified (either by this folks client, or a different
34
* client), the {@link Edsf.Persona} remains the same, but is assigned a new
35
* {@link E.Contact}. It then updates its properties from this new contact.
32
37
public class Edsf.Persona : Folks.Persona,
75
80
"email_1", "email_2", "email_3", "email_4"
80
84
* vCard field names for miscellaneous URIs.
88
[Deprecated (since = "0.6.3",
89
replacement = "Folks.UrlFieldDetails.PARAM_TYPE_BLOG")]
84
90
public static const string[] url_properties = {
85
91
"blog_url", "fburl", "homepage_url", "video_url"
144
150
"web-service-addresses" };
146
private HashSet<PhoneFieldDetails> _phone_numbers;
147
private Set<PhoneFieldDetails> _phone_numbers_ro;
148
private HashSet<EmailFieldDetails> _email_addresses;
149
private Set<EmailFieldDetails> _email_addresses_ro;
150
private HashSet<NoteFieldDetails> _notes;
151
private Set<NoteFieldDetails> _notes_ro;
152
152
private static HashTable<string, E.ContactField>? _im_eds_map = null;
154
private HashSet<PostalAddressFieldDetails> _postal_addresses;
155
private Set<PostalAddressFieldDetails> _postal_addresses_ro;
157
private HashSet<string> _local_ids;
158
private Set<string> _local_ids_ro;
160
private HashMultiMap<string, WebServiceFieldDetails> _web_service_addresses;
162
private bool _is_favourite;
164
154
private E.Contact _contact; /* should be set on construct */
172
162
construct { this._contact = value; }
165
/* NOTE: Other properties support lazy initialisation, but
166
* web-service-addresses doesn't as it's a linkable property, so always has to
167
* be loaded anyway. */
168
private HashMultiMap<string, WebServiceFieldDetails> _web_service_addresses;
195
190
web_service_addresses);
193
/* NOTE: Other properties support lazy initialisation, but local-ids doesn't
194
* as it's a linkable property, so always has to be loaded anyway. */
195
private HashSet<string> _local_ids = new HashSet<string> ();
196
private Set<string> _local_ids_ro;
199
199
* IDs used to link {@link Edsf.Persona}s.
233
236
[CCode (notify = false)]
234
237
public Set<PostalAddressFieldDetails> postal_addresses
236
get { return this._postal_addresses_ro; }
241
this._update_addresses (true, false);
242
return this._postal_addresses_ro;
237
244
set { this.change_postal_addresses.begin (value); }
257
267
[CCode (notify = false)]
258
268
public Set<PhoneFieldDetails> phone_numbers
260
get { return this._phone_numbers_ro; }
272
this._update_phones (true, false);
273
return this._phone_numbers_ro;
261
275
set { this.change_phone_numbers.begin (value); }
280
297
[CCode (notify = false)]
281
298
public Set<EmailFieldDetails> email_addresses
283
get { return this._email_addresses_ro; }
302
this._update_emails (true, false);
303
return this._email_addresses_ro;
284
305
set { this.change_email_addresses.begin (value); }
465
493
yield ((Edsf.PersonaStore) this.store)._set_gender (this, gender);
468
private HashSet<UrlFieldDetails> _urls;
469
private Set<UrlFieldDetails> _urls_ro;
496
private HashSet<UrlFieldDetails>? _urls = null;
497
private Set<UrlFieldDetails>? _urls_ro = null;
489
521
yield ((Edsf.PersonaStore) this.store)._set_urls (this, urls);
524
/* NOTE: Other properties support lazy initialisation, but im-addresses
525
* doesn't as it's a linkable property, so always has to be loaded anyway. */
492
526
private HashMultiMap<string, ImFieldDetails> _im_addresses =
493
527
new HashMultiMap<string, ImFieldDetails> (null, null,
494
528
(GLib.HashFunc) ImFieldDetails.hash,
517
551
yield ((Edsf.PersonaStore) this.store)._set_im_fds (this, im_addresses);
520
private HashSet<string> _groups;
521
private Set<string> _groups_ro;
554
private HashSet<string>? _groups = null;
555
private Set<string>? _groups_ro = null;
540
578
public async void change_group (string group, bool is_member)
541
579
throws GLib.Error
581
/* NOTE: This method specifically accesses this.groups rather than
582
* this._groups, so that lazy loading is guaranteed to happen if
543
584
/* Nothing to do? */
544
if ((is_member == true && this._groups.contains (group) == true) ||
545
(is_member == false && this._groups.contains (group) == false))
585
if ((is_member == true && this.groups.contains (group) == true) ||
586
(is_member == false && this.groups.contains (group) == false))
550
591
/* Replace the current set of groups with a modified one. */
551
592
var new_groups = new HashSet<string> ();
552
foreach (var category_name in this._groups)
593
foreach (var category_name in this.groups)
554
595
new_groups.add (category_name);
749
804
* Create a new persona.
751
* Create a new persona for the {@link PersonaStore} `store`, representing
752
* the EDS contact given by `contact`.
806
* Create a new persona for the {@link PersonaStore} ``store``, representing
807
* the EDS contact given by ``contact``.
754
809
* @param store the store which will contain the persona
755
810
* @param contact the EDS contact being represented by the persona
762
817
Edsf.Persona._get_property_from_contact<string> (contact, "id");
763
818
var contact_id = (!) (_contact_id ?? "");
765
var uid = this.build_uid (BACKEND_NAME, store.id, contact_id);
820
var uid = Folks.Persona.build_uid (BACKEND_NAME, store.id, contact_id);
766
821
var iid = Edsf.Persona.build_iid (store.id, contact_id);
767
822
var is_user = BookClient.is_self (contact);
784
839
debug ("Creating new Edsf.Persona with IID '%s'", this.iid);
786
841
this._gender = Gender.UNSPECIFIED;
787
this._phone_numbers = new HashSet<PhoneFieldDetails> (
788
(GLib.HashFunc) PhoneFieldDetails.hash,
789
(GLib.EqualFunc) PhoneFieldDetails.equal);
790
this._phone_numbers_ro = this._phone_numbers.read_only_view;
791
this._email_addresses = new HashSet<EmailFieldDetails> (
792
(GLib.HashFunc) EmailFieldDetails.hash,
793
(GLib.EqualFunc) EmailFieldDetails.equal);
794
this._email_addresses_ro = this._email_addresses.read_only_view;
795
this._notes = new HashSet<NoteFieldDetails> (
796
(GLib.HashFunc) NoteFieldDetails.hash,
797
(GLib.EqualFunc) NoteFieldDetails.equal);
798
this._notes_ro = this._notes.read_only_view;
799
this._urls = new HashSet<UrlFieldDetails> (
800
(GLib.HashFunc) UrlFieldDetails.hash,
801
(GLib.EqualFunc) UrlFieldDetails.equal);
802
this._urls_ro = this._urls.read_only_view;
803
this._postal_addresses = new HashSet<PostalAddressFieldDetails> (
804
(GLib.HashFunc) PostalAddressFieldDetails.hash,
805
(GLib.EqualFunc) PostalAddressFieldDetails.equal);
806
this._postal_addresses_ro = this._postal_addresses.read_only_view;
807
this._local_ids = new HashSet<string> ();
808
842
this._local_ids_ro = this._local_ids.read_only_view;
809
843
this._web_service_addresses =
810
844
new HashMultiMap<string, WebServiceFieldDetails> (
812
846
(GLib.HashFunc) WebServiceFieldDetails.hash,
813
847
(GLib.EqualFunc) WebServiceFieldDetails.equal);
814
this._groups = new HashSet<string> ();
815
this._groups_ro = this._groups.read_only_view;
816
this._roles = new HashSet<RoleFieldDetails> (
817
(GLib.HashFunc) RoleFieldDetails.hash,
818
(GLib.EqualFunc) RoleFieldDetails.equal);
819
this._roles_ro = this._roles.read_only_view;
820
848
this._anti_links = new HashSet<string> ();
821
849
this._anti_links_ro = this._anti_links.read_only_view;
890
918
this._update_names ();
891
919
this._update_avatar ();
892
this._update_urls ();
893
this._update_phones ();
894
this._update_addresses ();
895
this._update_emails ();
920
this._update_urls (false);
921
this._update_phones (false);
922
this._update_addresses (false);
923
this._update_emails (false);
897
925
/* Note: because we assume certain e-mail addresses
898
926
* (@gmail, @msn, etc) to also be IM IDs we /must/
901
929
this._update_im_addresses ();
903
this._update_groups ();
904
this._update_notes ();
931
this._update_groups (false);
932
this._update_notes (false);
905
933
this._update_local_ids ();
906
934
this._update_web_services_addresses ();
907
935
this._update_gender ();
908
936
this._update_birthday ();
909
this._update_roles ();
937
this._update_roles (false);
910
938
this._update_favourite ();
911
939
this._update_anti_links ();
979
1007
* by the BirthdayDetails interface.
980
1008
* We cache the timezone since creating it requires mmapping
981
1009
* /etc/localtime, which means lots of syscalls. */
982
var d = new DateTime (this._local_time_zone,
1010
var d = new DateTime (Persona._local_time_zone,
983
1011
(int) bday.year, (int) bday.month, (int) bday.day, 0, 0, 0.0);
984
1012
if (this._birthday == null ||
985
1013
(this._birthday != null &&
1002
private void _update_roles ()
1030
private void _update_roles (bool create_if_not_exist, bool emit_notification = true)
1032
/* See the comments in Folks.Individual about the lazy instantiation
1033
* strategy for roles. */
1034
if (this._roles == null && create_if_not_exist == false)
1036
if (emit_notification)
1038
this.notify_property ("roles");
1042
else if (this._roles == null)
1044
this._roles = new HashSet<RoleFieldDetails> (
1045
(GLib.HashFunc) RoleFieldDetails.hash,
1046
(GLib.EqualFunc) RoleFieldDetails.equal);
1047
this._roles_ro = this._roles.read_only_view;
1004
1050
var new_roles = new HashSet<RoleFieldDetails> (
1005
1051
(GLib.HashFunc) RoleFieldDetails.hash,
1006
1052
(GLib.EqualFunc) RoleFieldDetails.equal);
1156
private void _update_emails ()
1205
private void _update_emails (bool create_if_not_exist, bool emit_notification = true)
1207
/* See the comments in Folks.Individual about the lazy instantiation
1208
* strategy for e-mail addresses. */
1209
if (this._email_addresses == null && create_if_not_exist == false)
1211
if (emit_notification)
1213
this.notify_property ("email-addresses");
1217
else if (this._email_addresses == null)
1219
this._email_addresses = new HashSet<EmailFieldDetails> (
1220
(GLib.HashFunc) EmailFieldDetails.hash,
1221
(GLib.EqualFunc) EmailFieldDetails.equal);
1222
this._email_addresses_ro = this._email_addresses.read_only_view;
1158
1225
var new_email_addresses = new HashSet<EmailFieldDetails> (
1159
1226
(GLib.HashFunc) EmailFieldDetails.hash,
1160
1227
(GLib.EqualFunc) EmailFieldDetails.equal);
1176
1243
if (!Folks.Internal.equal_sets<EmailFieldDetails> (new_email_addresses,
1177
1244
this._email_addresses))
1179
this._email_addresses = new_email_addresses;
1180
this._email_addresses_ro = new_email_addresses.read_only_view;
1181
this.notify_property ("email-addresses");
1246
this._email_addresses = new_email_addresses;
1247
this._email_addresses_ro = new_email_addresses.read_only_view;
1248
if (emit_notification)
1250
this.notify_property ("email-addresses");
1185
private void _update_notes ()
1255
private void _update_notes (bool create_if_not_exist, bool emit_notification = true)
1257
/* See the comments in Folks.Individual about the lazy instantiation
1258
* strategy for notes. */
1259
if (this._notes == null && create_if_not_exist == false)
1261
if (emit_notification)
1263
this.notify_property ("notes");
1267
else if (this._notes == null)
1269
this._notes = new HashSet<NoteFieldDetails> (
1270
(GLib.HashFunc) NoteFieldDetails.hash,
1271
(GLib.EqualFunc) NoteFieldDetails.equal);
1272
this._notes_ro = this._notes.read_only_view;
1187
1275
var new_notes = new HashSet<NoteFieldDetails> (
1188
1276
(GLib.HashFunc) NoteFieldDetails.hash,
1189
1277
(GLib.EqualFunc) NoteFieldDetails.equal);
1347
private void _update_urls ()
1438
private void _update_urls (bool create_if_not_exist, bool emit_notification = true)
1349
var new_urls = new HashSet<UrlFieldDetails> ();
1440
/* See the comments in Folks.Individual about the lazy instantiation
1441
* strategy for URIs. */
1442
if (this._urls == null && create_if_not_exist == false)
1444
if (emit_notification)
1446
this.notify_property ("urls");
1450
else if (this._urls == null)
1452
this._urls = new HashSet<UrlFieldDetails> (
1453
(GLib.HashFunc) UrlFieldDetails.hash,
1454
(GLib.EqualFunc) UrlFieldDetails.equal);
1455
this._urls_ro = this._urls.read_only_view;
1458
var new_urls = new HashSet<UrlFieldDetails> (
1459
(GLib.HashFunc) UrlFieldDetails.hash,
1460
(GLib.EqualFunc) UrlFieldDetails.equal);
1351
1462
/* First we get the standard Evo urls.. */
1352
foreach (var mapping in this._url_properties)
1463
foreach (var mapping in Persona._url_properties)
1354
1465
var url_property = mapping.vcard_field_name;
1355
1466
var folks_type = mapping.folks_type;
1358
1469
if (u != null && u != "")
1360
1471
var fd_u = new UrlFieldDetails ((!) u);
1361
fd_u.set_parameter (fd_u.PARAM_TYPE, folks_type);
1472
fd_u.set_parameter (AbstractFieldDetails.PARAM_TYPE, folks_type);
1362
1473
new_urls.add (fd_u);
1386
1497
this._urls = new_urls;
1387
1498
this._urls_ro = new_urls.read_only_view;
1388
this.notify_property ("urls");
1499
if (emit_notification)
1501
this.notify_property ("urls");
1392
1506
private void _update_im_addresses ()
1394
var im_eds_map = this._get_im_eds_map ();
1508
var im_eds_map = Persona._get_im_eds_map ();
1395
1509
var new_im_addresses = new HashMultiMap<string, ImFieldDetails> (null,
1396
1510
null, (GLib.HashFunc) ImFieldDetails.hash,
1397
1511
(GLib.EqualFunc) ImFieldDetails.equal);
1492
private void _update_groups ()
1610
private void _update_groups (bool create_if_not_exist, bool emit_notification = true)
1612
/* See the comments in Folks.Individual about the lazy instantiation
1613
* strategy for groups. */
1614
if (this._groups == null && create_if_not_exist == false)
1616
if (emit_notification)
1618
this.notify_property ("groups");
1622
else if (this._groups == null)
1624
this._groups = new HashSet<string> ();
1625
this._groups_ro = this._groups.read_only_view;
1494
1628
var category_names =
1495
1629
this._contact.get<GLib.List<string>> (E.ContactField.CATEGORY_LIST);
1496
1630
var new_categories = new HashSet<string> ();
1583
1717
/* Notify if anything's changed. */
1584
1718
this.freeze_notify ();
1586
if (added_categories.size != 0 || removed_categories.size != 0)
1720
if ((added_categories.size != 0 || removed_categories.size != 0) &&
1588
1723
this.notify_property ("groups");
1590
if (this._is_favourite != old_is_favourite)
1725
if (this._is_favourite != old_is_favourite && emit_notification)
1592
1727
this.notify_property ("is-favourite");
1594
1729
if (in_google_personal_group != this._in_google_personal_group)
1596
1731
this._in_google_personal_group = in_google_personal_group;
1597
this.notify_property ("in-google-personal-group");
1732
if (emit_notification)
1734
this.notify_property ("in-google-personal-group");
1600
1738
this.thaw_notify ();
1635
private void _update_phones ()
1773
private void _update_phones (bool create_if_not_exist, bool emit_notification = true)
1775
/* See the comments in Folks.Individual about the lazy instantiation
1776
* strategy for phone numbers. */
1777
if (this._phone_numbers == null && create_if_not_exist == false)
1779
this.notify_property ("phone-numbers");
1782
else if (this._phone_numbers == null)
1784
this._phone_numbers = new HashSet<PhoneFieldDetails> (
1785
(GLib.HashFunc) PhoneFieldDetails.hash,
1786
(GLib.EqualFunc) PhoneFieldDetails.equal);
1787
this._phone_numbers_ro = this._phone_numbers.read_only_view;
1637
1790
var new_phone_numbers = new HashSet<PhoneFieldDetails> (
1638
1791
(GLib.HashFunc) PhoneFieldDetails.hash,
1639
1792
(GLib.EqualFunc) PhoneFieldDetails.equal);
1721
1877
* are the same and if so instantiate only one PostalAddress
1722
1878
* (with the given types).
1724
private void _update_addresses ()
1880
private void _update_addresses (bool create_if_not_exist, bool emit_notification = true)
1882
/* See the comments in Folks.Individual about the lazy instantiation
1883
* strategy for addresses. */
1884
if (this._postal_addresses == null && create_if_not_exist == false)
1886
if (emit_notification)
1888
this.notify_property ("postal-addresses");
1892
else if (this._postal_addresses == null)
1894
this._postal_addresses = new HashSet<PostalAddressFieldDetails> (
1895
(GLib.HashFunc) PostalAddressFieldDetails.hash,
1896
(GLib.EqualFunc) PostalAddressFieldDetails.equal);
1897
this._postal_addresses_ro = this._postal_addresses.read_only_view;
1726
1900
var new_postal_addresses = new HashSet<PostalAddressFieldDetails> (
1727
(GLib.HashFunc) PhoneFieldDetails.hash,
1728
(GLib.EqualFunc) PhoneFieldDetails.equal);
1901
(GLib.HashFunc) PostalAddressFieldDetails.hash,
1902
(GLib.EqualFunc) PostalAddressFieldDetails.equal);
1730
1904
var attrs = this.contact.get_attributes (E.ContactField.ADDRESS);
1731
1905
foreach (unowned E.VCardAttribute attr in attrs)
1748
1922
this._postal_addresses = new_postal_addresses;
1749
1923
this._postal_addresses_ro = new_postal_addresses.read_only_view;
1750
this.notify_property ("phone-numbers");
1924
if (emit_notification)
1926
this.notify_property ("postal-addresses");
1753
this.notify_property ("postal-addresses");
1756
1931
private void _update_local_ids ()