Commit ef3d3b73 authored by Philip Withnall's avatar Philip Withnall
Browse files

core: Add AliasDetails.change_alias()

This allows the alias of an implementing class to be changed asynchronously
with proper error notification.

Helps: bgo#657510
parent be2f0140
......@@ -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);
}
}
......@@ -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");
}
/**
......
......@@ -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");
}
/**
......
/*
* 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."));
}
}
/*
* 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");
}
/**
......
......@@ -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
......
......@@ -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
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment