[folks] core: Add AliasDetails.change_alias()



commit ef3d3b73d80f7510f8817383a061f544b3ac0367
Author: Philip Withnall <philip tecnocode co uk>
Date:   Sat Aug 27 15:58:30 2011 +0100

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

 backends/eds/lib/edsf-persona-store.vala |   72 ++++++++++++++++++++++++++++++
 backends/key-file/kf-persona.vala        |   26 +++++++---
 backends/telepathy/lib/tpf-persona.vala  |   25 ++++++++---
 folks/alias-details.vala                 |   21 +++++++++
 folks/individual.vala                    |   68 ++++++++++++++++++----------
 po/POTFILES.in                           |    1 +
 po/POTFILES.skip                         |    1 +
 7 files changed, 176 insertions(+), 38 deletions(-)
---
diff --git a/backends/eds/lib/edsf-persona-store.vala b/backends/eds/lib/edsf-persona-store.vala
index 1f11fa6..12b7ceb 100644
--- a/backends/eds/lib/edsf-persona-store.vala
+++ b/backends/eds/lib/edsf-persona-store.vala
@@ -1314,4 +1314,76 @@ public class Edsf.PersonaStore : Folks.PersonaStore
            this._emit_personas_changed (null, removed_personas);
          }
     }
+
+  /* Convert an EClientError or EBookClientError to a Folks.PropertyError for
+   * property modifications. */
+  private PropertyError e_client_error_to_property_error (string property_name,
+      GLib.Error error_in)
+    {
+      if (error_in.domain == BookClient.error_quark ())
+        {
+          switch ((BookClientError) error_in.code)
+            {
+              /* We don't expect to receive any of the error codes below: */
+              case BookClientError.CONTACT_NOT_FOUND:
+              case BookClientError.NO_SUCH_BOOK:
+              case BookClientError.CONTACT_ID_ALREADY_EXISTS:
+              case BookClientError.NO_SUCH_SOURCE:
+              case BookClientError.NO_SPACE:
+              default:
+                /* Fall out */
+                break;
+            }
+        }
+      else if (error_in.domain == Client.error_quark ())
+        {
+          switch ((ClientError) error_in.code)
+            {
+              case ClientError.REPOSITORY_OFFLINE:
+              case ClientError.PERMISSION_DENIED:
+              case ClientError.NOT_SUPPORTED:
+              case ClientError.AUTHENTICATION_REQUIRED:
+                /* TODO: Support authentication. bgo#653339 */
+                return new PropertyError.NOT_WRITEABLE (
+                    /* Translators: the first parameter is a non-human-readable
+                     * property name and the second parameter is an error
+                     * message. */
+                    _("Property â%sâ is not writeable: %s"), property_name,
+                    error_in.message);
+              /* We expect to receive these, but they don't need special
+               * error codes: */
+              case ClientError.INVALID_ARG:
+                return new PropertyError.INVALID_VALUE (
+                    /* Translators: the first parameter is a non-human-readable
+                     * property name and the second parameter is an error
+                     * message. */
+                    _("Invalid value for property â%sâ: %s"), property_name,
+                    error_in.message);
+              case ClientError.BUSY:
+              case ClientError.DBUS_ERROR:
+              case ClientError.OTHER_ERROR:
+                /* Fall through. */
+              /* We don't expect to receive any of the error codes below: */
+              case ClientError.COULD_NOT_CANCEL:
+              case ClientError.AUTHENTICATION_FAILED:
+              case ClientError.TLS_NOT_AVAILABLE:
+              case ClientError.OFFLINE_UNAVAILABLE:
+              case ClientError.UNSUPPORTED_AUTHENTICATION_METHOD:
+              case ClientError.SEARCH_SIZE_LIMIT_EXCEEDED:
+              case ClientError.SEARCH_TIME_LIMIT_EXCEEDED:
+              case ClientError.INVALID_QUERY:
+              case ClientError.QUERY_REFUSED:
+              default:
+                /* Fall out */
+                break;
+            }
+        }
+
+      /* Fallback error. */
+      return new PropertyError.UNKNOWN_ERROR (
+          /* Translators: the first parameter is a non-human-readable
+           * property name and the second parameter is an error message. */
+          _("Unknown error setting property â%sâ: %s"), property_name,
+          error_in.message);
+    }
 }
