[gnome-maps/wip/contacts] wipwip



commit dc918d3db045293b053e904058e343575838f9b0
Author: Jonas Danielsson <jonas threetimestwo org>
Date:   Wed Dec 10 07:00:39 2014 -0500

    wipwip

 configure.ac                                     |    2 +
 lib/Makefile.am                                  |    8 +-
 lib/mapsc-contact-address.c                      |   54 ++++++++
 lib/mapsc-contact-address.h                      |    7 +-
 lib/mapsc-contact.c                              |  154 +++++++++++++++++++--
 lib/mapsc-contact.h                              |   16 ++-
 lib/mapsc-contacts.c                             |   50 ++++----
 src/application.js                               |   25 ++---
 src/busy-marker.ui                               |   24 ++++
 src/busyMarker.js                                |   28 ++++
 src/contact.js                                   |   57 ++++++--
 src/geocodeService.js                            |    1 +
 src/gnome-maps.data.gresource.xml                |    3 +-
 src/gnome-maps.js.gresource.xml                  |    5 +-
 src/mainWindow.js                                |   15 ++
 src/mapBubble.js                                 |    2 +-
 src/mapView.js                                   |   69 ++++++-----
 src/{search-result-bubble.ui => place-bubble.ui} |    0
 src/{searchResultBubble.js => placeBubble.js}    |   19 ++-
 src/{searchResultMarker.js => placeMarker.js}    |   10 +-
 src/utils.js                                     |   27 ++--
 21 files changed, 440 insertions(+), 136 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 794c972..5ecaec1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -37,10 +37,12 @@ PKG_CHECK_MODULES(GNOME_MAPS, [
 
 FOLKS_MIN_VERSION=0.10.0
 GEE_MIN_VERSION=0.16.0
+GEOCODE_MIN_VERSION=3.14
 
 PKG_CHECK_MODULES(MAPSC, [
     gee-0.8                      >= $GEE_MIN_VERSION
     folks                        >= $FOLKS_MIN_VERSION
+    geocode-glib-1.0             >= $GEOCODE_MIN_VERSION
 ])
 AC_SUBST(MAPSC_CFLAGS)
 AC_SUBST(MAPSC_LIBS)
diff --git a/lib/Makefile.am b/lib/Makefile.am
index b2daa53..779a077 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -4,8 +4,8 @@ BUILT_SOURCES = \
                mapsc-enum-types.c \
                mapsc-enum-types.h
 
-libmapsc_headers_public = mapsc-contacts.h mapsc-contact.h mapsc-contact-address.h
-libmapsc_sources = mapsc-contacts.c mapsc-contact.c mapsc-contact-address.c
+libmapsc_headers_public = mapsc-contacts.h mapsc-contact.h
+libmapsc_sources = mapsc-contacts.c mapsc-contact.c
 libmapsc_la_SOURCES = $(libmapsc_sources) $(libmapsc_headers_public) $(BUILT_SOURCES)
 libmapsc_la_LIBADD = $(MAPSC_LIBS)
 
@@ -42,8 +42,8 @@ INTROSPECTION_COMPILER_ARGS =
 
 MapsC-1.0.gir: libmapsc.la
 MapsC_1_0_gir_NAMESPACE = MapsC
-MapsC_1_0_gir_INCLUDES = GLib-2.0 GObject-2.0
-MapsC_1_0_gir_PACKAGES = gobject-2.0
+MapsC_1_0_gir_INCLUDES = GLib-2.0 GObject-2.0 GeocodeGlib-1.0
+MapsC_1_0_gir_PACKAGES = gobject-2.0 geocode-glib-1.0
 MapsC_1_0_gir_FILES = $(libmapsc_la_SOURCES)
 MapsC_1_0_gir_CFLAGS = $(MAPSC_CFLAGS) -I$(top_srcdir) -I$(top_builddir)
 MapsC_1_0_gir_LIBS = libmapsc.la
diff --git a/lib/mapsc-contact-address.c b/lib/mapsc-contact-address.c
index a058d6f..5c2f018 100644
--- a/lib/mapsc-contact-address.c
+++ b/lib/mapsc-contact-address.c
@@ -30,6 +30,12 @@ struct _MapsCContactAddressPrivate {
   char *locality;
   char *postal_code;
   char *street;
+
+  char *osm_id;
+  char *osm_type;
+
+  double latitude;
+  double longitude;
 };
 
 enum {
@@ -276,6 +282,54 @@ mapsc_contact_address_init (MapsCContactAddress *contact)
   contact->priv->region = NULL;
   contact->priv->postal_code = NULL;
   contact->priv->locality = NULL;
+  contact->priv->latitude = -G_MAXDOUBLE;
+  contact->priv->longitude = -G_MAXDOUBLE;
+}
+
+/**
+ * mapsc_contact_address_set_location:
+ * @address: A #MapsCContactAddress object
+ * @latitude: The latitude of the address
+ * @longitude: The longitude of the address
+ * 
+ **/
+void
+mapsc_contact_address_set_location (MapsCContactAddress *address,
+                                    double               latitude,
+                                    double               longitude)
+{
+  g_return_if_fail (address != NULL);
+  g_return_if_fail (MAPSC_IS_CONTACT_ADDRESS (address));
+
+  address->priv->latitude = latitude;
+  address->priv->longitude = longitude;
+}
+
+/**
+ * mapsc_contact_address_get_location:
+ * @address: A #MapsCContactAddress object
+ * @latitude: (out): The latitude of the address
+ * @longitude: (out): The latitude of the address
+ * 
+ * Returns: %TRUE if @address have a location.
+ **/
+gboolean
+mapsc_contact_address_get_location (MapsCContactAddress *address,
+                                    double              *latitude,
+                                    double              *longitude)
+{
+  g_return_if_fail (address != NULL);
+  g_return_if_fail (MAPSC_IS_CONTACT_ADDRESS (address));
+
+  if (address->priv->latitude == -G_MAXDOUBLE ||
+      address->priv->longitude == -G_MAXDOUBLE) {
+    return FALSE;
+  }
+
+  *latitude = address->priv->latitude;
+  *longitude = address->priv->longitude;
+
+  return TRUE;
 }
 
 MapsCContactAddress *
diff --git a/lib/mapsc-contact-address.h b/lib/mapsc-contact-address.h
index b4ecae7..bb0244e 100644
--- a/lib/mapsc-contact-address.h
+++ b/lib/mapsc-contact-address.h
@@ -46,5 +46,10 @@ struct _MapsCContactAddressClass {
 GType mapsc_contact_address_get_type (void);
 
 MapsCContactAddress *mapsc_contact_address_new  (void);
-
+void mapsc_contact_address_set_location         (MapsCContactAddress *address,
+                                                 double               latitude,
+                                                 double               longitude);
+gboolean mapsc_contact_address_get_location     (MapsCContactAddress *address,
+                                                 double              *latitude,
+                                                 double              *longitude);
 #endif
diff --git a/lib/mapsc-contact.c b/lib/mapsc-contact.c
index 54f3796..eed9b7b 100644
--- a/lib/mapsc-contact.c
+++ b/lib/mapsc-contact.c
@@ -20,17 +20,30 @@
 
 
 #include <folks/folks.h>
-#include "mapsc-contact.h"
+#include <geocode-glib/geocode-glib.h>
 
+#include "mapsc-contact.h"
 
 struct _MapsCContactPrivate {
   char *name;
   char *id;
 
   GLoadableIcon *icon;
-  GList *addresses;
+  GList *places;
+
+  GMutex geocode_mutex;
+  guint geocode_counter;
+  guint geocodes_to_perform;
 };
 
+typedef struct {
+  GeocodePlace *place;
+  MapsCContact *contact;
+  MapsCContactGeocodeCallback callback;
+
+  GHashTable *params;
+} GeocodeData;
+
 enum {
   PROP_0,
 
@@ -110,7 +123,7 @@ mapsc_contact_dispose (GObject *object)
   g_clear_pointer (&contact->priv->name, g_free);
   g_clear_pointer (&contact->priv->id, g_free);
   g_clear_object (&contact->priv->icon);
-  g_list_free_full (contact->priv->addresses, g_object_unref);
+  g_list_free_full (contact->priv->places, g_object_unref);
 
   G_OBJECT_CLASS (mapsc_contact_parent_class)->dispose (object);
 }
@@ -173,40 +186,151 @@ mapsc_contact_init (MapsCContact *contact)
   contact->priv->name = NULL;
   contact->priv->id = NULL;
   contact->priv->icon = NULL;
-  contact->priv->addresses = NULL;
+  contact->priv->places = NULL;
+  
+  g_mutex_init (&contact->priv->geocode_mutex);
 }
 
 /**
  * mapsc_contact_add_address:
  * @contact: A #MapsCContact object
- * @address: A #MapsCContactAddress object
+ * @place: A #GeocodePlace object
  *
  **/
 void
-mapsc_contact_add_address (MapsCContact *contact,
-                           MapsCContactAddress *address)
+mapsc_contact_add_place (MapsCContact *contact,
+                         GeocodePlace *place)
 {
   g_return_if_fail (contact != NULL);
   g_return_if_fail (MAPSC_IS_CONTACT (contact));
-  g_return_if_fail (address != NULL);
-  g_return_if_fail (MAPSC_IS_CONTACT_ADDRESS (address));
-
-  contact->priv->addresses = g_list_prepend (contact->priv->addresses, address);
+  g_return_if_fail (place != NULL);
+  g_return_if_fail (GEOCODE_IS_PLACE (place));
+  
+  contact->priv->places = g_list_prepend (contact->priv->places, place);
 }
 
 /**
- * mapsc_contact_get_addresses:
+ * mapsc_contact_get_places:
  * @contact: A #MapsCContact object
  *
- * Returns: (element-type MapsCContactAddress) (transfer container): a list of #MapsCContactAddress
+ * Returns: (element-type GeocodePlace) (transfer container): a list of #GeocodePlace
  **/
 GList *
-mapsc_contact_get_addresses (MapsCContact *contact)
+mapsc_contact_get_places (MapsCContact *contact)
 {
   g_return_if_fail (contact != NULL);
   g_return_if_fail (MAPSC_IS_CONTACT (contact));
 
-  return contact->priv->addresses;
+  return contact->priv->places;
+}
+
+static void
+on_geocode_search_async (GeocodeForward *forward,
+                         GAsyncResult   *res,
+                         GeocodeData    *data)
+{
+  MapsCContact *contact;
+  GList *places;
+  gboolean call_callback = FALSE;
+
+  contact = data->contact;
+  places = geocode_forward_search_finish (forward, res, NULL);
+
+  if (places) {
+    GeocodePlace *place = g_list_nth_data (places, 0);
+    GeocodeLocation *location = geocode_place_get_location (place);
+    const char *street_address;
+    
+    geocode_place_set_location (data->place, location);
+    g_object_set (G_OBJECT (data->place), "osm-type",
+                            geocode_place_get_osm_type (place));
+    g_object_set (G_OBJECT (data->place), "osm-id",
+                            geocode_place_get_osm_id (place));
+
+    street_address = geocode_place_get_street_address (place);
+    if (street_address) {
+      g_object_set (G_OBJECT (data->place), "street-address",
+                    street_address);
+    } else {
+      g_object_set (G_OBJECT (data->place), "street-address",
+                    geocode_place_get_street (place));
+
+    }
+  }
+
+  g_mutex_lock (&contact->priv->geocode_mutex);
+
+  contact->priv->geocode_counter++;
+  if (contact->priv->geocode_counter == contact->priv->geocodes_to_perform)
+    call_callback = TRUE;
+  
+  g_mutex_unlock (&contact->priv->geocode_mutex);
+
+  g_hash_table_destroy (data->params);
+  
+  if (call_callback)
+    data->callback (contact);
+}
+
+static void add_attribute (GHashTable *ht,
+                           const char *key,
+                           const char *s)
+{
+  GValue *value;
+  value = g_new0 (GValue, 1);
+  g_value_init (value, G_TYPE_STRING);
+  g_value_set_static_string (value, s);
+  g_hash_table_insert (ht, g_strdup (key), value);
+
+}
+
+/**
+ * mapsc_contact_geocode:
+ * @contact: A #MapsCContact object
+ * @callback: (scope async): A #MapsCContactGeocodeCallback function
+ *
+ **/
+void
+mapsc_contact_geocode (MapsCContact *contact,
+                       MapsCContactGeocodeCallback callback)
+{
+  g_return_if_fail (contact != NULL);
+  g_return_if_fail (MAPSC_IS_CONTACT (contact));
+  g_return_if_fail (callback != NULL);
+
+  GeocodeForward *forward;
+  GList *l;
+
+  contact->priv->geocode_counter = 0;
+  contact->priv->geocodes_to_perform = g_list_length (contact->priv->places);
+
+  for (l = contact->priv->places; l != NULL; l = l->next) {
+    GeocodeData *data;
+
+    data = g_slice_new (GeocodeData);
+    data->contact = contact;
+    data->place = l->data;
+    data->callback = callback;
+    data->params = g_hash_table_new_full (g_str_hash,
+                                          g_str_equal,
+                                          g_free,
+                                          g_free);
+
+    add_attribute (data->params, "street",
+                   geocode_place_get_street_address (data->place));
+    add_attribute (data->params, "locality",
+                   geocode_place_get_town (data->place));
+    add_attribute (data->params, "region",
+                   geocode_place_get_state (data->place));
+    add_attribute (data->params, "country",
+                   geocode_place_get_country (data->place));
+
+    forward = geocode_forward_new_for_params (data->params);
+    geocode_forward_search_async (forward,
+                                  NULL,
+                                  (GAsyncReadyCallback) on_geocode_search_async,
+                                  data);
+  }
 }
 
 MapsCContact *
diff --git a/lib/mapsc-contact.h b/lib/mapsc-contact.h
index b15de82..520e120 100644
--- a/lib/mapsc-contact.h
+++ b/lib/mapsc-contact.h
@@ -21,7 +21,7 @@
 #define __MAPSC_CONTACT_H__
 
 #include <glib-object.h>
-#include "mapsc-contact-address.h"
+#include <geocode-glib/geocode-glib.h>
 
 #define MAPSC_TYPE_CONTACT            (mapsc_contact_get_type ())
 #define MAPSC_CONTACT(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), MAPSC_TYPE_CONTACT, MapsCContact))
@@ -34,6 +34,12 @@ typedef struct _MapsCContact MapsCContact;
 typedef struct _MapsCContactClass MapsCContactClass;
 typedef struct _MapsCContactPrivate MapsCContactPrivate;
 
+/**
+ * MapsCContactGeocodeCallback:
+ * @contact: A #MapsCContact object
+ **/
+typedef void (*MapsCContactGeocodeCallback) (MapsCContact *contact);
+
 struct _MapsCContact {
   GObject parent_instance;
   MapsCContactPrivate *priv;
@@ -47,7 +53,9 @@ struct _MapsCContactClass {
 GType mapsc_contact_get_type (void);
 
 MapsCContact *mapsc_contact_new    (void);
-void mapsc_contact_add_address     (MapsCContact *contact,
-                                    MapsCContactAddress *address);
-GList *mapsc_contact_get_addresses (MapsCContact *contact);
+void mapsc_contact_add_place       (MapsCContact *contact,
+                                    GeocodePlace *place);
+GList *mapsc_contact_get_places    (MapsCContact *contact);
+void mapsc_contact_geocode (MapsCContact *contact,
+                            MapsCContactGeocodeCallback callback);
 #endif
diff --git a/lib/mapsc-contacts.c b/lib/mapsc-contacts.c
index 844ae0e..0765dc4 100644
--- a/lib/mapsc-contacts.c
+++ b/lib/mapsc-contacts.c
@@ -20,6 +20,7 @@
 
 
 #include <folks/folks.h>
+#include <geocode-glib/geocode-glib.h>
 
 #include "mapsc-contacts.h"
 #include "mapsc-contact.h"
@@ -135,45 +136,48 @@ get_contact (FolksIndividual *individual)
                 avatar);
 
   while (gee_iterator_has_next (iter)) {
-    MapsCContactAddress *contact_address;
-    FolksPostalAddress *address;
+    GeocodePlace *place;
+    FolksPostalAddress *addr;
     FolksAbstractFieldDetails *details;
     GeeCollection *values;
+    GeeMultiMap *map;
     GeeIterator *values_iter;
-    char *id;
+    char *name;
+    char *type = "Unknown";
 
     gee_iterator_next (iter);
     details = gee_iterator_get (iter);
-    address = (FolksPostalAddress *) folks_abstract_field_details_get_value (details);
+    addr = (FolksPostalAddress *) folks_abstract_field_details_get_value (details);
 
-    g_object_get (G_OBJECT (address), "id", &id);
-
-    values = gee_multi_map_get_values (folks_abstract_field_details_get_parameters (details));
+    map = folks_abstract_field_details_get_parameters (details);
+    values = gee_multi_map_get_values (map);
     values_iter = gee_iterable_iterator (GEE_ITERABLE (values));
     if (!values_iter)
       return NULL;
 
-    contact_address = mapsc_contact_address_new ();
     if (gee_iterator_has_next (values_iter)) {
-      char *type;
-
       gee_iterator_next (values_iter);
       type = gee_iterator_get (values_iter);
-      g_object_set (G_OBJECT (contact_address), "type", type, NULL);
     }
 
-    g_object_set (G_OBJECT (contact_address), "country",
-                  folks_postal_address_get_country (address), NULL);
-    g_object_set (G_OBJECT (contact_address), "region",
-                  folks_postal_address_get_region (address), NULL);
-    g_object_set (G_OBJECT (contact_address), "locality",
-                  folks_postal_address_get_locality (address), NULL);
-    g_object_set (G_OBJECT (contact_address), "postal-code",
-                  folks_postal_address_get_postal_code (address), NULL);
-    g_object_set (G_OBJECT (contact_address), "street",
-                  folks_postal_address_get_street (address), NULL);
-
-    mapsc_contact_add_address (contact, contact_address);
+    name = g_strdup_printf ("%s (%s)",
+                            folks_individual_get_display_name (individual),
+                            type);
+    place = geocode_place_new (name, GEOCODE_PLACE_TYPE_UNKNOWN);
+    g_free (name);
+
+    geocode_place_set_country (place,
+                               folks_postal_address_get_country (addr));
+    geocode_place_set_state (place,
+                             folks_postal_address_get_region (addr));
+    geocode_place_set_postal_code (place,
+                                   folks_postal_address_get_postal_code (addr));
+    geocode_place_set_town (place,
+                            folks_postal_address_get_locality (addr));
+    geocode_place_set_street_address (place,
+                                      folks_postal_address_get_street (addr));
+
+    mapsc_contact_add_place (contact, place);
   }
 
   return contact;
diff --git a/src/application.js b/src/application.js
index decc8bb..8f6339f 100644
--- a/src/application.js
+++ b/src/application.js
@@ -21,6 +21,7 @@
  *         Zeeshan Ali (Khattak) <zeeshanak gnome org>
  */
 
+const Geocode = imports.gi.GeocodeGlib;
 const GLib = imports.gi.GLib;
 const GObject = imports.gi.GObject;
 const Gettext = imports.gettext;
@@ -106,22 +107,14 @@ const Application = new Lang.Class({
         this._checkNetwork();
         this._mainWindow.window.present();
 
-        let contactArray = [];
-        contacts.lookup(parameter.deep_unpack(), (function(contact) {
-            contact.get_addresses().forEach(function(address) {
-                contactArray.push(new Contact.Contact({ name: contact.name,
-                                                        id: contact.id,
-                                                        icon: contact.icon,
-                                                        type: address.type,
-                                                        street_address: address.street,
-                                                        county: address.region,
-                                                        town: address.locality,
-                                                        postal_code: address.postal_code,
-                                                        country: address.country
-                                                      }));
-            });
-
-            this._mainWindow.mapView.showContact(contactArray);
+        contacts.lookup(parameter.deep_unpack(), (function(mapscContact) {
+            let contact = new Contact.Contact(mapscContact);
+
+            this._mainWindow.markBusy();
+            contact.geocode((function() {
+                this._mainWindow.unmarkBusy();
+                this._mainWindow.mapView.showContact(contact);
+            }).bind(this));
         }).bind(this));
     },
 
diff --git a/src/busy-marker.ui b/src/busy-marker.ui
new file mode 100644
index 0000000..b4cd3c2
--- /dev/null
+++ b/src/busy-marker.ui
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <!-- interface-requires gtk+ 3.10 -->
+  <template class= "Gjs_BusyMarker" parent="GtkFrame">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="width_request">200</property>
+    <property name="height_request">150</property>
+    <property name="expand">False</property>
+    <property name="valign">center"</property>
+    <property name="halign">center"</property>
+    <child>
+      <object class="GtkSpinner" id="spinner">
+        <property name="visible">True</property>
+        <property name="active">True</property>
+        <property name="width-request">32</property>
+        <property name="height-request">32</property>
+        <property name="can_focus">False</property>
+        <property name="valign">center"</property>
+        <property name="halign">center"</property>        
+      </object>
+    </child>
+  </template>
+</interface>
diff --git a/src/busyMarker.js b/src/busyMarker.js
new file mode 100644
index 0000000..34da513
--- /dev/null
+++ b/src/busyMarker.js
@@ -0,0 +1,28 @@
+/* -*- Mode: JS2; indent-tabs-mode: nil; js2-basic-offset: 4 -*- */
+/* vim: set et ts=4 sw=4: */
+/*
+ * GNOME Maps is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * GNOME Maps is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with GNOME Maps; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Author: Jonas Danielsson <jonas threetimestwo org>
+ */
+
+const Gtk = imports.gi.Gtk;
+const Lang = imports.lang;
+
+const BusyMarker = new Lang.Class({
+    Name: 'BusyMarker',
+    Extends: Gtk.Frame,
+    Template: 'resource:///org/gnome/maps/busy-marker.ui'
+});
diff --git a/src/contact.js b/src/contact.js
index e91b724..4118630 100644
--- a/src/contact.js
+++ b/src/contact.js
@@ -22,34 +22,63 @@
 
 const _ = imports.gettext.gettext;
 
+const Champlain = imports.gi.Champlain;
 const Geocode = imports.gi.GeocodeGlib;
 const Lang = imports.lang;
 
 const Place = imports.place;
 
-const Contact = new Lang.Class({
-    Name: 'Contact',
+const ContactPlace = new Lang.Class({
+    Name: 'ContactPlace',
     Extends: Place.Place,
 
     _init: function(params) {
-        params.osm_id = params.id || params.osm_id || null;
-        delete params.id;
+        this._avatar = params.avatar;
+        delete params.avatar;
 
-        this._type = params.type;
-        delete params.type;
+        this.parent(params);
+    },
 
-        this.icon = params.icon;
-        delete params.icon;
+    get icon() {
+        return this._avatar;
+    },
 
-        if (this._type)
-            params.name = params.name + ' (' + this._type + ')';
+    get isContact() {
+        return true;
+    }
+});
 
-        params.osm_type = Geocode.PlaceOsmType.UNKNOWN;
+const Contact = new Lang.Class({
+    Name: 'Contact',
 
-        this.parent(params);
+    _init: function(mapscContact) {
+        this._mapscContact = mapscContact;
+        this._places = [];
+        this._bbox = null;
+    },
+
+    get places() {
+        return this._places;
     },
 
-    get_icon: function() {
-        return this.icon;
+    get bbox() {
+        return this._bbox;
+    },
+
+    geocode: function(callback) {
+        this._bbox = new Champlain.BoundingBox();
+        this._mapscContact.geocode((function () {
+            this._mapscContact.get_places().forEach((function(p) {
+                if (!p.location)
+                    return;
+                
+                this._bbox.extend(p.location.latitude, p.location.longitude);
+                let place = new ContactPlace({ place: p,
+                                               avatar: this._mapscContact.icon });
+                this._places.push(place);
+            }).bind(this));
+
+            callback(this._places);
+        }).bind(this));
     }
 });
diff --git a/src/geocodeService.js b/src/geocodeService.js
index e5e1df1..ec23d57 100644
--- a/src/geocodeService.js
+++ b/src/geocodeService.js
@@ -22,6 +22,7 @@
  */
 
 const Geocode = imports.gi.GeocodeGlib;
+const GObject = imports.gi.GObject;
 const Lang = imports.lang;
 
 const Application = imports.application;
diff --git a/src/gnome-maps.data.gresource.xml b/src/gnome-maps.data.gresource.xml
index b19a625..8de1882 100644
--- a/src/gnome-maps.data.gresource.xml
+++ b/src/gnome-maps.data.gresource.xml
@@ -2,6 +2,7 @@
 <gresources>
   <gresource prefix="/org/gnome/maps">
     <file preprocess="xml-stripblanks">app-menu.ui</file>
+    <file preprocess="xml-stripblanks">busy-marker.ui</file>
     <file preprocess="xml-stripblanks">favorites-popover.ui</file>
     <file preprocess="xml-stripblanks">place-entry.ui</file>
     <file preprocess="xml-stripblanks">main-window.ui</file>
@@ -14,7 +15,7 @@
     <file preprocess="xml-stripblanks">notification.ui</file>
     <file preprocess="xml-stripblanks">route-entry.ui</file>
     <file preprocess="xml-stripblanks">map-bubble.ui</file>
-    <file preprocess="xml-stripblanks">search-result-bubble.ui</file>
+    <file preprocess="xml-stripblanks">place-bubble.ui</file>
     <file preprocess="xml-stripblanks">share-dialog.ui</file>
     <file preprocess="xml-stripblanks">user-location-bubble.ui</file>
     <file alias="application.css">../data/gnome-maps.css</file>
diff --git a/src/gnome-maps.js.gresource.xml b/src/gnome-maps.js.gresource.xml
index 4399859..ebec475 100644
--- a/src/gnome-maps.js.gresource.xml
+++ b/src/gnome-maps.js.gresource.xml
@@ -2,6 +2,7 @@
 <gresources>
   <gresource prefix="/org/gnome/maps">
     <file>application.js</file>
+    <file>busyMarker.js</file>
     <file>config.js</file>
     <file>contact.js</file>
     <file>contextMenu.js</file>
@@ -31,8 +32,8 @@
     <file>routeQuery.js</file>
     <file>routeService.js</file>
     <file>searchPopup.js</file>
-    <file>searchResultBubble.js</file>
-    <file>searchResultMarker.js</file>
+    <file>placeBubble.js</file>
+    <file>placeMarker.js</file>
     <file>shareDialog.js</file>
     <file>turnPointBubble.js</file>
     <file>turnPointMarker.js</file>
diff --git a/src/mainWindow.js b/src/mainWindow.js
index d09ffe0..701d1a0 100644
--- a/src/mainWindow.js
+++ b/src/mainWindow.js
@@ -29,6 +29,7 @@ const Lang = imports.lang;
 const Mainloop = imports.mainloop;
 
 const Application = imports.application;
+const BusyMarker = imports.busyMarker;
 const Config = imports.config;
 const ContextMenu = imports.contextMenu;
 const FavoritesPopover = imports.favoritesPopover;
@@ -339,5 +340,19 @@ const MainWindow = new Lang.Class({
         aboutDialog.show();
         aboutDialog.connect('response',
                             aboutDialog.destroy.bind(aboutDialog));
+    },
+
+    markBusy: function() {
+        if (!this._busy) {
+            this._busy = new BusyMarker.BusyMarker();
+            this._overlay.add_overlay(this._busy);
+        } else {
+            this._busy.show();
+        }
+    },
+
+    unmarkBusy: function() {
+        if (this._busy)
+            this._busy.hide();
     }
 });
diff --git a/src/mapBubble.js b/src/mapBubble.js
index 7c7f80c..eaf50ea 100644
--- a/src/mapBubble.js
+++ b/src/mapBubble.js
@@ -45,7 +45,7 @@ const MapBubble = new Lang.Class({
     Abstract: true,
 
     _init: function(params) {
-        this._place = new Place.Place({ place: params.place });
+        this._place = params.place;
         delete params.place;
 
         this._mapView = params.mapView;
diff --git a/src/mapView.js b/src/mapView.js
index 0ac0cc6..fe27e68 100644
--- a/src/mapView.js
+++ b/src/mapView.js
@@ -29,7 +29,7 @@ const Lang = imports.lang;
 
 const Application = imports.application;
 const MapWalker = imports.mapWalker;
-const SearchResultMarker = imports.searchResultMarker;
+const PlaceMarker = imports.placeMarker;
 const TurnPointMarker = imports.turnPointMarker;
 const UserLocationMarker = imports.userLocationMarker;
 const Utils = imports.utils;
@@ -112,8 +112,8 @@ const MapView = new Lang.Class({
         this.view.add_layer(this._routeLayer);
 
         let mode = Champlain.SelectionMode.SINGLE;
-        this._searchResultLayer = new Champlain.MarkerLayer({ selection_mode: mode });
-        this.view.add_layer(this._searchResultLayer);
+        this._placeLayer = new Champlain.MarkerLayer({ selection_mode: mode });
+        this.view.add_layer(this._placeLayer);
 
         this._instructionMarkerLayer = new Champlain.MarkerLayer({ selection_mode: mode });
         this.view.add_layer(this._instructionMarkerLayer);
@@ -179,6 +179,20 @@ const MapView = new Lang.Class({
         this.emit('user-location-changed');
     },
 
+    _gotoBBox: function(bbox) {
+        let [lat, lon] = bbox.get_center();
+        let place = new Geocode.Place({
+            location     : new Geocode.Location({ latitude  : lat,
+                                                  longitude : lon }),
+            bounding_box : new Geocode.BoundingBox({ top    : bbox.top,
+                                                     bottom : bbox.bottom,
+                                                     left   : bbox.left,
+                                                     right  : bbox.right })
+        });
+
+        new MapWalker.MapWalker(place, this).goTo(true);
+    },
+
     showTurnPoint: function(turnPoint) {
         if (this._turnPointMarker)
             this._turnPointMarker.destroy();
@@ -192,29 +206,32 @@ const MapView = new Lang.Class({
         this._turnPointMarker.goToAndSelect(true);
     },
 
-    showContact: function(contacts) {
-        this._searchResultLayer.remove_all();
-        contacts.forEach(function(contact) {
-            let marker = new SearchResultMarker.SearchResultMarker({ place: contact,
-                                                                     mapView: this });
-            this._searchResultLayer.add_marker(marker);
-        });
+    showContact: function(contact) {
+        if (contact.places.length == 0)
+            return;
+
+        this._placeLayer.remove_all();
+        contact.places.forEach((function(place) {
+            log ('adding place: ' + place.name);
+            log ('contact?: ' + place.isContact);
+            log ('icon?: ' + place.icon);
+            let marker = new PlaceMarker.PlaceMarker({ place: place,
+                                                       mapView: this });
+            this._placeLayer.add_marker(marker);
+        }).bind(this));
 
-        if (contacts.length > 0) {
-            let bbox = this._searchResultLayer.get_bounding_box();
-            this.view.ensure_visible(bbox, true);
-        }
+        this._gotoBBox(contact.bbox);
     },
 
     showSearchResult: function(place) {
-        this._searchResultLayer.remove_all();
-        let searchResultMarker = new SearchResultMarker.SearchResultMarker({ place: place,
-                                                                             mapView: this });
+        this._placeLayer.remove_all();
+        let placeMarker = new PlaceMarker.PlaceMarker({ place: place,
+                                                               mapView: this });
 
-        this._searchResultLayer.add_marker(searchResultMarker);
-        searchResultMarker.goToAndSelect(true);
+        this._placeLayer.add_marker(placeMarker);
+        placeMarker.goToAndSelect(true);
 
-        return searchResultMarker;
+        return placeMarker;
     },
 
     showRoute: function(route) {
@@ -223,18 +240,8 @@ const MapView = new Lang.Class({
 
         route.path.forEach(this._routeLayer.add_node.bind(this._routeLayer));
 
-        let [lat, lon] = route.bbox.get_center();
-        let place = new Geocode.Place({
-            location     : new Geocode.Location({ latitude  : lat,
-                                                  longitude : lon }),
-            bounding_box : new Geocode.BoundingBox({ top    : route.bbox.top,
-                                                     bottom : route.bbox.bottom,
-                                                     left   : route.bbox.left,
-                                                     right  : route.bbox.right })
-        });
-
         this._showDestinationTurnpoints();
-        new MapWalker.MapWalker(place, this).goTo(true);
+        this._gotoBBox(route.bbox);
     },
 
     _showDestinationTurnpoints: function() {
diff --git a/src/search-result-bubble.ui b/src/place-bubble.ui
similarity index 100%
rename from src/search-result-bubble.ui
rename to src/place-bubble.ui
diff --git a/src/searchResultBubble.js b/src/placeBubble.js
similarity index 88%
rename from src/searchResultBubble.js
rename to src/placeBubble.js
index 092d8c6..6e29009 100644
--- a/src/searchResultBubble.js
+++ b/src/placeBubble.js
@@ -20,6 +20,7 @@
  * Author: Damián Nohales <damiannohales gmail com>
  */
 
+const Geocode = imports.gi.GeocodeGlib;
 const Gtk = imports.gi.Gtk;
 const Format = imports.format;
 const Lang = imports.lang;
@@ -33,16 +34,16 @@ const PlaceFormatter = imports.placeFormatter;
 const PlaceStore = imports.placeStore;
 const Utils = imports.utils;
 
-const SearchResultBubble = new Lang.Class({
-    Name: "SearchResultBubble",
+const PlaceBubble = new Lang.Class({
+    Name: "PlaceBubble",
     Extends: MapBubble.MapBubble,
 
     _init: function(params) {
-        let ui = Utils.getUIObject('search-result-bubble', [ 'stack',
-                                                             'box-content',
-                                                             'label-title']);
+        let ui = Utils.getUIObject('place-bubble', [ 'stack',
+                                                     'box-content',
+                                                     'label-title']);
         params.buttons = (MapBubble.Button.ROUTE |
-                          MapBubble.Button.SHARE |
+                          MapBubble.Button.SHARE|
                           MapBubble.Button.FAVORITE);
 
         this.parent(params);
@@ -55,7 +56,11 @@ const SearchResultBubble = new Lang.Class({
         this._title = ui.labelTitle;
         this._boxContent = ui.boxContent;
 
-        if (Application.placeStore.exists(this.place, null)) {
+        log ('icon: ' + this.place.icon);
+        
+        if (this.place.isContact) {
+            this._populate(this.place);
+        } else if (Application.placeStore.exists(this.place, null)) {
             let place = Application.placeStore.get(this.place);
             this._populate(place);
         } else {
diff --git a/src/searchResultMarker.js b/src/placeMarker.js
similarity index 82%
rename from src/searchResultMarker.js
rename to src/placeMarker.js
index a4fc7f8..914bb1c 100644
--- a/src/searchResultMarker.js
+++ b/src/placeMarker.js
@@ -23,11 +23,11 @@
 const Lang = imports.lang;
 
 const MapMarker = imports.mapMarker;
-const SearchResultBubble = imports.searchResultBubble;
+const PlaceBubble = imports.placeBubble;
 const Utils = imports.utils;
 
-const SearchResultMarker = new Lang.Class({
-    Name: 'SearchResultMarker',
+const PlaceMarker = new Lang.Class({
+    Name: 'PlaceMarker',
     Extends: MapMarker.MapMarker,
 
     _init: function(params) {
@@ -43,8 +43,8 @@ const SearchResultMarker = new Lang.Class({
 
     _createBubble: function() {
         if (this.place.name) {
-            return new SearchResultBubble.SearchResultBubble({ place: this.place,
-                                                               mapView: this._mapView });
+            return new PlaceBubble.PlaceBubble({ place: this.place,
+                                                 mapView: this._mapView });
         } else
             return null;
     }
diff --git a/src/utils.js b/src/utils.js
index 79c857f..38ff3ab 100644
--- a/src/utils.js
+++ b/src/utils.js
@@ -261,7 +261,7 @@ function getAccuracyDescription(accuracy) {
 }
 
 function load_icon(icon, size, loadCompleteCallback) {
-    if (icon instanceof Gio.FileIcon) {
+    if (icon instanceof Gio.FileIcon || icon instanceof Gio.BytesIcon) {
         _load_file_icon(icon, loadCompleteCallback);
     } else if (icon instanceof Gio.ThemedIcon) {
         _load_themed_icon(icon, size, loadCompleteCallback);
@@ -269,26 +269,29 @@ function load_icon(icon, size, loadCompleteCallback) {
 }
 
 function _load_file_icon(icon, loadCompleteCallback) {
-    let pixbuf = _iconStore[icon.file.get_uri()];
+    if (icon.file) {
+        let pixbuf = _iconStore[icon.file.get_uri()];
 
-    if (pixbuf) { // check if the icon is cached
-        loadCompleteCallback(pixbuf);
-        return;
-    }
+        if (pixbuf) { // check if the icon is cached
+            loadCompleteCallback(pixbuf);
+            return;
+        }
 
-    if (icon.file.has_uri_scheme ("http") || icon.file.has_uri_scheme ("https")) {
-        _load_http_icon(icon, loadCompleteCallback);
-        return;
+        if (icon.file.has_uri_scheme ("http") || icon.file.has_uri_scheme ("https")) {
+            _load_http_icon(icon, loadCompleteCallback);
+            return;
+        }
     }
 
     icon.load_async(-1, null, function(icon, res) {
         try {
             let stream = icon.load_finish(res, null)[0];
 
-            pixbuf =
-                GdkPixbuf.Pixbuf.new_from_stream(stream, null);
+            let pixbuf = GdkPixbuf.Pixbuf.new_from_stream(stream, null);
 
-            _iconStore[icon.file.get_uri()] = pixbuf;
+            if (icon.file)
+                _iconStore[icon.file.get_uri()] = pixbuf;
+            
             loadCompleteCallback(pixbuf);
         } catch(e) {
             log("Failed to load pixbuf: " + e);


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