[geocode-glib] geocode-backend: Add support for multiple reverse results



commit 2a8d8e40ed3710db967d066f601bb0da6e901df1
Author: Philip Withnall <philip withnall collabora co uk>
Date:   Thu Oct 13 14:37:32 2016 +0100

    geocode-backend: Add support for multiple reverse results
    
    Some geocoding APIs (such as the Google Geocoding API) can return
    multiple results for a reverse resolution request, such as the building
    at that location, the street it is on, the town it is in, etc.
    
    While we currently only support Nominatim, other backends may be added
    (potentially out of tree) in future. Change the GeocodeBackend API to
    allow them to return multiple reverse results.
    
    This does not change the GeocodeReverse API, which returns the first
    result in the list, which should be the most relevant one.
    
    https://developers.google.com/maps/documentation/geocoding/intro#ReverseGeocoding
    
    https://bugzilla.gnome.org/show_bug.cgi?id=756311

 geocode-glib/geocode-backend.c   |   33 +++++++++++++++++++++------------
 geocode-glib/geocode-backend.h   |    8 ++++----
 geocode-glib/geocode-nominatim.c |   24 ++++++++++++++++--------
 geocode-glib/geocode-reverse.c   |   35 +++++++++++++++++++++++++++--------
 4 files changed, 68 insertions(+), 32 deletions(-)
