Commit 4c27e04b authored by Philip Withnall's avatar Philip Withnall Committed by Philip Withnall
Browse files

geocode-glib: Accept a hash table for GeocodeBackend.reverse_resolve()

Instead of only accepting a GeocodeLocation, accept a hash table of
string keys and GValues. Typically, this will contain `lat` and `lon`
entries which represent the GeocodeLocation. But in future, it could
contain other keys to look up a GeocodePlace by its backend-specific ID,
for example; or to limit the search results by place type.

Whether the keys are static or non-static is decided by the caller.

This changes the API in GeocodeBackend (which is not stable yet), but
not in GeocodeReverse, so it’s not an API break.

https://bugzilla.gnome.org/show_bug.cgi?id=756311
parent f97421f6
......@@ -145,14 +145,26 @@ geocode_backend_forward_search (GeocodeBackend *backend,
/**
* geocode_backend_reverse_resolve_async:
* @backend: a #GeocodeBackend.
* @location: a #GeocodeLocation.
* @params: (transfer none) (element-type utf8 GValue): a #GHashTable with string keys, and #GValue values.
* @cancellable: optional #GCancellable object, %NULL to ignore.
* @callback: a #GAsyncReadyCallback to call when the request is satisfied.
* @user_data: the data to pass to callback function.
*
* Asynchronously gets the result of a reverse geocoding query using the
* backend. Use geocode_backend_reverse_resolve() to do the same thing
* synchronously.
* backend.
*
* Typically, a single result will be returned representing the place at a
* given latitude and longitude (the `lat` and `lon` keys to @params); but in
* some cases the results will be ambiguous and *multiple* results will be
* returned. They will be returned in order of relevance, with the most
* relevant result first in the list.
*
* The @params hash table is in the format used by Telepathy, and documented
* in the [Telepathy specification](http://telepathy.freedesktop.org/spec/Connection_Interface_Location.html#Mapping:Location).
*
* See also: [XEP-0080 specification](http://xmpp.org/extensions/xep-0080.html).
*
* Use geocode_backend_reverse_resolve() to do the same thing synchronously.
*
* When the operation is finished, @callback will be called. You can then call
* geocode_backend_reverse_resolve_finish() to get the result of the operation.
......@@ -161,7 +173,7 @@ geocode_backend_forward_search (GeocodeBackend *backend,
*/
void
geocode_backend_reverse_resolve_async (GeocodeBackend *backend,
GeocodeLocation *location,
GHashTable *params,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
......@@ -169,12 +181,12 @@ geocode_backend_reverse_resolve_async (GeocodeBackend *backend,
GeocodeBackendInterface *iface;
g_return_if_fail (GEOCODE_IS_BACKEND (backend));
g_return_if_fail (GEOCODE_IS_LOCATION (location));
g_return_if_fail (params != NULL);
g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
iface = GEOCODE_BACKEND_GET_IFACE (backend);
return (* iface->reverse_resolve_async) (backend, location,
return (* iface->reverse_resolve_async) (backend, params,
cancellable, callback, user_data);
}
......@@ -212,15 +224,16 @@ geocode_backend_reverse_resolve_finish (GeocodeBackend *backend,
/**
* geocode_backend_reverse_resolve:
* @backend: a #GeocodeBackend.
* @location: a #GeocodeLocation.
* @params: (transfer none) (element-type utf8 GValue): a #GHashTable with string keys, and #GValue values.
* @cancellable: optional #GCancellable object, %NULL to ignore.
* @error: a #GError.
*
* Gets the result of a reverse geocoding query using the @backend. Typically, a
* single result will be returned representing the place at the given location;
* but in some cases the results will be ambiguous and multiple results will
* be returned. They will be returned in order of relevance, with the most
* relevant result first in the list.
* Gets the result of a reverse geocoding query using the @backend.
*
* This is a synchronous function, which means it may block on network requests.
* In most situations, the asynchronous version,
* geocode_backend_forward_search_async(), is more appropriate. See its
* documentation for more information on usage.
*
* Returns: (transfer full) (element-type GeocodePlace): A list of
* #GeocodePlace instances, or %NULL in case of errors. The list is ordered
......@@ -231,14 +244,14 @@ geocode_backend_reverse_resolve_finish (GeocodeBackend *backend,
*/
GList *
geocode_backend_reverse_resolve (GeocodeBackend *backend,
GeocodeLocation *location,
GHashTable *params,
GCancellable *cancellable,
GError **error)
{
GeocodeBackendInterface *iface;
g_return_val_if_fail (GEOCODE_IS_BACKEND (backend), NULL);
g_return_val_if_fail (GEOCODE_IS_LOCATION (location), NULL);
g_return_val_if_fail (params != NULL, NULL);
g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
......@@ -254,7 +267,7 @@ geocode_backend_reverse_resolve (GeocodeBackend *backend,
return NULL;
}
return (* iface->reverse_resolve) (backend, location,
return (* iface->reverse_resolve) (backend, params,
cancellable, error);
}
......@@ -309,13 +322,13 @@ real_forward_search_finish (GeocodeBackend *backend,
static void
reverse_resolve_async_thread (GTask *task,
GeocodeBackend *backend,
GeocodeLocation *location,
GHashTable *params,
GCancellable *cancellable)
{
GError *error = NULL;
GList *places; /* (element-type GeocodePlace) */
places = geocode_backend_reverse_resolve (backend, location,
places = geocode_backend_reverse_resolve (backend, params,
cancellable, &error);
if (error)
g_task_return_error (task, error);
......@@ -326,7 +339,7 @@ reverse_resolve_async_thread (GTask *task,
static void
real_reverse_resolve_async (GeocodeBackend *backend,
GeocodeLocation *location,
GHashTable *params,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
......@@ -334,7 +347,8 @@ real_reverse_resolve_async (GeocodeBackend *backend,
GTask *task;
task = g_task_new (backend, cancellable, callback, user_data);
g_task_set_task_data (task, g_object_ref (location), g_object_unref);
g_task_set_task_data (task, g_hash_table_ref (params),
(GDestroyNotify) g_hash_table_unref);
g_task_run_in_thread (task, (GTaskThreadFunc) reverse_resolve_async_thread);
g_object_unref (task);
}
......
......@@ -78,11 +78,11 @@ struct _GeocodeBackendInterface
/* Reverse */
GList *(*reverse_resolve) (GeocodeBackend *backend,
GeocodeLocation *location,
GHashTable *params,
GCancellable *cancellable,
GError **error);
void (*reverse_resolve_async) (GeocodeBackend *backend,
GeocodeLocation *location,
GHashTable *params,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
......@@ -110,7 +110,7 @@ GList *geocode_backend_forward_search (GeocodeBackend *backe
/* Reverse geocoding operations */
void geocode_backend_reverse_resolve_async (GeocodeBackend *backend,
GeocodeLocation *location,
GHashTable *params,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
......@@ -118,7 +118,7 @@ GList *geocode_backend_reverse_resolve_finish (GeocodeBackend *back
GAsyncResult *result,
GError **error);
GList *geocode_backend_reverse_resolve (GeocodeBackend *backend,
GeocodeLocation *location,
GHashTable *params,
GCancellable *cancellable,
GError **error);
......
......@@ -783,17 +783,33 @@ _geocode_glib_dup_hash_table (GHashTable *ht)
}
static gchar *
get_resolve_uri_for_params (GeocodeNominatim *self,
GHashTable *orig_ht)
get_resolve_uri_for_params (GeocodeNominatim *self,
GHashTable *orig_ht,
GError **error)
{
GHashTable *ht;
char *locale;
char *params, *uri;
GeocodeNominatimPrivate *priv;
const GValue *lat, *lon;
priv = geocode_nominatim_get_instance_private (self);
ht = _geocode_glib_dup_hash_table (orig_ht);
/* Make sure we have both lat and lon. */
lat = g_hash_table_lookup (orig_ht, "lat");
lon = g_hash_table_lookup (orig_ht, "lon");
if (lat == NULL || lon == NULL) {
g_set_error_literal (error, GEOCODE_ERROR, GEOCODE_ERROR_INVALID_ARGUMENTS,
"Only following parameters supported: lat, lon");
return NULL;
}
ht = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL);
g_hash_table_insert (ht, (gpointer) "lat", (gpointer) g_value_get_string (lat));
g_hash_table_insert (ht, (gpointer) "lon", (gpointer) g_value_get_string (lon));
g_hash_table_insert (ht, (gpointer) "format", (gpointer) "json");
g_hash_table_insert (ht, (gpointer) "email",
......@@ -961,29 +977,6 @@ geocode_nominatim_query (GeocodeNominatim *self,
/******************************************************************************/
static GHashTable *
_geocode_location_to_params (GeocodeLocation *location)
{
GHashTable *ht;
char coord[G_ASCII_DTOSTR_BUF_SIZE];
char *lat;
char *lon;
lat = g_strdup (g_ascii_dtostr (coord,
G_ASCII_DTOSTR_BUF_SIZE,
geocode_location_get_latitude (location)));
lon = g_strdup (g_ascii_dtostr (coord,
G_ASCII_DTOSTR_BUF_SIZE,
geocode_location_get_longitude (location)));
ht = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
g_hash_table_insert (ht, g_strdup ("lat"), lat);
g_hash_table_insert (ht, g_strdup ("lon"), lon);
return ht;
}
static GList *
geocode_nominatim_reverse_resolve_finish (GeocodeBackend *backend,
GAsyncResult *res,
......@@ -1192,21 +1185,25 @@ on_reverse_query_ready (GeocodeNominatim *self,
static void
geocode_nominatim_reverse_resolve_async (GeocodeBackend *self,
GeocodeLocation *location,
GHashTable *params,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
GTask *task;
GHashTable *ht;
gchar *uri = NULL;
GError *error = NULL;
g_return_if_fail (GEOCODE_IS_BACKEND (self));
g_return_if_fail (GEOCODE_IS_LOCATION (location));
g_return_if_fail (params != NULL);
ht = _geocode_location_to_params (location);
uri = get_resolve_uri_for_params (GEOCODE_NOMINATIM (self), ht);
g_hash_table_unref (ht);
uri = get_resolve_uri_for_params (GEOCODE_NOMINATIM (self), params,
&error);
if (error != NULL) {
g_task_report_error (self, callback, user_data, NULL, error);
return;
}
task = g_task_new (self, cancellable, callback, user_data);
GEOCODE_NOMINATIM_GET_CLASS (self)->query_async (GEOCODE_NOMINATIM (self),
......@@ -1219,23 +1216,24 @@ geocode_nominatim_reverse_resolve_async (GeocodeBackend *self,
}
static GList *
geocode_nominatim_reverse_resolve (GeocodeBackend *self,
GeocodeLocation *location,
GCancellable *cancellable,
GError **error)
geocode_nominatim_reverse_resolve (GeocodeBackend *self,
GHashTable *params,
GCancellable *cancellable,
GError **error)
{
char *contents;
GHashTable *ht;
GHashTable *result = NULL;
g_autoptr (GeocodePlace) place = NULL;
gchar *uri = NULL;
g_return_val_if_fail (GEOCODE_IS_BACKEND (self), NULL);
g_return_val_if_fail (GEOCODE_IS_LOCATION (location), NULL);
g_return_val_if_fail (params != NULL, NULL);
ht = _geocode_location_to_params (location);
uri = get_resolve_uri_for_params (GEOCODE_NOMINATIM (self), ht);
g_hash_table_unref (ht);
uri = get_resolve_uri_for_params (GEOCODE_NOMINATIM (self), params,
error);
if (uri == NULL)
return NULL;
contents = GEOCODE_NOMINATIM_GET_CLASS (self)->query (GEOCODE_NOMINATIM (self),
uri,
......
......@@ -109,6 +109,48 @@ ensure_backend (GeocodeReverse *object)
object->priv->backend = GEOCODE_BACKEND (geocode_nominatim_get_gnome ());
}
static GValue *
str_to_value (const gchar *str)
{
GValue *value;
value = g_new0 (GValue, 1);
g_value_init (value, G_TYPE_STRING);
g_value_set_string (value, str);
return value;
}
static void
free_value (GValue *value)
{
g_value_unset (value);
g_free (value);
}
static GHashTable *
_geocode_location_to_params (GeocodeLocation *location)
{
GHashTable *ht;
char lat[G_ASCII_DTOSTR_BUF_SIZE];
char lon[G_ASCII_DTOSTR_BUF_SIZE];
g_ascii_dtostr (lat,
G_ASCII_DTOSTR_BUF_SIZE,
geocode_location_get_latitude (location));
g_ascii_dtostr (lon,
G_ASCII_DTOSTR_BUF_SIZE,
geocode_location_get_longitude (location));
/* Semantics from http://xmpp.org/extensions/xep-0080.html */
ht = g_hash_table_new_full (g_str_hash, g_str_equal, NULL,
(GDestroyNotify) free_value);
g_hash_table_insert (ht, (gpointer) "lat", str_to_value (lat));
g_hash_table_insert (ht, (gpointer) "lon", str_to_value (lon));
return ht;
}
static void
places_list_free (GList *places)
{
......@@ -155,6 +197,7 @@ geocode_reverse_resolve_async (GeocodeReverse *object,
gpointer user_data)
{
GTask *task;
g_autoptr (GHashTable) params = NULL;
g_return_if_fail (GEOCODE_IS_REVERSE (object));
g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
......@@ -162,9 +205,11 @@ geocode_reverse_resolve_async (GeocodeReverse *object,
ensure_backend (object);
g_assert (object->priv->backend != NULL);
params = _geocode_location_to_params (object->priv->location);
task = g_task_new (object, cancellable, callback, user_data);
geocode_backend_reverse_resolve_async (object->priv->backend,
object->priv->location,
params,
cancellable,
(GAsyncReadyCallback) backend_reverse_resolve_ready,
g_object_ref (task));
......@@ -211,6 +256,7 @@ geocode_reverse_resolve (GeocodeReverse *object,
{
GList *places = NULL; /* (element-type GeocodePlace) */
GeocodePlace *place = NULL;
g_autoptr (GHashTable) params = NULL;
g_return_val_if_fail (GEOCODE_IS_REVERSE (object), NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
......@@ -218,8 +264,9 @@ geocode_reverse_resolve (GeocodeReverse *object,
ensure_backend (object);
g_assert (object->priv->backend != NULL);
params = _geocode_location_to_params (object->priv->location);
places = geocode_backend_reverse_resolve (object->priv->backend,
object->priv->location,
params,
NULL,
error);
......
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