[folks] core: Add FavouriteDetails.change_is_favourite()



commit 073dc310a0294bf5c26f2e31ebf4073a543db0f6
Author: Philip Withnall <philip tecnocode co uk>
Date:   Sun Aug 28 20:19:09 2011 +0100

    core: Add FavouriteDetails.change_is_favourite()
    
    This allows the favouriteness of an implementing class to be changed
    asynchronously with proper error notification.
    
    Helps: bgo#657510

 backends/telepathy/lib/tpf-persona-store.vala |    8 ++--
 backends/telepathy/lib/tpf-persona.vala       |   26 ++++++++--
 backends/tracker/lib/trf-persona.vala         |   41 ++++++++++------
 folks/favourite-details.vala                  |   21 ++++++++
 folks/individual.vala                         |   65 ++++++++++++++++++++-----
 po/POTFILES.in                                |    1 +
 po/POTFILES.skip                              |    1 +
 7 files changed, 125 insertions(+), 38 deletions(-)
---
diff --git a/backends/telepathy/lib/tpf-persona-store.vala b/backends/telepathy/lib/tpf-persona-store.vala
index 3346f9e..37532c8 100644
--- a/backends/telepathy/lib/tpf-persona-store.vala
+++ b/backends/telepathy/lib/tpf-persona-store.vala
@@ -1972,17 +1972,16 @@ public class Tpf.PersonaStore : Folks.PersonaStore
    * Telepathy logger service, so may fail if that connection is not present.
    */
   internal async void change_is_favourite (Folks.Persona persona,
-      bool is_favourite)
+      bool is_favourite) throws PropertyError
     {
       /* It's possible for us to not be able to connect to the logger;
        * see _connection_ready_cb() */
       if (this._logger == null)
         {
-          warning (
+          throw new PropertyError.UNKNOWN_ERROR (
               /* Translators: "telepathy-logger" is the name of an application,
                * and should not be translated. */
               _("Failed to change favorite without a connection to the telepathy-logger service."));
-          return;
         }
 
       try
@@ -1998,7 +1997,8 @@ public class Tpf.PersonaStore : Folks.PersonaStore
         }
       catch (GLib.Error e)
         {
-          warning (_("Failed to change a persona's favorite status."));
+          throw new PropertyError.UNKNOWN_ERROR (
+              _("Failed to change a persona's favorite status."));
         }
     }
 
diff --git a/backends/telepathy/lib/tpf-persona.vala b/backends/telepathy/lib/tpf-persona.vala
index b5fa21e..73aed69 100644
--- a/backends/telepathy/lib/tpf-persona.vala
+++ b/backends/telepathy/lib/tpf-persona.vala
@@ -163,19 +163,33 @@ public class Tpf.Persona : Folks.Persona,
    *
    * See { link Folks.FavouriteDetails.is_favourite}.
    */
+  [CCode (notify = false)]
   public bool is_favourite
     {
       get { return this._is_favourite; }
+      set { this.change_is_favourite.begin (value); }
+    }
 
-      set
+  /**
+   * { inheritDoc}
+   *
+   * @since UNRELEASED
+   */
+  public async void change_is_favourite (bool is_favourite) throws PropertyError
+    {
+      if (this._is_favourite == is_favourite)
         {
-          if (this._is_favourite == value)
-            return;
+          return;
+        }
 
-          if (this._is_constructed)
-            ((Tpf.PersonaStore) this.store).change_is_favourite (this, value);
-          this._is_favourite = value;
+      if (this._is_constructed)
+        {
+          yield ((Tpf.PersonaStore) this.store).change_is_favourite (this,
+              is_favourite);
         }
+
+      this._is_favourite = is_favourite;
+      this.notify_property ("is-favourite");
     }
 
   /**
diff --git a/backends/tracker/lib/trf-persona.vala b/backends/tracker/lib/trf-persona.vala
index 26ffdbb..0076197 100644
--- a/backends/tracker/lib/trf-persona.vala
+++ b/backends/tracker/lib/trf-persona.vala
@@ -332,23 +332,29 @@ public class Trf.Persona : Folks.Persona,
   /**
    * Whether this contact is a user-defined favourite.
    */
+  [CCode (notify = false)]
   public bool is_favourite
       {
         get { return this._is_favourite; }
-
-        set
-          {
-            if (this._is_favourite == value)
-              return;
-
-            /* Note:
-             * this property will be set (and notified)
-             * once we receive a notification event from Tracker
-             */
-            ((Trf.PersonaStore) this.store)._set_is_favourite (this, value);
-          }
+        set { this.change_is_favourite.begin (value); }
       }
 
+  /**
+   * { inheritDoc}
+   *
+   * @since UNRELEASED
+   */
+  public async void change_is_favourite (bool is_favourite) throws PropertyError
+    {
+      if (this._is_favourite == is_favourite)
+        {
+          return;
+        }
+
+      yield ((Trf.PersonaStore) this.store)._set_is_favourite (this,
+          is_favourite);
+    }
+
   private HashSet<string> _local_ids;
   private Set<string> _local_ids_ro;
 