diff --git a/backends/key-file/kf-persona.vala b/backends/key-file/kf-persona.vala
index 1d3b349..4845bf7 100644
--- a/backends/key-file/kf-persona.vala
+++ b/backends/key-file/kf-persona.vala
@@ -72,22 +72,32 @@ public class Folks.Backends.Kf.Persona : Folks.Persona,
    *
    * @since 0.1.15
    */
+  [CCode (notify = false)]
   public string alias
     {
       get { return this._alias; }
+      set { this.change_alias.begin (value); }
+    }
 
-      set
+  /**
+   * { inheritDoc}
+   *
+   * @since UNRELEASED
+   */
+  public async void change_alias (string alias) throws PropertyError
+    {
+      if (this._alias == alias)
         {
-          if (this._alias == value)
-            return;
+          return;
+        }
 
-          debug ("Setting alias of Kf.Persona '%s' to '%s'.", this.uid, value);
+      debug ("Setting alias of Kf.Persona '%s' to '%s'.", this.uid, alias);
 
-          this._alias = value;
-          this._key_file.set_string (this.display_id, "__alias", value);
+      this._key_file.set_string (this.display_id, "__alias", alias);
+      yield ((Kf.PersonaStore) this.store).save_key_file ();
 
-          ((Kf.PersonaStore) this.store).save_key_file.begin ();
-        }
+      this._alias = alias;
+      this.notify_property ("alias");
     }
 
   /**
diff --git a/backends/telepathy/lib/tpf-persona.vala b/backends/telepathy/lib/tpf-persona.vala
index b929705..307a451 100644
--- a/backends/telepathy/lib/tpf-persona.vala
+++ b/backends/telepathy/lib/tpf-persona.vala
@@ -123,19 +123,32 @@ public class Tpf.Persona : Folks.Persona,
    *
    * See { link Folks.AliasDetails.alias}.
    */
+  [CCode (notify = false)]
   public string alias
     {
       get { return this._alias; }
+      set { this.change_alias.begin (value); }
+    }
 
-      set
+  /**
+   * { inheritDoc}
+   *
+   * @since UNRELEASED
+   */
+  public async void change_alias (string alias) throws PropertyError
+    {
+      if (this._alias == alias)
         {
-          if (this._alias == value)
-            return;
+          return;
+        }
 
-          if (this._is_constructed)
-            ((Tpf.PersonaStore) this.store).change_alias (this, value);
-          this._alias = value;
+      if (this._is_constructed)
+        {
+          yield ((Tpf.PersonaStore) this.store).change_alias (this, alias);
         }
+
+      this._alias = alias;
+      this.notify_property ("alias");
     }
 
   /**
diff --git a/folks/alias-details.vala b/folks/alias-details.vala
index dce661c..e7fac34 100644
--- a/folks/alias-details.vala
+++ b/folks/alias-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
@@ -16,6 +17,7 @@
  *
  * Authors:
  *       Travis Reitter <travis reitter collabora co uk>
+ *       Philip Withnall <philip tecnocode co uk>
  */
 
 using GLib;
@@ -33,4 +35,23 @@ public interface Folks.AliasDetails : Object
    * represent the contact to the user.
    */
   public abstract string alias { get; set; }
+
+  /**
+   * Change the contact's alias.
+   *
+   * It's preferred to call this rather than setting { link AliasDetails.alias}
+   * directly, as this method gives error notification and will only return
+   * once the alias has been written to the relevant backing store (or the
+   * operation's failed).
+   *
+   * @param alias the new alias
+   * @throws PropertyError if setting the alias failed
+   * @since UNRELEASED
+   */
+  public virtual async void change_alias (string alias) throws PropertyError
+    {
+      /* Default implementation. */
+      throw new PropertyError.NOT_WRITEABLE (
+          _("Alias is not writeable on this contact."));
+    }
 }
diff --git a/folks/individual.vala b/folks/individual.vala
index fc57c40..d55e6de 100644
--- a/folks/individual.vala
+++ b/folks/individual.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
@@ -16,6 +17,7 @@
  *
  * Authors:
  *       Travis Reitter <travis reitter collabora co uk>
+ *       Philip Withnall <philip tecnocode co uk>
  */
 
 using Gee;
@@ -197,48 +199,66 @@ public class Folks.Individual : Object,
   /**
    * { inheritDoc}
    */
+  [CCode (notify = false)]
   public string alias
     {
       get { return this._alias; }
+      set { this.change_alias.begin (value); }
+    }
 
-      set
+  /**
+   * { inheritDoc}
+   *
+   * @since UNRELEASED
+   */
+  public async void change_alias (string alias) throws PropertyError
+    {
+      if (this._alias == alias)
         {
-          if (this._alias == value)
-            return;
+          return;
+        }
 
-          this._alias = value;
+      debug ("Setting alias of individual '%s' to '%s'â", this.id, alias);
 
-          debug ("Setting alias of individual '%s' to '%s'â", this.id, value);
+      PropertyError? persona_error = null;
+      var alias_changed = false;
 
-          /* First, try to write it to only the writeable Personasâ */
-          var alias_changed = false;
-          foreach (var p in this._persona_set)
+      /* Try to write it to only the writeable Personas which have "alias"
+       * as a writeable property. */
+      foreach (var p in this._persona_set)
+        {
+          var a = p as AliasDetails;
+          if (a != null && p.store.is_writeable == true &&
+              "alias" in p.writeable_properties)
             {
-              if (p is AliasDetails &&
-                  ((Persona) p).store.is_writeable == true)
+              try
                 {
-                  debug ("    written to writeable persona '%s'",
-                      ((Persona) p).uid);
-                  ((AliasDetails) p).alias = value;
+                  yield a.change_alias (alias);
+                  debug ("    written to writeable persona '%s'", p.uid);
                   alias_changed = true;
                 }
-            }
-
-          /* âbut if there are no writeable Personas, we have to fall back to
-           * writing it to every Persona. */
-          if (alias_changed == false)
-            {
-              foreach (var p in this._persona_set)
+              catch (PropertyError e)
                 {
-                  if (p is AliasDetails)
+                  /* Store the first error so we can throw it if setting the
+                   * alias fails on every other persona. */
+                  if (persona_error == null)
                     {
-                      debug ("    written to non-writeable persona '%s'",
-                          ((Persona) p).uid);
-                      ((AliasDetails) p).alias = value;
+                      persona_error = e;
                     }
                 }
             }
         }
+
+      /* Failure? */
+      if (alias_changed == false)
+        {
+          assert (persona_error != null);
+          throw persona_error;
+        }
+
+      /* Update our copy of the alias. */
+      this._alias = alias;
+      this.notify_property ("alias");
     }
 
   /**
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 7c20f68..f477b87 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -7,6 +7,7 @@ backends/telepathy/lib/tp-lowlevel.c
 backends/telepathy/lib/tpf-persona-store.vala
 backends/telepathy/lib/tpf-persona.vala
 backends/tracker/lib/trf-persona-store.vala
+folks/alias-details.vala
 folks/backend-store.vala
 folks/im-details.vala
 folks/individual-aggregator.vala
diff --git a/po/POTFILES.skip b/po/POTFILES.skip
index 67fd94a..f8ac551 100644
--- a/po/POTFILES.skip
+++ b/po/POTFILES.skip
@@ -6,6 +6,7 @@ backends/telepathy/lib/tpf-persona-store.c
 backends/telepathy/lib/tpf-persona.c
 backends/tracker/lib/trf-persona-store.c
 docs/gtk-doc/folks-telepathy/ccomments/tp-lowlevel.c
+folks/alias-details.c
 folks/backend-store.c
 folks/im-details.c
 folks/individual-aggregator.c



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