diff options
author | Niels De Graef <nielsdegraef@gmail.com> | 2022-10-09 10:07:04 +0200 |
---|---|---|
committer | Niels De Graef <ndegraef@redhat.com> | 2022-10-11 08:31:48 +0200 |
commit | 3f932b2d14a884d59aceceb5be6aef7f2a360c27 (patch) | |
tree | fc52555e66a5818560ab8c0889325f1c9dfef614 /src | |
parent | e515d79d4f9440534cf64f1b893f96c2022d6502 (diff) | |
download | gnome-contacts-3f932b2d14a884d59aceceb5be6aef7f2a360c27.tar.gz |
Keep track if a chunk has changed
Introduce a property `dirty` which signifies if a `Contacts.Chunk`
chagned compared to its original value. That way, we can make sure we
don't try to save a property that didn't change, saving us some
necessary work. Although normally folks does a similar check, it's still
good to prevent going into folks (or anything similar) in the first
placE.
As a side effect, it solves a problem we currently had with the
`NicknameChunk`: when calling `save_to_persona()`, it erroneously
represented an empty value as both `""` and `null`. Since those are
different, it would try to save them and the E-D-S would time out in
that case (and throw an appropriate error). As a consequence, when
editing a contact, Contacts would always get blocked on the "nickname"
property.
Fixes: https://gitlab.gnome.org/GNOME/gnome-contacts/-/issues/271
Diffstat (limited to 'src')
-rw-r--r-- | src/core/contacts-addresses-chunk.vala | 36 | ||||
-rw-r--r-- | src/core/contacts-alias-chunk.vala | 13 | ||||
-rw-r--r-- | src/core/contacts-avatar-chunk.vala | 10 | ||||
-rw-r--r-- | src/core/contacts-bin-chunk.vala | 110 | ||||
-rw-r--r-- | src/core/contacts-birthday-chunk.vala | 26 | ||||
-rw-r--r-- | src/core/contacts-chunk.vala | 7 | ||||
-rw-r--r-- | src/core/contacts-contact.vala | 6 | ||||
-rw-r--r-- | src/core/contacts-email-addresses-chunk.vala | 17 | ||||
-rw-r--r-- | src/core/contacts-full-name-chunk.vala | 13 | ||||
-rw-r--r-- | src/core/contacts-im-addresses-chunk.vala | 25 | ||||
-rw-r--r-- | src/core/contacts-nickname-chunk.vala | 13 | ||||
-rw-r--r-- | src/core/contacts-notes-chunk.vala | 14 | ||||
-rw-r--r-- | src/core/contacts-phones-chunk.vala | 18 | ||||
-rw-r--r-- | src/core/contacts-roles-chunk.vala | 21 | ||||
-rw-r--r-- | src/core/contacts-structured-name-chunk.vala | 10 | ||||
-rw-r--r-- | src/core/contacts-urls-chunk.vala | 14 |
16 files changed, 330 insertions, 23 deletions
diff --git a/src/core/contacts-addresses-chunk.vala b/src/core/contacts-addresses-chunk.vala index c322e91..bcdf508 100644 --- a/src/core/contacts-addresses-chunk.vala +++ b/src/core/contacts-addresses-chunk.vala @@ -36,7 +36,7 @@ public class Contacts.AddressesChunk : BinChunk { } } - emptiness_check (); + finish_initialization (); } protected override BinChunkChild create_empty_child () { @@ -85,6 +85,26 @@ public class Contacts.Address : BinChunkChild { this.parameters = address_field.parameters; } + protected override int compare_internal (BinChunkChild other) + requires (other is Address) { + var this_types = this.parameters["type"]; + var other_types = other.parameters["type"]; + + // Put home address first. + // FIXME: we should be minding case sensitivity here + if (("HOME" in this_types) != ("HOME" in other_types)) + return ("HOME" in this_types)? -1 : 1; + + // If no specific preference by type, compare by string + unowned var other_address = (Address) other; + var nr_cmp = strcmp (to_string (""), other_address.to_string ("")); + if (nr_cmp != 0) + return nr_cmp; + + // Fall back to an even dumber comparison + return dummy_compare_parameters (other); + } + /** * Returns the TypeDescriptor that describes the type of this address * (for example home, work, ...) @@ -135,4 +155,18 @@ public class Contacts.Address : BinChunkChild { return new PostalAddressFieldDetails (this.address, this.parameters); } + + public override BinChunkChild copy () { + var address = new Address (); + address.address.address_format = this.address.address_format; + address.address.country = this.address.country; + address.address.extension = this.address.extension; + address.address.locality = this.address.locality; + address.address.po_box = this.address.po_box; + address.address.postal_code = this.address.postal_code; + address.address.region = this.address.region; + address.address.street = this.address.street; + copy_parameters (address); + return address; + } } diff --git a/src/core/contacts-alias-chunk.vala b/src/core/contacts-alias-chunk.vala index 921e9cf..e2d0f20 100644 --- a/src/core/contacts-alias-chunk.vala +++ b/src/core/contacts-alias-chunk.vala @@ -19,6 +19,8 @@ using Folks; public class Contacts.AliasChunk : Chunk { + private string original_alias = ""; + public string alias { get { return this._alias; } set { @@ -26,10 +28,13 @@ public class Contacts.AliasChunk : Chunk { return; bool was_empty = this.is_empty; + bool was_dirty = this.dirty; this._alias = value; notify_property ("alias"); if (this.is_empty != was_empty) notify_property ("is-empty"); + if (was_dirty != this.dirty) + notify_property ("dirty"); } } private string _alias = ""; @@ -38,11 +43,17 @@ public class Contacts.AliasChunk : Chunk { public override bool is_empty { get { return this._alias.strip () == ""; } } + public override bool dirty { + get { return this.alias.strip () == this.original_alias.strip (); } + } + construct { if (persona != null) { return_if_fail (persona is AliasDetails); - persona.bind_property ("alias", this, "alias", BindingFlags.SYNC_CREATE); + persona.bind_property ("alias", this, "alias"); + this._alias = ((AliasDetails) persona).alias; } + this.original_alias = this.alias; } public override Value? to_value () { diff --git a/src/core/contacts-avatar-chunk.vala b/src/core/contacts-avatar-chunk.vala index 56dbce2..850c6cf 100644 --- a/src/core/contacts-avatar-chunk.vala +++ b/src/core/contacts-avatar-chunk.vala @@ -19,6 +19,8 @@ using Folks; public class Contacts.AvatarChunk : Chunk { + private LoadableIcon? original_avatar = null; + public LoadableIcon? avatar { get { return this._avatar; } set { @@ -35,11 +37,17 @@ public class Contacts.AvatarChunk : Chunk { public override bool is_empty { get { return this._avatar == null; } } + public override bool dirty { + get { return this.avatar != this.original_avatar; } + } + construct { if (persona != null) { return_if_fail (persona is AvatarDetails); - persona.bind_property ("avatar", this, "avatar", BindingFlags.SYNC_CREATE); + persona.bind_property ("avatar", this, "avatar"); + this._avatar = ((AvatarDetails) persona).avatar; } + this.original_avatar = this.avatar; } public override Value? to_value () { diff --git a/src/core/contacts-bin-chunk.vala b/src/core/contacts-bin-chunk.vala index 3ce05e5..eac0060 100644 --- a/src/core/contacts-bin-chunk.vala +++ b/src/core/contacts-bin-chunk.vala @@ -29,6 +29,9 @@ using Folks; */ public abstract class Contacts.BinChunk : Chunk, GLib.ListModel { + private BinChunkChild[] original_elements; + private bool original_elements_set = false; + private GenericArray<BinChunkChild> elements = new GenericArray<BinChunkChild> (); public override bool is_empty { @@ -43,6 +46,30 @@ public abstract class Contacts.BinChunk : Chunk, GLib.ListModel { } } + public override bool dirty { + get { + // If we're hitting this, a subclass forgot to set the field + return_if_fail (this.original_elements_set); + + var non_empty_count = nr_nonempty_children (); + if (this.original_elements.length != non_empty_count) + return true; + + // Since we guarantee ordering by BinChunkChild::compare, + // we can just check for equality by paired indices (ignoring the empty + // ones though) + for (uint i = 0, j = 0; i < this.elements.length; i++, j++) { + if (this.elements[i].is_empty) { + j--; + continue; + } + if (this.elements[i].compare (this.original_elements[j]) != 0) + return true; + } + return false; + } + } + /** * Should be called by subclasses when they add a child. * @@ -94,6 +121,15 @@ public abstract class Contacts.BinChunk : Chunk, GLib.ListModel { return false; } + private uint nr_nonempty_children () { + uint result = 0; + for (uint i = 0; i < this.elements.length; i++) { + if (!this.elements[i].is_empty) + result++; + } + return result; + } + public override Value? to_value () { var afds = new Gee.HashSet<AbstractFieldDetails> (); for (uint i = 0; i < this.elements.length; i++) { @@ -117,6 +153,21 @@ public abstract class Contacts.BinChunk : Chunk, GLib.ListModel { return afds; } + /** + * A helper finish the initialization of a BinChunk. It makes sure to set the + * "original_elements" field (which is used to calculate the "dirty" + * property) as well as doing an initial emptiness check + */ + protected void finish_initialization () { + // Make a deep copy to ensure changes don't propagate to original_elements + this.original_elements = this.elements.copy ((child) => { + return child.copy (); + }).steal (); + this.original_elements_set = true; + + emptiness_check (); + } + // ListModel implementation public uint n_items { get { return this.elements.length; } } @@ -163,6 +214,19 @@ public abstract class Contacts.BinChunkChild : GLib.Object { */ public abstract AbstractFieldDetails? create_afd (); + /** + * Creates a deep copy of this child + */ + public abstract BinChunkChild copy (); + + // Helper to copy this object's parameters field into that of @copy + protected void copy_parameters (BinChunkChild copy) { + copy.parameters.clear (); + var iter = this.parameters.map_iterator (); + while (iter.next ()) + copy.parameters[iter.get_key ()] = iter.get_value (); + } + // A helper to change a string field with the proper propery notifies protected void change_string_prop (string prop_name, ref string old_value, @@ -180,8 +244,8 @@ public abstract class Contacts.BinChunkChild : GLib.Object { } /** - * Compares 2 children in an intuitive manner, so that preferred children go - * first and empty children are last + * Compares 2 children in such a way that unequal children are sorted in an + * intuitive manner */ public int compare (BinChunkChild other) { // Fields with a PREF hint always go first (see vCard PREF attribute) @@ -195,7 +259,7 @@ public abstract class Contacts.BinChunkChild : GLib.Object { return empty? 1 : -1; // FIXME: maybe also compare the types? (e.g. put HOME before WORK) - return 0; + return compare_internal (other); } /** @@ -213,4 +277,44 @@ public abstract class Contacts.BinChunkChild : GLib.Object { } return false; } + + /** + * Should be implemented by subclasses to compare with logic specific to that + * property. Note that we ideally try to go for a stable sort + */ + protected abstract int compare_internal (BinChunkChild other); + + // Helper to do a very dumb ordering with this function + protected int dummy_compare_parameters (BinChunkChild other) { + // TYPE is a special vcard param, so use that + var this_types = this.parameters["type"].to_array (); + var other_types = other.parameters["type"].to_array (); + + // If one type is more specific than the other, use that + if (this_types.length != other_types.length) + return other_types.length - this_types.length; + + for (uint i = 0; i < this_types.length; i++) { + var type_cmp = strcmp (this_types[i], other_types[i]); + if (type_cmp != 0) + return type_cmp; + } + + // If the number of parameters is larger, assume it's more specific + // so put it up front + if (this.parameters.size != other.parameters.size) + return other.parameters.size - this.parameters.size; + + // Go over all parameters and check for any difference in size + var keys = this.parameters.get_keys (); + foreach (string key in keys) { + var this_params = this.parameters[key]; + var other_params = other.parameters[key]; + + if (this_params.size != other_params.size) + return other_params.size - this_params.size; + } + + return 0; + } } diff --git a/src/core/contacts-birthday-chunk.vala b/src/core/contacts-birthday-chunk.vala index 087da6a..d929dc5 100644 --- a/src/core/contacts-birthday-chunk.vala +++ b/src/core/contacts-birthday-chunk.vala @@ -23,19 +23,25 @@ using Folks; */ public class Contacts.BirthdayChunk : Chunk { + private DateTime? original_birthday = null; + public DateTime? birthday { get { return this._birthday; } set { - if (this._birthday == null && value == null) + if (this.birthday == null && value == null) return; - if (this._birthday != null && value != null - && this._birthday.equal (value.to_utc ())) + if (this.birthday != null && value != null && this.birthday.equal (value)) return; + bool was_empty = this.is_empty; + bool was_dirty = this.dirty; this._birthday = (value != null)? value.to_utc () : null; notify_property ("birthday"); - notify_property ("is-empty"); + if (was_empty != this.is_empty) + notify_property ("is-empty"); + if (was_dirty != this.dirty) + notify_property ("dirty"); } } private DateTime? _birthday = null; @@ -44,11 +50,21 @@ public class Contacts.BirthdayChunk : Chunk { public override bool is_empty { get { return this.birthday == null; } } + public override bool dirty { + get { + if (this.birthday != null && this.original_birthday != null) + return !this.birthday.equal (this.original_birthday); + return this.birthday != this.original_birthday; + } + } + construct { if (persona != null) { return_if_fail (persona is BirthdayDetails); - persona.bind_property ("birthday", this, "birthday", BindingFlags.SYNC_CREATE); + persona.bind_property ("birthday", this, "birthday"); + this._birthday = ((BirthdayDetails) persona).birthday; } + this.original_birthday = this.birthday; } public override Value? to_value () { diff --git a/src/core/contacts-chunk.vala b/src/core/contacts-chunk.vala index 998ad69..328a042 100644 --- a/src/core/contacts-chunk.vala +++ b/src/core/contacts-chunk.vala @@ -42,10 +42,11 @@ public abstract class Contacts.Chunk : GLib.Object { public abstract bool is_empty { get; } /** - * A separate field to keep track of whether something has changed. - * If it did, we know we'll have to (possibly) save the changes. + * A separate field to keep track of whether this has changed from its + * original value. If it did, we know we'll have to (possibly) save the + * changes. */ - public bool changed { get; protected set; default = false; } + public abstract bool dirty { get; } /** * Converts this chunk into a GLib.Value, as expected by API like diff --git a/src/core/contacts-contact.vala b/src/core/contacts-contact.vala index 5fcc742..761f447 100644 --- a/src/core/contacts-contact.vala +++ b/src/core/contacts-contact.vala @@ -273,6 +273,12 @@ public class Contacts.Contact : GLib.Object, GLib.ListModel { if (individual == null) individual = chunk.persona.individual; + if (!chunk.dirty) { + debug ("Not saving unchanged property '%s' to persona %s", + chunk.property_name, chunk.persona.uid); + continue; + } + if (!(chunk.property_name in chunk.persona.writeable_properties)) { warning ("Can't save to unwriteable property '%s' to persona %s", chunk.property_name, chunk.persona.uid); diff --git a/src/core/contacts-email-addresses-chunk.vala b/src/core/contacts-email-addresses-chunk.vala index 1119a2c..36f5715 100644 --- a/src/core/contacts-email-addresses-chunk.vala +++ b/src/core/contacts-email-addresses-chunk.vala @@ -32,7 +32,7 @@ public class Contacts.EmailAddressesChunk : BinChunk { } } - emptiness_check (); + finish_initialization (); } protected override BinChunkChild create_empty_child () { @@ -72,6 +72,15 @@ public class Contacts.EmailAddress : BinChunkChild { this.parameters = email_field.parameters; } + protected override int compare_internal (BinChunkChild other) + requires (other is EmailAddress) { + unowned var other_email_addr = (EmailAddress) other; + var addr_cmp = strcmp (this.raw_address, other_email_addr.raw_address); + if (addr_cmp != 0) + return addr_cmp; + return dummy_compare_parameters (other); + } + /** * Returns the TypeDescriptor that describes the type of the email address * (for example personal, work, ...) @@ -86,6 +95,12 @@ public class Contacts.EmailAddress : BinChunkChild { return new EmailFieldDetails (this.raw_address, this.parameters); } + public override BinChunkChild copy () { + var email_address = new EmailAddress (); + email_address.raw_address = this.raw_address; + copy_parameters (email_address); + return email_address; + } public string get_mailto_uri () { return "mailto:" + Uri.escape_string (this.raw_address, "@" , false); diff --git a/src/core/contacts-full-name-chunk.vala b/src/core/contacts-full-name-chunk.vala index 647f556..e59fb38 100644 --- a/src/core/contacts-full-name-chunk.vala +++ b/src/core/contacts-full-name-chunk.vala @@ -24,6 +24,8 @@ using Folks; */ public class Contacts.FullNameChunk : Chunk { + private string original_full_name = ""; + public string full_name { get { return this._full_name; } set { @@ -31,10 +33,13 @@ public class Contacts.FullNameChunk : Chunk { return; bool was_empty = this.is_empty; + bool was_dirty = this.dirty; this._full_name = value; notify_property ("full-name"); if (this.is_empty != was_empty) notify_property ("is-empty"); + if (was_dirty != this.dirty) + notify_property ("dirty"); } } private string _full_name = ""; @@ -43,11 +48,17 @@ public class Contacts.FullNameChunk : Chunk { public override bool is_empty { get { return this._full_name.strip () == ""; } } + public override bool dirty { + get { return this.full_name.strip () != this.original_full_name.strip (); } + } + construct { if (persona != null) { return_if_fail (persona is NameDetails); - persona.bind_property ("full-name", this, "full-name", BindingFlags.SYNC_CREATE); + persona.bind_property ("full-name", this, "full-name"); + this._full_name = ((NameDetails) persona).full_name; } + this.original_full_name = this.full_name; } public override Value? to_value () { diff --git a/src/core/contacts-im-addresses-chunk.vala b/src/core/contacts-im-addresses-chunk.vala index 031f804..95cdd3a 100644 --- a/src/core/contacts-im-addresses-chunk.vala +++ b/src/core/contacts-im-addresses-chunk.vala @@ -39,7 +39,7 @@ public class Contacts.ImAddressesChunk : BinChunk { } } - emptiness_check (); + finish_initialization (); } protected override BinChunkChild create_empty_child () { @@ -90,10 +90,33 @@ public class Contacts.ImAddress : BinChunkChild { this.parameters = im_field.parameters; } + protected override int compare_internal (BinChunkChild other) + requires (other is ImAddress) { + unowned var other_im_addr = (ImAddress) other; + + var protocol_cmp = strcmp (this.protocol, other_im_addr.protocol); + if (protocol_cmp != 0) + return protocol_cmp; + + var addr_cmp = strcmp (this.address, other_im_addr.address); + if (addr_cmp != 0) + return addr_cmp; + + return dummy_compare_parameters (other); + } + public override AbstractFieldDetails? create_afd () { if (this.is_empty) return null; return new ImFieldDetails (this.address, this.parameters); } + + public override BinChunkChild copy () { + var ima = new ImAddress (); + ima.protocol = this.protocol; + ima.address = this.address; + copy_parameters (ima); + return ima; + } } diff --git a/src/core/contacts-nickname-chunk.vala b/src/core/contacts-nickname-chunk.vala index ba505f0..81cf1d9 100644 --- a/src/core/contacts-nickname-chunk.vala +++ b/src/core/contacts-nickname-chunk.vala @@ -22,6 +22,8 @@ using Folks; */ public class Contacts.NicknameChunk : Chunk { + private string original_nickname = ""; + public string nickname { get { return this._nickname; } set { @@ -29,10 +31,13 @@ public class Contacts.NicknameChunk : Chunk { return; bool was_empty = this.is_empty; + bool was_dirty = this.dirty; this._nickname = value; notify_property ("nickname"); if (this.is_empty != was_empty) notify_property ("is-empty"); + if (was_dirty != this.dirty) + notify_property ("dirty"); } } private string _nickname = ""; @@ -41,11 +46,17 @@ public class Contacts.NicknameChunk : Chunk { public override bool is_empty { get { return this._nickname.strip () == ""; } } + public override bool dirty { + get { return this.nickname.strip () != this.original_nickname.strip (); } + } + construct { if (persona != null) { return_if_fail (persona is NameDetails); - persona.bind_property ("nickname", this, "nickname", BindingFlags.SYNC_CREATE); + persona.bind_property ("nickname", this, "nickname"); + this._nickname = ((NameDetails) persona).nickname; } + this.original_nickname = this.nickname; } public override Value? to_value () { diff --git a/src/core/contacts-notes-chunk.vala b/src/core/contacts-notes-chunk.vala index 45b5c43..2f1ee3a 100644 --- a/src/core/contacts-notes-chunk.vala +++ b/src/core/contacts-notes-chunk.vala @@ -36,7 +36,7 @@ public class Contacts.NotesChunk : BinChunk { } } - emptiness_check (); + finish_initialization (); } protected override BinChunkChild create_empty_child () { @@ -76,10 +76,22 @@ public class Contacts.Note : BinChunkChild { this.parameters = note_field.parameters; } + protected override int compare_internal (BinChunkChild other) + requires (other is Note) { + return strcmp (this.text, ((Note) other).text); + } + public override AbstractFieldDetails? create_afd () { if (this.is_empty) return null; return new NoteFieldDetails (this.text, this.parameters); } + + public override BinChunkChild copy () { + var note = new Note (); + note.text = this.text; + copy_parameters (note); + return note; + } } diff --git a/src/core/contacts-phones-chunk.vala b/src/core/contacts-phones-chunk.vala index 8135d98..c8e0ce3 100644 --- a/src/core/contacts-phones-chunk.vala +++ b/src/core/contacts-phones-chunk.vala @@ -36,7 +36,7 @@ public class Contacts.PhonesChunk : BinChunk { } } - emptiness_check (); + finish_initialization (); } protected override BinChunkChild create_empty_child () { @@ -80,6 +80,15 @@ public class Contacts.Phone : BinChunkChild { this.parameters = phone_field.parameters; } + protected override int compare_internal (BinChunkChild other) + requires (other is Phone) { + unowned var other_phone = (Phone) other; + var nr_cmp = strcmp (this.raw_number, other_phone.raw_number); + if (nr_cmp != 0) + return nr_cmp; + return dummy_compare_parameters (other); + } + /** * Returns the TypeDescriptor that describes the type of phone number * (for example mobile, work, fax, ...) @@ -94,4 +103,11 @@ public class Contacts.Phone : BinChunkChild { return new PhoneFieldDetails (this.raw_number, this.parameters); } + + public override BinChunkChild copy () { + var phone = new Phone (); + phone.raw_number = this.raw_number; + copy_parameters (phone); + return phone; + } } diff --git a/src/core/contacts-roles-chunk.vala b/src/core/contacts-roles-chunk.vala index bec585b..948c42b 100644 --- a/src/core/contacts-roles-chunk.vala +++ b/src/core/contacts-roles-chunk.vala @@ -37,7 +37,7 @@ public class Contacts.RolesChunk : BinChunk { } } - emptiness_check (); + finish_initialization (); } protected override BinChunkChild create_empty_child () { @@ -72,6 +72,16 @@ public class Contacts.OrgRole : BinChunkChild { this.parameters = role_field.parameters; } + protected override int compare_internal (BinChunkChild other) + requires (other is OrgRole) { + unowned var other_orgrole = (OrgRole) other; + var orgs_cmp = strcmp (this.role.organisation_name, + other_orgrole.role.organisation_name); + if (orgs_cmp != 0) + return orgs_cmp; + return strcmp (this.role.title, other_orgrole.role.title); + } + public override AbstractFieldDetails? create_afd () { if (this.is_empty) return null; @@ -79,6 +89,15 @@ public class Contacts.OrgRole : BinChunkChild { return new RoleFieldDetails (this.role, this.parameters); } + public override BinChunkChild copy () { + var org_role = new OrgRole (); + org_role.role.organisation_name = this.role.organisation_name; + org_role.role.role = this.role.role; + org_role.role.title = this.role.title; + copy_parameters (org_role); + return org_role; + } + public string to_string () { if (this.role.title != "") { if (this.role.organisation_name != "") { diff --git a/src/core/contacts-structured-name-chunk.vala b/src/core/contacts-structured-name-chunk.vala index 07cbc8f..388aa9f 100644 --- a/src/core/contacts-structured-name-chunk.vala +++ b/src/core/contacts-structured-name-chunk.vala @@ -25,6 +25,8 @@ using Folks; */ public class Contacts.StructuredNameChunk : Chunk { + private StructuredName original_structured_name; + public StructuredName structured_name { get { return this._structured_name; } set { @@ -51,11 +53,17 @@ public class Contacts.StructuredNameChunk : Chunk { } } + public override bool dirty { + get { return !this.original_structured_name.equal (this._structured_name); } + } + construct { if (persona != null) { return_if_fail (persona is NameDetails); - persona.bind_property ("structured-name", this, "structured-name", BindingFlags.SYNC_CREATE); + persona.bind_property ("structured-name", this, "structured-name"); + this._structured_name = ((NameDetails) persona).structured_name; } + this.original_structured_name = this.structured_name; } public override Value? to_value () { diff --git a/src/core/contacts-urls-chunk.vala b/src/core/contacts-urls-chunk.vala index 671fc4d..62b02c0 100644 --- a/src/core/contacts-urls-chunk.vala +++ b/src/core/contacts-urls-chunk.vala @@ -36,7 +36,7 @@ public class Contacts.UrlsChunk : BinChunk { } } - emptiness_check (); + finish_initialization (); } protected override BinChunkChild create_empty_child () { @@ -76,6 +76,11 @@ public class Contacts.Url : BinChunkChild { this.parameters = url_field.parameters; } + protected override int compare_internal (BinChunkChild other) + requires (other is Url) { + return strcmp (this.raw_url, ((Url) other).raw_url); + } + /** * Tries to return an absolute URL (with a scheme). * Since we know contact URL values are for web addresses, we try to fall @@ -92,4 +97,11 @@ public class Contacts.Url : BinChunkChild { return new UrlFieldDetails (this.raw_url, this.parameters); } + + public override BinChunkChild copy () { + var url = new Url (); + url.raw_url = this.raw_url; + copy_parameters (url); + return url; + } } |