diff options
author | Alexander Larsson <alexl@redhat.com> | 2012-01-24 11:18:21 +0100 |
---|---|---|
committer | Alexander Larsson <alexl@redhat.com> | 2012-01-24 15:15:39 +0100 |
commit | ddd4e8d0ac29e4de392f4f74ed5d0e0c1768b009 (patch) | |
tree | 342c16fc754b4dc5b9f474311347f913f5d4d2cd /src/contacts-linking.vala | |
parent | 796af7fa5ddcd437fad64b485a769e9dbffbdb0d (diff) | |
download | gnome-contacts-ddd4e8d0ac29e4de392f4f74ed5d0e0c1768b009.tar.gz |
Add undo ability for link/unlink
Diffstat (limited to 'src/contacts-linking.vala')
-rw-r--r-- | src/contacts-linking.vala | 159 |
1 files changed, 145 insertions, 14 deletions
diff --git a/src/contacts-linking.vala b/src/contacts-linking.vala index dc1f380..efbb408 100644 --- a/src/contacts-linking.vala +++ b/src/contacts-linking.vala @@ -21,6 +21,73 @@ using Folks; using Gee; namespace Contacts { + public class LinkOperation : Object { + internal class Change { + public PersonaAttribute attribute; + public Persona persona; + public Object old_value; + } + private Persona? _added_persona; + private Contact? main_contact; + private ArrayList<Persona>? split_out_personas; + ArrayList<Change> changes; + + public LinkOperation() { + changes = new ArrayList<Change> (); + } + + public void set_main_contact (Contact? contact) { + main_contact = contact; + } + + public void set_split_out_contact (Contact? contact) { + split_out_personas = new ArrayList<Persona> (); + split_out_personas.add_all (contact.individual.personas); + } + + public void added_persona (Persona persona) { + _added_persona = persona; + } + + public void add_change (PersonaAttribute attribute, Persona persona, Object old_value) { + var c = new Change (); + c.attribute = attribute; + c.persona = persona; + c.old_value = old_value; + changes.add (c); + } + + public async void undo () { + if (main_contact != null) + main_contact.set_data ("contacts-master-at-join", true); + if (split_out_personas != null) { + foreach (var p in split_out_personas) + p.set_data ("contacts-new-contact", true); + } + + try { + if (_added_persona != null) { + yield _added_persona.store.remove_persona (_added_persona); + } + foreach (var c in changes) { + if (c.persona != _added_persona) { + yield c.attribute.set_value (c.persona, c.old_value); + } + } + } catch (GLib.Error e) { + warning ("Error when undoing linking: %s\n", e.message); + } + + if (main_contact != null) + main_contact.set_data ("contacts-master-at-join", false); + + if (split_out_personas != null) { + foreach (var p in split_out_personas) + p.set_data ("contacts-new-contact", false); + } + } + } + public abstract class PersonaAttribute : Object { public string property_name; @@ -49,7 +116,9 @@ namespace Contacts { public abstract async void persona_apply_attributes (Persona persona, Set<PersonaAttribute> added_attributes, - Set<PersonaAttribute> removed_attributes); + Set<PersonaAttribute> removed_attributes, + LinkOperation operation); + public abstract async void set_value (Persona persona, Object value); } internal class PersonaAttributeLocalId : PersonaAttribute { @@ -80,7 +149,8 @@ namespace Contacts { public override async void persona_apply_attributes (Persona persona, Set<PersonaAttribute> added_attributes, - Set<PersonaAttribute> removed_attributes) { + Set<PersonaAttribute> removed_attributes, + LinkOperation operation) { var details = persona as LocalIdDetails; if (details == null) return; @@ -113,13 +183,29 @@ namespace Contacts { if (changed) { try { + var old_value = new HashSet<string> (); + old_value.add_all (details.local_ids); yield details.change_local_ids (new_values); + operation.add_change (this, persona, old_value); } catch (GLib.Error e) { warning ("Unable to set local ids when linking: %s\n", e.message); } } } + public override async void set_value (Persona persona, Object value) { + var details = persona as LocalIdDetails; + if (details == null) + return; + + try { + var v = value as HashSet<string>; + yield details.change_local_ids (v); + } catch (GLib.Error e) { + warning ("Unable to set local ids when undoing link: %s\n", e.message); + } + } + public override bool equal (PersonaAttribute _that) { var that = _that as PersonaAttributeLocalId; return @@ -159,7 +245,8 @@ namespace Contacts { public override async void persona_apply_attributes (Persona persona, Set<PersonaAttribute> added_attributes, - Set<PersonaAttribute> removed_attributes) { + Set<PersonaAttribute> removed_attributes, + LinkOperation operation) { var details = persona as ImDetails; if (details == null) return; @@ -204,13 +291,28 @@ namespace Contacts { if (changed) { try { + var old_value = details.im_addresses; yield details.change_im_addresses (new_values); + operation.add_change (this, persona, old_value); } catch (GLib.Error e) { warning ("Unable to set im address when linking: %s\n", e.message); } } } + public override async void set_value (Persona persona, Object value) { + var details = persona as ImDetails; + if (details == null) + return; + + try { + var v = value as HashMultiMap<string, ImFieldDetails>; + yield details.change_im_addresses (v); + } catch (GLib.Error e) { + warning ("Unable to set local ids when undoing link: %s\n", e.message); + } + } + public override bool equal (PersonaAttribute _that) { var that = _that as PersonaAttributeImAddress; return @@ -251,7 +353,8 @@ namespace Contacts { public override async void persona_apply_attributes (Persona persona, Set<PersonaAttribute> added_attributes, - Set<PersonaAttribute> removed_attributes) { + Set<PersonaAttribute> removed_attributes, + LinkOperation operation) { var details = persona as WebServiceDetails; if (details == null) return; @@ -296,13 +399,28 @@ namespace Contacts { if (changed) { try { + var old_value = details.web_service_addresses; yield details.change_web_service_addresses (new_values); + operation.add_change (this, persona, old_value); } catch (GLib.Error e) { warning ("Unable to set web service when linking: %s\n", e.message); } } } + public override async void set_value (Persona persona, Object value) { + var details = persona as WebServiceDetails; + if (details == null) + return; + + try { + var v = value as HashMultiMap<string, WebServiceFieldDetails>; + yield details.change_web_service_addresses (v); + } catch (GLib.Error e) { + warning ("Unable to set local ids when undoing link: %s\n", e.message); + } + } + public override bool equal (PersonaAttribute _that) { var that = _that as PersonaAttributeWebService; return @@ -378,7 +496,8 @@ namespace Contacts { public static async void persona_apply_attributes (Persona persona, Set<PersonaAttribute>? added_attributes, - Set<PersonaAttribute>? removed_attributes) { + Set<PersonaAttribute>? removed_attributes, + LinkOperation operation) { var properties = new HashSet<PersonaAttribute>((GLib.HashFunc)attr_type_hash, (GLib.EqualFunc) attr_type_equal); if (added_attributes != null) { @@ -407,15 +526,18 @@ namespace Contacts { removed.add (a4); } } - yield property.persona_apply_attributes (persona, added, removed); + yield property.persona_apply_attributes (persona, added, removed, operation); } } - public async void link_contacts (Contact main, Contact other) { + public async LinkOperation link_contacts (Contact main, Contact other) { // This should not be used as being replaced with the new individual // instead we should always pick this contact to keep around main.set_data ("contacts-master-at-join", true); + var operation = new LinkOperation (); + operation.set_split_out_contact (other); + var main_linkables = get_linkable_attributes_for_individual (main.individual); var other_linkables = get_linkable_attributes_for_individual (other.individual); Set<PersonaAttribute>? linkables = null; @@ -452,6 +574,7 @@ namespace Contacts { var details = new HashTable<string, Value?> (str_hash, str_equal); try { write_persona = yield main.store.aggregator.primary_store.add_persona_from_details (details); + operation.added_persona (write_persona); linkables = main_linkables; linkables.add_all (other_linkables); var name_details = write_persona as NameDetails; @@ -460,20 +583,25 @@ namespace Contacts { } catch (GLib.Error e) { main.set_data ("contacts-master-at-join", false); warning ("Unable to create new persona when linking: %s\n", e.message); - return; + return operation; } } - yield persona_apply_attributes (write_persona, linkables, null); + yield persona_apply_attributes (write_persona, linkables, null, operation); main.set_data ("contacts-master-at-join", false); + + return operation; } - public async void unlink_persona (Contact contact, Persona persona_to_unlink) { + public async LinkOperation unlink_persona (Contact contact, Persona persona_to_unlink) { var individual = contact.individual; var persona_to_unlink_removals = PersonaAttribute.create_set (); var other_personas_removals = PersonaAttribute.create_set (); + var operation = new LinkOperation (); + operation.set_main_contact (contact); + foreach (PersonaAttribute a1 in get_linkable_attributes (persona_to_unlink)) { // Check that this attribute actually is used to link this persona to the individual bool used_to_link = false; @@ -552,9 +680,10 @@ namespace Contacts { try { main_persona = yield contact.store.aggregator.primary_store.add_persona_from_details (details); yield (main_persona as NameDetails).change_full_name (contact.display_name); + operation.added_persona (main_persona); } catch (GLib.Error e) { warning ("Unable to create new persona when unlinking: %s\n", e.message); - return; + return operation; } } @@ -563,13 +692,15 @@ namespace Contacts { // First apply all additions on the primary persona so that we avoid temporarily being // unlinked and then relinked if (main_persona != null) - yield persona_apply_attributes (main_persona, main_persona_additions, other_personas_removals); + yield persona_apply_attributes (main_persona, main_persona_additions, other_personas_removals, operation); foreach (var p in other_personas) { - yield persona_apply_attributes (p, null, other_personas_removals); + yield persona_apply_attributes (p, null, other_personas_removals, operation); } // Last we do the removals on the persona_to_unlink - yield persona_apply_attributes (persona_to_unlink, null, persona_to_unlink_removals); + yield persona_apply_attributes (persona_to_unlink, null, persona_to_unlink_removals, operation); persona_to_unlink.set_data ("contacts-new-contact", false); + + return operation; } } |