---
diff --git a/geocode-glib/geocode-backend.c b/geocode-glib/geocode-backend.c
index bd26feb..febe33f 100644
--- a/geocode-glib/geocode-backend.c
+++ b/geocode-glib/geocode-backend.c
@@ -186,12 +186,14 @@ geocode_backend_reverse_resolve_async (GeocodeBackend      *backend,
  *
  * Finishes a reverse geocoding operation. See geocode_backend_reverse_resolve_async().
  *
- * Returns: (transfer full): A #GeocodePlace instance, or %NULL in case of
- * errors. Free the returned instance with g_object_unref() when done.
+ * Returns: (transfer full) (element-type GeocodePlace): A list of
+ *    #GeocodePlace instances, or %NULL in case of errors. The list is ordered
+ *    by relevance, with most relevant results first. Free the returned
+ *    instances with g_object_unref() and the list with g_list_free() when done.
  *
  * Since: UNRELEASED
  **/
-GeocodePlace *
+GList *
 geocode_backend_reverse_resolve_finish (GeocodeBackend  *backend,
                                         GAsyncResult    *result,
                                         GError         **error)
@@ -214,14 +216,20 @@ geocode_backend_reverse_resolve_finish (GeocodeBackend  *backend,
  * @cancellable: optional #GCancellable object, %NULL to ignore.
  * @error: a #GError.
  *
- * Gets the result of a reverse geocoding query using the @backend.
+ * 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.
  *
- * Returns: (transfer full): A #GeocodePlace instance, or %NULL in case of
- * errors. Free the returned instance with g_object_unref() when done.
+ * Returns: (transfer full) (element-type GeocodePlace): A list of
+ *    #GeocodePlace instances, or %NULL in case of errors. The list is ordered
+ *    by relevance, with most relevant results first. Free the returned
+ *    instances with g_object_unref() and the list with g_list_free() when done.
  *
  * Since: UNRELEASED
  */
-GeocodePlace *
+GList *
 geocode_backend_reverse_resolve (GeocodeBackend   *backend,
                                  GeocodeLocation  *location,
                                  GCancellable     *cancellable,
@@ -305,14 +313,15 @@ reverse_resolve_async_thread (GTask           *task,
                               GCancellable    *cancellable)
 {
        GError *error = NULL;
-       GeocodePlace *place;
+       GList *places;  /* (element-type GeocodePlace) */
 
-       place = geocode_backend_reverse_resolve (backend, location,
-                                                cancellable, &error);
+       places = geocode_backend_reverse_resolve (backend, location,
+                                                 cancellable, &error);
        if (error)
                g_task_return_error (task, error);
        else
-               g_task_return_pointer (task, place, g_object_unref);
+               g_task_return_pointer (task, places,
+                                      (GDestroyNotify) places_list_free);
 }
 
 static void
@@ -330,7 +339,7 @@ real_reverse_resolve_async (GeocodeBackend      *backend,
        g_object_unref (task);
 }
 
-static GeocodePlace *
+static GList *
 real_reverse_resolve_finish (GeocodeBackend  *backend,
                              GAsyncResult    *result,
                              GError         **error)
diff --git a/geocode-glib/geocode-backend.h b/geocode-glib/geocode-backend.h
index 98d2443..a003826 100644
--- a/geocode-glib/geocode-backend.h
+++ b/geocode-glib/geocode-backend.h
@@ -77,7 +77,7 @@ struct _GeocodeBackendInterface
                                                  GError              **error);
 
        /* Reverse */
-       GeocodePlace *(*reverse_resolve)         (GeocodeBackend       *backend,
+       GList        *(*reverse_resolve)         (GeocodeBackend       *backend,
                                                  GeocodeLocation      *location,
                                                  GCancellable         *cancellable,
                                                  GError              **error);
@@ -86,7 +86,7 @@ struct _GeocodeBackendInterface
                                                  GCancellable         *cancellable,
                                                  GAsyncReadyCallback   callback,
                                                  gpointer              user_data);
-       GeocodePlace *(*reverse_resolve_finish)  (GeocodeBackend       *backend,
+       GList        *(*reverse_resolve_finish)  (GeocodeBackend       *backend,
                                                  GAsyncResult         *result,
                                                  GError              **error);
 
@@ -114,10 +114,10 @@ void          geocode_backend_reverse_resolve_async  (GeocodeBackend       *back
                                                       GCancellable         *cancellable,
                                                       GAsyncReadyCallback   callback,
                                                       gpointer              user_data);
-GeocodePlace *geocode_backend_reverse_resolve_finish (GeocodeBackend       *backend,
+GList        *geocode_backend_reverse_resolve_finish (GeocodeBackend       *backend,
                                                       GAsyncResult         *result,
                                                       GError              **error);
-GeocodePlace *geocode_backend_reverse_resolve        (GeocodeBackend       *backend,
+GList        *geocode_backend_reverse_resolve        (GeocodeBackend       *backend,
                                                       GeocodeLocation      *location,
                                                       GCancellable         *cancellable,
                                                       GError              **error);
diff --git a/geocode-glib/geocode-nominatim.c b/geocode-glib/geocode-nominatim.c
index aade593..b351b30 100644
--- a/geocode-glib/geocode-nominatim.c
+++ b/geocode-glib/geocode-nominatim.c
@@ -984,12 +984,12 @@ _geocode_location_to_params (GeocodeLocation *location)
        return ht;
 }
 
-static GeocodePlace *
+static GList *
 geocode_nominatim_reverse_resolve_finish (GeocodeBackend  *backend,
                                           GAsyncResult    *res,
                                           GError         **error)
 {
-       return GEOCODE_PLACE (g_task_propagate_pointer (G_TASK (res), error));
+       return g_task_propagate_pointer (G_TASK (res), error);
 }
 
 static void
@@ -1150,13 +1150,19 @@ resolve_json (const char  *contents,
 }
 
 static void
+places_list_free (GList *places)
+{
+       g_list_free_full (places, g_object_unref);
+}
+
+static void
 on_reverse_query_ready (GeocodeNominatim *self,
                         GAsyncResult     *res,
                         GTask            *task)
 {
        GError *error = NULL;
        char *contents;
-       GeocodePlace *ret;
+       g_autoptr (GeocodePlace) place = NULL;
        GHashTable *attributes;
 
        contents = GEOCODE_NOMINATIM_GET_CLASS (self)->query_finish (GEOCODE_NOMINATIM (self), res, &error);
@@ -1175,10 +1181,12 @@ on_reverse_query_ready (GeocodeNominatim *self,
                return;
        }
 
-       ret = _geocode_create_place_from_attributes (attributes);
+       place = _geocode_create_place_from_attributes (attributes);
        g_hash_table_unref (attributes);
 
-       g_task_return_pointer (task, ret, g_object_unref);
+       g_task_return_pointer (task,
+                              g_list_prepend (NULL, g_object_ref (place)),
+                              (GDestroyNotify) places_list_free);
        g_object_unref (task);
 }
 
@@ -1210,7 +1218,7 @@ geocode_nominatim_reverse_resolve_async (GeocodeBackend      *self,
        g_free (uri);
 }
 
-static GeocodePlace *
+static GList *
 geocode_nominatim_reverse_resolve (GeocodeBackend   *self,
                                    GeocodeLocation  *location,
                                    GCancellable     *cancellable,
@@ -1219,7 +1227,7 @@ geocode_nominatim_reverse_resolve (GeocodeBackend   *self,
        char *contents;
        GHashTable *ht;
        GHashTable *result = NULL;
-       GeocodePlace *place;
+       g_autoptr (GeocodePlace) place = NULL;
        gchar *uri = NULL;
 
        g_return_val_if_fail (GEOCODE_IS_BACKEND (self), NULL);
@@ -1246,7 +1254,7 @@ geocode_nominatim_reverse_resolve (GeocodeBackend   *self,
        place = _geocode_create_place_from_attributes (result);
        g_hash_table_unref (result);
 
-       return place;
+       return g_list_prepend (NULL, g_object_ref (place));
 }
 
 /******************************************************************************/
diff --git a/geocode-glib/geocode-reverse.c b/geocode-glib/geocode-reverse.c
index a20ce16..43d3b77 100644
--- a/geocode-glib/geocode-reverse.c
+++ b/geocode-glib/geocode-reverse.c
@@ -110,19 +110,28 @@ ensure_backend (GeocodeReverse *object)
 }
 
 static void
+places_list_free (GList *places)
+{
+       g_list_free_full (places, g_object_unref);
+}
+
+static void
 backend_reverse_resolve_ready (GeocodeBackend *backend,
                                GAsyncResult   *res,
                                GTask          *task)
 {
-       GeocodePlace *place;
+       GList *places = NULL;  /* (element-type GeocodePlace) */
        GError *error = NULL;
 
-       place = geocode_backend_reverse_resolve_finish (backend, res, &error);
-       if (place)
-               g_task_return_pointer (task, place, g_object_unref);
+       /* Extract the first result from the list and return that. */
+       places = geocode_backend_reverse_resolve_finish (backend, res, &error);
+       if (places != NULL)
+               g_task_return_pointer (task, g_object_ref (places->data),
+                                      g_object_unref);
        else
                g_task_return_error (task, error);
        g_object_unref (task);
+       g_clear_pointer (&places, places_list_free);
 }
 
 /**
@@ -200,16 +209,26 @@ GeocodePlace *
 geocode_reverse_resolve (GeocodeReverse *object,
                          GError        **error)
 {
+       GList *places = NULL;  /* (element-type GeocodePlace) */
+       GeocodePlace *place = NULL;
+
        g_return_val_if_fail (GEOCODE_IS_REVERSE (object), NULL);
        g_return_val_if_fail (error == NULL || *error == NULL, NULL);
 
        ensure_backend (object);
        g_assert (object->priv->backend != NULL);
 
-       return geocode_backend_reverse_resolve (object->priv->backend,
-                                               object->priv->location,
-                                               NULL,
-                                               error);
+       places = geocode_backend_reverse_resolve (object->priv->backend,
+                                                 object->priv->location,
+                                                 NULL,
+                                                 error);
+
+       if (places != NULL)
+               place = g_object_ref (places->data);
+
+       g_list_free_full (places, g_object_unref);
+
+       return place;
 }
 
 /**


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