@@ -1259,8 +1265,7 @@ public class Trf.Persona : Folks.Persona,
   private void _update_favourite ()
     {
       var favourite = this._cursor.get_string (Trf.Fields.FAVOURITE).dup ();
-
-      this._is_favourite = false;
+      var is_favourite = false;
 
       if (favourite != null)
         {
@@ -1270,10 +1275,16 @@ public class Trf.Persona : Folks.Persona,
             {
               if (int.parse (tag) == favorite_tracker_id)
                 {
-                  this._is_favourite = true;
+                  is_favourite = true;
                 }
             }
         }
+
+      if (is_favourite != this._is_favourite)
+        {
+          this._is_favourite = is_favourite;
+          this.notify_property ("is-favourite");
+        }
     }
 
   /**
diff --git a/folks/favourite-details.vala b/folks/favourite-details.vala
index c1f0fa2..8618c1c 100644
--- a/folks/favourite-details.vala
+++ b/folks/favourite-details.vala
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2010 Collabora Ltd.
+ * Copyright (C) 2011 Philip Withnall
  *
  * This library is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Lesser General Public License as published by
@@ -30,4 +31,24 @@ public interface Folks.FavouriteDetails : Object
    * Whether this contact is a user-defined favourite.
    */
   public abstract bool is_favourite { get; set; }
+
+  /**
+   * Change whether the contact is a user-defined favourite.
+   *
+   * It's preferred to call this rather than setting
+   * { link FavouriteDetails.is_favourite} directly, as this method gives error
+   * notification and will only return once the favouriteness has been written
+   * to the relevant backing store (or the operation's failed).
+   *
+   * @param is_favourite `true` if the contact is a favourite; `false` otherwise
+   * @throws PropertyError if setting the favouriteness failed
+   * @since UNRELEASED
+   */
+  public virtual async void change_is_favourite (bool is_favourite)
+      throws PropertyError
+    {
+      /* Default implementation. */
+      throw new PropertyError.NOT_WRITEABLE (
+          _("Favourite status is not writeable on this contact."));
+    }
 }
diff --git a/folks/individual.vala b/folks/individual.vala
index 9823148..850fa64 100644
--- a/folks/individual.vala
+++ b/folks/individual.vala
@@ -492,31 +492,70 @@ public class Folks.Individual : Object,
    * This property is `true` if any of this Individual's { link Persona}s are
    * favourites).
    */
+  [CCode (notify = false)]
   public bool is_favourite
     {
       get { return this._is_favourite; }
+      set { this.change_is_favourite.begin (value); }
+    }
 
-      set
+  /**
+   * { inheritDoc}
+   *
+   * @since UNRELEASED
+   */
+  public async void change_is_favourite (bool is_favourite) throws PropertyError
+    {
+      if (this._is_favourite == is_favourite)
         {
-          if (this._is_favourite == value)
-            return;
+          return;
+        }
 
-          debug ("Setting '%s' favourite status to %s", this.id,
-              value ? "TRUE" : "FALSE");
+      debug ("Setting '%s' favourite status to %sâ", this.id,
+        is_favourite ? "TRUE" : "FALSE");
 
-          this._is_favourite = value;
-          foreach (var p in this._persona_set)
+      PropertyError? persona_error = null;
+      var is_favourite_changed = false;
+
+      /* Try to write it to only the Personas which have "is-favourite" as a
+       * writeable property.
+       *
+       * NOTE: We don't check whether the persona's store is writeable, as we
+       * want is-favourite status to propagate to all stores, if possible. This
+       * is one property which is harmless to propagate. */
+      foreach (var p in this._persona_set)
+        {
+          var a = p as FavouriteDetails;
+          if (a != null && "is-favourite" in p.writeable_properties)
             {
-              if (p is FavouriteDetails)
+              try
                 {
-                  SignalHandler.block_by_func (p,
-                      (void*) this._notify_is_favourite_cb, this);
-                  ((FavouriteDetails) p).is_favourite = value;
-                  SignalHandler.unblock_by_func (p,
-                      (void*) this._notify_is_favourite_cb, this);
+                  yield a.change_is_favourite (is_favourite);
+                  debug ("    written to persona '%s'", p.uid);
+                  is_favourite_changed = true;
+                }
+              catch (PropertyError e)
+                {
+                  /* Store the first error so we can throw it if setting the
+                   * property fails on every other persona. */
+                  if (persona_error == null)
+                    {
+                      persona_error = e;
+                    }
                 }
             }
         }
+
+      /* Failure? */
+      if (is_favourite_changed == false)
+        {
+          assert (persona_error != null);
+          throw persona_error;
+        }
+
+      /* Update our copy of the property. */
+      this._is_favourite = is_favourite;
+      this.notify_property ("is-favourite");
     }
 
   /**
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 72120ca..839882e 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -12,6 +12,7 @@ folks/avatar-details.vala
 folks/backend-store.vala
 folks/birthday-details.vala
 folks/email-details.vala
+folks/favourite-details.vala
 folks/im-details.vala
 folks/individual-aggregator.vala
 folks/postal-address-details.vala
diff --git a/po/POTFILES.skip b/po/POTFILES.skip
index 321fa71..8adfe1c 100644
--- a/po/POTFILES.skip
+++ b/po/POTFILES.skip
@@ -11,6 +11,7 @@ folks/avatar-details.c
 folks/backend-store.c
 folks/birthday-details.c
 folks/email-details.c
+folks/favourite-details.c
 folks/im-details.c
 folks/individual-aggregator.c
 folks/postal-address-details.c



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]