[gnome-maps] Add c shim library



commit 9d0bce40170e09dc2c012e17020e4d4a913c7205
Author: Jonas Danielsson <jonas threetimestwo org>
Date:   Tue Dec 16 03:35:02 2014 -0500

    Add c shim library
    
    This is needed to integrate contact data via libfolks.
    And the library might be needed for other non-introspectable things
    in the future.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=741591

 Makefile.am                    |    2 +-
 configure.ac                   |   22 +++
 lib/Makefile.am                |   57 ++++++
 lib/maps-contact-store.c       |  309 +++++++++++++++++++++++++++++++++
 lib/maps-contact-store.h       |   69 ++++++++
 lib/maps-contact.c             |  368 ++++++++++++++++++++++++++++++++++++++++
 lib/maps-contact.h             |   55 ++++++
 lib/maps-enum-types.c.template |   31 ++++
 lib/maps-enum-types.h.template |   36 ++++
 lib/maps.h                     |   26 +++
 10 files changed, 974 insertions(+), 1 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index ce68989..8f53c8f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,3 +1,3 @@
 ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS}
 
-SUBDIRS = src data po
+SUBDIRS = lib src data po
diff --git a/configure.ac b/configure.ac
index 366ddfd..6e9c48e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -23,6 +23,9 @@ AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE,"$GETTEXT_PACKAGE",[The name of the gettext d
 IT_PROG_INTLTOOL(0.40.0)
 PKG_PROG_PKG_CONFIG([0.22])
 
+GLIB_MKENUMS=`$PKG_CONFIG --variable=glib_mkenums glib-2.0`
+AC_SUBST(GLIB_MKENUMS)
+
 GIO_MIN_VERSION=2.39.3
 GJS_MIN_VERSION=1.43.3
 GOBJECT_INTROSPECTION_MIN_VERSION=0.10.1
@@ -33,6 +36,22 @@ PKG_CHECK_MODULES(GNOME_MAPS, [
     gobject-introspection-1.0    >= $GOBJECT_INTROSPECTION_MIN_VERSION
 ])
 
+FOLKS_MIN_VERSION=0.10.0
+GEE_MIN_VERSION=0.16.0
+GEOCODE_MIN_VERSION=3.15.2
+CHAMPLAIN_MIN_VERSION=0.12.9
+
+PKG_CHECK_MODULES(GNOME_MAPS_LIB, [
+    gee-0.8                      >= $GEE_MIN_VERSION
+    folks                        >= $FOLKS_MIN_VERSION
+    geocode-glib-1.0             >= $GEOCODE_MIN_VERSION
+    champlain-0.12               >= $CHAMPLAIN_MIN_VERSION
+])
+AC_SUBST(GNOME_MAPS_LIB_CFLAGS)
+AC_SUBST(GNOME_MAPS_LIB_LIBS)
+
+AC_PROG_LIBTOOL
+
 GLIB_GSETTINGS
 
 AC_PATH_PROG([GJS],[gjs])
@@ -40,8 +59,11 @@ AC_PATH_PROG([GJS],[gjs])
 GLIB_COMPILE_RESOURCES=`$PKG_CONFIG --variable glib_compile_resources gio-2.0`
 AC_SUBST(GLIB_COMPILE_RESOURCES)
 
+GOBJECT_INTROSPECTION_CHECK([0.6.3])
+
 AC_CONFIG_FILES([
     Makefile
+    lib/Makefile
     src/Makefile
     data/Makefile
     data/icons/Makefile
diff --git a/lib/Makefile.am b/lib/Makefile.am
new file mode 100644
index 0000000..b2e33d4
--- /dev/null
+++ b/lib/Makefile.am
@@ -0,0 +1,57 @@
+lib_LTLIBRARIES = libgnome-maps.la
+
+BUILT_SOURCES =                                                        \
+       maps-enum-types.c                                               \
+       maps-enum-types.h
+
+libgnome_maps_headers_private = maps-contact-store.h maps-contact.h maps.h
+libgnome_maps_sources = maps-contact-store.c maps-contact.c
+libgnome_maps_la_SOURCES =                                             \
+       $(libgnome_maps_sources)                                        \
+       $(libgnome_maps_headers_private)                                \
+       $(BUILT_SOURCES)
+
+libgnome_maps_la_LIBADD = $(GNOME_MAPS_LIB_LIBS)
+
+AM_CPPFLAGS =                                                          \
+       $(GNOME_MAPS_LIB_CFLAGS)                                        \
+       -I$(top_srcdir)
+
+maps-enum-types.h: $(libgnome_maps_headers_private)
+       $(AM_V_GEN) ($(GLIB_MKENUMS)                                    \
+               --template maps-enum-types.h.template                   \
+               $^ > xgen-$(@F) && mv -f xgen-$(@F) $@)
+
+maps-enum-types.c: $(libgnome_maps_headers_private) maps-enum-types.h
+       $(AM_V_GEN) ($(GLIB_MKENUMS)                                    \
+               --template maps-enum-types.c.template                   \
+               $^ > xgen-$(@F) && mv -f xgen-$(@F) $@)
+
+if HAVE_INTROSPECTION
+-include $(INTROSPECTION_MAKEFILE)
+INTROSPECTION_SCANNER_ARGS = --warn-all
+
+GnomeMaps-1.0.gir: libgnome-maps.la
+GnomeMaps_1_0_gir_INCLUDES =                                           \
+       GLib-2.0                                                        \
+       GObject-2.0                                                     \
+       GeocodeGlib-1.0                                         \
+       Champlain-0.12
+GnomeMaps_1_0_gir_PACKAGES = gobject-2.0 geocode-glib-1.0
+GnomeMaps_1_0_gir_FILES = $(libgnome_maps_la_SOURCES)
+GnomeMaps_1_0_gir_CFLAGS = $(MAPS_CFLAGS) -I$(top_srcdir) -I$(top_builddir)
+GnomeMaps_1_0_gir_LIBS = libgnome-maps.la
+GnomeMaps_1_0_gir_EXPORT_PACKAGES = gnome-maps-1.0
+GnomeMaps_1_0_gir_SCANNERFLAGS =                                       \
+       --symbol-prefix=maps                                            \
+       --identifier-prefix=Maps
+INTROSPECTION_GIRS = GnomeMaps-1.0.gir
+
+girdir = $(datadir)/gir-1.0
+gir_DATA = $(INTROSPECTION_GIRS)
+
+typelibdir = $(libdir)/girepository-1.0
+typelib_DATA = $(INTROSPECTION_GIRS:.gir=.typelib)
+
+CLEANFILES = $(gir_DATA) $(typelib_DATA) $(BUILT_SOURCES)
+endif
diff --git a/lib/maps-contact-store.c b/lib/maps-contact-store.c
new file mode 100644
index 0000000..2e0b071
--- /dev/null
+++ b/lib/maps-contact-store.c
@@ -0,0 +1,309 @@
+/*
+ * Copyright (c) 2015 Jonas Danielsson
+ *
+ * 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>
+ */
+
+
+#include <folks/folks.h>
+#include <geocode-glib/geocode-glib.h>
+
+#include "maps-contact-store.h"
+#include "maps-contact.h"
+#include "maps-enum-types.h"
+
+struct _MapsContactStorePrivate
+{
+  GList *list;
+  MapsContactStoreState state;
+  FolksIndividualAggregator *aggregator;
+};
+
+enum {
+  PROP_0,
+
+  PROP_STATE
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (MapsContactStore, maps_contact_store, G_TYPE_OBJECT)
+
+static void
+maps_contact_store_get_property (GObject    *object,
+                                 guint       property_id,
+                                 GValue     *value,
+                                 GParamSpec *pspec)
+{
+  MapsContactStore *store = MAPS_CONTACT_STORE (object);
+
+  switch (property_id)
+    {
+    case PROP_STATE:
+      g_value_set_enum (value,
+                        store->priv->state);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+    }
+}
+
+static void
+maps_contact_store_dispose (GObject *object)
+{
+  MapsContactStore *store = (MapsContactStore *) object;
+
+  g_list_free (store->priv->list);
+  g_object_unref (store->priv->aggregator);
+
+  G_OBJECT_CLASS (maps_contact_store_parent_class)->dispose (object);
+}
+
+static void
+maps_contact_store_class_init (MapsContactStoreClass *klass)
+{
+  GObjectClass *maps_class = G_OBJECT_CLASS (klass);
+  GParamSpec *pspec;
+
+  maps_class->dispose = maps_contact_store_dispose;
+  maps_class->get_property = maps_contact_store_get_property;
+
+  /**
+   * MapsContactStore:state:
+   *
+   * The type of the contact.
+   */
+  pspec = g_param_spec_enum ("state",
+                             "State",
+                             "State",
+                             MAPS_TYPE_CONTACT_STORE_STATE,
+                             MAPS_CONTACT_STORE_STATE_INITIAL,
+                             G_PARAM_READABLE |
+                             G_PARAM_STATIC_STRINGS);
+  g_object_class_install_property (maps_class, PROP_STATE, pspec);
+}
+
+static void
+maps_contact_store_init (MapsContactStore *store)
+{
+  store->priv = maps_contact_store_get_instance_private (store);
+  store->priv->list = NULL;
+  store->priv->state = MAPS_CONTACT_STORE_STATE_INITIAL;
+}
+
+static MapsContact *
+get_contact (FolksIndividual *individual)
+{
+  MapsContact *contact;
+  GLoadableIcon *avatar;
+  GeeCollection *addresses;
+  GeeIterator *iter;
+
+  g_object_get (G_OBJECT (individual), "postal-addresses",
+                &addresses, NULL);
+  if (!addresses)
+    return NULL;
+
+  iter = gee_iterable_iterator (GEE_ITERABLE (addresses));
+  if (!gee_iterator_has_next (iter))
+    return NULL;
+
+  contact = maps_contact_new ();
+
+  g_object_set (G_OBJECT (contact), "name",
+                folks_individual_get_display_name (individual));
+  g_object_set (G_OBJECT (contact), "id",
+                folks_individual_get_id (individual));
+
+  g_object_get (G_OBJECT (individual), "avatar",
+                &avatar);
+  g_object_set (G_OBJECT (contact), "icon",
+                avatar);
+
+  while (gee_iterator_has_next (iter))
+    {
+      GeocodePlace *place;
+      FolksPostalAddress *addr;
+      FolksAbstractFieldDetails *details;
+      GeeMultiMap *map;
+      GeeSet *keys;
+      GeeIterator *keys_iter;
+      char *name;
+      char *type = "Unknown";
+
+      gee_iterator_next (iter);
+      details = gee_iterator_get (iter);
+      addr = (FolksPostalAddress *) folks_abstract_field_details_get_value (details);
+
+      /* Get the type of the address, such as "Home", "Work", "Other" */
+      map = folks_abstract_field_details_get_parameters (details);
+      keys = gee_multi_map_get_keys (map);
+      keys_iter = gee_iterable_iterator (GEE_ITERABLE (keys));
+      if (gee_iterator_has_next (keys_iter))
+        {
+          GeeCollection *values;
+          GeeIterator *values_iter;
+
+          gee_iterator_next (keys_iter);
+          values = gee_multi_map_get (map,
+                                      gee_iterator_get (keys_iter));
+          if (gee_collection_get_size (values) != 0)
+            {
+              values_iter = gee_iterable_iterator (GEE_ITERABLE (values));
+              gee_iterator_next (values_iter);
+              type = gee_iterator_get (values_iter);
+            }
+        }
+      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));
+
+      maps_contact_add_place (contact, place);
+    }
+
+  return contact;
+}
+
+MapsContactStore *
+maps_contact_store_new ()
+{
+  return g_object_new (MAPS_TYPE_CONTACT_STORE, NULL);
+}
+
+static void
+maps_contact_store_lookup_cb (FolksIndividualAggregator     *aggregator,
+                              GAsyncResult                  *res,
+                              MapsContactStoreLookupCallback callback)
+{
+  FolksIndividual *individual;
+
+  individual = folks_individual_aggregator_look_up_individual_finish (aggregator,
+                                                                      res,
+                                                                      NULL);
+  if (individual != NULL)
+    {
+      MapsContact *contact = get_contact (individual);
+      callback (contact);
+    }
+  else
+    {
+      callback (NULL);
+    }
+}
+
+/**
+ * maps_contact_store_lookup:
+ * @store: A #MapsContactStore object
+ * @callback: (scope async): A #MapsContactStoreLookupCallback function
+ */
+void
+maps_contact_store_lookup (MapsContactStore              *store,
+                           const char                    *id,
+                           MapsContactStoreLookupCallback callback)
+{
+  folks_individual_aggregator_look_up_individual (store->priv->aggregator,
+                                                  id,
+                                                  (GAsyncReadyCallback) maps_contact_store_lookup_cb,
+                                                  callback);
+}
+
+static void
+aggregator_quiescent_notify (FolksIndividualAggregator *aggregator,
+                             GParamSpec                *pspec,
+                             MapsContactStore          *store)
+{
+  GeeMap *map;
+  GeeMapIterator *iter;
+
+  map = folks_individual_aggregator_get_individuals (aggregator);
+  iter = gee_map_map_iterator (map);
+
+  while (gee_map_iterator_has_next (iter))
+    {
+      MapsContact *contact;
+
+      gee_map_iterator_next (iter);
+      contact = get_contact (gee_map_iterator_get_value (iter));
+      if (contact)
+        store->priv->list = g_list_prepend (store->priv->list, contact);
+    }
+
+  store->priv->state = MAPS_CONTACT_STORE_STATE_LOADED;
+  g_object_notify (G_OBJECT (store), "state");
+}
+
+static void
+aggregator_prepare (FolksIndividualAggregator *aggregator,
+                    GAsyncResult              *res,
+                    gpointer                   user_data)
+{
+  folks_individual_aggregator_prepare_finish (aggregator, res, NULL);
+}
+
+/**
+ * maps_contact_store_load:
+ * @store: A #MapsContactStore object
+ *
+ * Load contacts from available backends.
+ *
+ */
+void
+maps_contact_store_load (MapsContactStore *store)
+{
+  g_return_if_fail (MAPS_IS_CONTACT_STORE (store));
+
+  store->priv->aggregator = folks_individual_aggregator_dup ();
+
+  g_signal_connect (G_OBJECT (store->priv->aggregator),
+                    "notify::is-quiescent",
+                    G_CALLBACK (aggregator_quiescent_notify),
+                    store);
+
+  store->priv->state = MAPS_CONTACT_STORE_STATE_LOADING;
+  g_object_notify (G_OBJECT (store), "state");
+
+  folks_individual_aggregator_prepare (store->priv->aggregator,
+                                       (GAsyncReadyCallback) aggregator_prepare,
+                                       NULL);
+}
+
+/**
+ * maps_contact_store_get_contacts:
+ * @store: A #MapsContactStore object
+ *
+ * Returns: (element-type MapsContact) (transfer container): a list of #MapsContact,
+ */
+GList *
+maps_contact_store_get_contacts (MapsContactStore *store)
+{
+  g_return_if_fail (MAPS_IS_CONTACT_STORE (store));
+
+  return store->priv->list;
+}
diff --git a/lib/maps-contact-store.h b/lib/maps-contact-store.h
new file mode 100644
index 0000000..a1d9521
--- /dev/null
+++ b/lib/maps-contact-store.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2015 Jonas Danielsson
+ *
+ * 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>
+ */
+
+#ifndef __MAPS_CONTACT_STORE_H__
+#define __MAPS_CONTACT_STORE_H__
+
+#include <glib-object.h>
+#include "maps-contact.h"
+
+#define MAPS_TYPE_CONTACT_STORE maps_contact_store_get_type ()
+G_DECLARE_FINAL_TYPE(MapsContactStore, maps_contact_store, MAPS, CONTACT_STORE,
+                     GObject)
+
+typedef struct _MapsContactStorePrivate MapsContactStorePrivate;
+
+/**
+ * MapsContactStoreState:
+ * @MAPS_CONTACT_STORE_STATE_INITIAL: Initial state
+ * @MAPS_CONTACT_STORE_STATE_LOADING: Loading
+ * @MAPS_CONTACT_STORE_STATE_LOADED: Loaded
+ */
+typedef enum {
+  MAPS_CONTACT_STORE_STATE_INITIAL,
+  MAPS_CONTACT_STORE_STATE_LOADING,
+  MAPS_CONTACT_STORE_STATE_LOADED,
+} MapsContactStoreState;
+
+/**
+ * MapsContactStoreLookupCallback:
+ * @contact: A #MapsContact object
+ */
+typedef void (*MapsContactStoreLookupCallback) (MapsContact *contact);
+
+struct _MapsContactStore
+{
+  GObject parent_instance;
+  MapsContactStorePrivate *priv;
+};
+
+struct _MapsContactStoreClass
+{
+  GObjectClass parent_class;
+};
+
+MapsContactStore * maps_contact_store_new          (void);
+void               maps_contact_store_load         (MapsContactStore              *store);
+void               maps_contact_store_lookup       (MapsContactStore              *store,
+                                                    const char                    *id,
+                                                    MapsContactStoreLookupCallback callback);
+GList *            maps_contact_store_get_contacts (MapsContactStore *store);
+
+#endif
diff --git a/lib/maps-contact.c b/lib/maps-contact.c
new file mode 100644
index 0000000..b681c4b
--- /dev/null
+++ b/lib/maps-contact.c
@@ -0,0 +1,368 @@
+/*
+ * Copyright (c) 2015 Jonas Danielsson
+ *
+ * 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>
+ */
+
+#include <folks/folks.h>
+#include <geocode-glib/geocode-glib.h>
+#include <champlain/champlain.h>
+
+#include "maps-contact.h"
+
+struct _MapsContactPrivate
+{
+  char *name;
+  char *id;
+
+  GLoadableIcon *icon;
+  GList *places;
+  ChamplainBoundingBox *bbox;
+
+  GMutex geocode_mutex;
+  guint geocode_counter;
+  guint geocodes_to_perform;
+};
+
+typedef struct
+{
+  GeocodePlace *place;
+  MapsContact *contact;
+  MapsContactGeocodeCallback callback;
+
+  GHashTable *params;
+} GeocodeData;
+
+enum {
+  PROP_0,
+
+  PROP_NAME,
+  PROP_ICON,
+  PROP_ID,
+  PROP_BBOX
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (MapsContact, maps_contact, G_TYPE_OBJECT)
+
+static void
+maps_contact_set_property (GObject      *object,
+                           guint         property_id,
+                           const GValue *value,
+                           GParamSpec   *pspec)
+{
+  MapsContact *contact = MAPS_CONTACT (object);
+
+  switch (property_id)
+    {
+    case PROP_NAME:
+      g_free (contact->priv->name);
+      contact->priv->name = g_value_dup_string (value);
+      break;
+
+    case PROP_ICON:
+      if (contact->priv->icon)
+        g_object_unref (contact->priv->icon);
+      contact->priv->icon = g_value_dup_object (value);
+      break;
+
+    case PROP_ID:
+      g_free (contact->priv->id);
+      contact->priv->id = g_value_dup_string (value);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+    }
+}
+
+static void
+maps_contact_get_property (GObject    *object,
+                           guint       property_id,
+                           GValue     *value,
+                           GParamSpec *pspec)
+{
+  MapsContact *contact = MAPS_CONTACT (object);
+
+  switch (property_id)
+    {
+    case PROP_NAME:
+      g_value_set_string (value,
+                          contact->priv->name);
+      break;
+
+    case PROP_ICON:
+      g_value_set_object (value,
+                          contact->priv->icon);
+      break;
+
+    case PROP_ID:
+      g_value_set_string (value,
+                          contact->priv->id);
+      break;
+
+    case PROP_BBOX:
+      g_value_set_boxed (value,
+                         contact->priv->bbox);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+    }
+}
+
+static void
+maps_contact_dispose (GObject *object)
+{
+  MapsContact *contact = (MapsContact *) object;
+
+  g_clear_pointer (&contact->priv->name, g_free);
+  g_clear_pointer (&contact->priv->id, g_free);
+  g_clear_object (&contact->priv->icon);
+  g_clear_object (&contact->priv->bbox);
+  g_list_free_full (contact->priv->places, g_object_unref);
+
+  G_OBJECT_CLASS (maps_contact_parent_class)->dispose (object);
+}
+
+static void
+maps_contact_class_init (MapsContactClass *klass)
+{
+  GObjectClass *maps_class = G_OBJECT_CLASS (klass);
+  GParamSpec *pspec;
+
+  maps_class->dispose = maps_contact_dispose;
+  maps_class->get_property = maps_contact_get_property;
+  maps_class->set_property = maps_contact_set_property;
+
+  /**
+   * MapsContact:name:
+   *
+   * The name of the contact.
+   */
+  pspec = g_param_spec_string ("name",
+                               "Name",
+                               "Name",
+                               NULL,
+                               G_PARAM_READWRITE |
+                               G_PARAM_STATIC_STRINGS);
+  g_object_class_install_property (maps_class, PROP_NAME, pspec);
+
+  /**
+   * MapsContact:id:
+   *
+   * The unique id of the contact.
+   */
+  pspec = g_param_spec_string ("id",
+                               "ID",
+                               "ID",
+                               NULL,
+                               G_PARAM_READWRITE |
+                               G_PARAM_STATIC_STRINGS);
+  g_object_class_install_property (maps_class, PROP_ID, pspec);
+
+  /**
+   * MapsContact:icon:
+   *
+   * The icon of the contact.
+   */
+  pspec = g_param_spec_object ("icon",
+                               "Icon",
+                               "An icon representing the contact",
+                               G_TYPE_ICON,
+                               G_PARAM_READWRITE |
+                               G_PARAM_STATIC_STRINGS);
+  g_object_class_install_property (maps_class, PROP_ICON, pspec);
+
+  /**
+   * MapsContact:bounding-box:
+   *
+   * The bounding box for the contact.
+   */
+  pspec = g_param_spec_boxed ("bounding-box",
+                              "Bounding Box",
+                              "The bounding box for the place",
+                              CHAMPLAIN_TYPE_BOUNDING_BOX,
+                              G_PARAM_READABLE |
+                              G_PARAM_STATIC_STRINGS);
+  g_object_class_install_property (maps_class, PROP_BBOX, pspec);
+}
+
+static void
+maps_contact_init (MapsContact *contact)
+{
+  contact->priv = maps_contact_get_instance_private (contact);
+
+  contact->priv->name = NULL;
+  contact->priv->id = NULL;
+  contact->priv->icon = NULL;
+  contact->priv->places = NULL;
+  contact->priv->bbox = NULL;
+
+  g_mutex_init (&contact->priv->geocode_mutex);
+}
+
+/**
+ * maps_contact_add_address:
+ * @contact: A #MapsContact object
+ * @place: A #GeocodePlace object
+ */
+void
+maps_contact_add_place (MapsContact  *contact,
+                        GeocodePlace *place)
+{
+  g_return_if_fail (MAPS_IS_CONTACT (contact));
+  g_return_if_fail (GEOCODE_IS_PLACE (place));
+
+  contact->priv->places = g_list_prepend (contact->priv->places, place);
+}
+
+/**
+ * maps_contact_get_places:
+ * @contact: A #MapsContact object
+ *
+ * Returns: (element-type GeocodePlace) (transfer container): a list of #GeocodePlace
+ */
+GList *
+maps_contact_get_places (MapsContact *contact)
+{
+  g_return_if_fail (MAPS_IS_CONTACT (contact));
+
+  return contact->priv->places;
+}
+
+static void
+on_geocode_search_async (GeocodeForward *forward,
+                         GAsyncResult   *res,
+                         GeocodeData    *data)
+{
+  MapsContact *contact;
+  GList *places;
+  gboolean call_callback = FALSE;
+
+  contact = data->contact;
+  places = geocode_forward_search_finish (forward, res, NULL);
+
+  g_mutex_lock (&contact->priv->geocode_mutex);
+
+  if (places)
+    {
+      GeocodePlace *place = g_list_nth_data (places, 0);
+      GeocodeLocation *location = geocode_place_get_location (place);
+      const char *street_address;
+
+      /* Keep the naming, but add location and osm info */
+      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));
+
+      /* Update the contact bounding box */
+      if (contact->priv->bbox == NULL)
+        contact->priv->bbox = champlain_bounding_box_new ();
+
+      champlain_bounding_box_extend (contact->priv->bbox,
+                                     geocode_location_get_latitude (location),
+                                     geocode_location_get_longitude (location));
+
+      /* Make sure we do not lie about how good our resolution is */
+      street_address = geocode_place_get_street_address (place);
+      if (street_address)
+        geocode_place_set_street_address (data->place, street_address);
+      else
+        geocode_place_set_street (data->place, geocode_place_get_street (place));
+
+      g_list_free (places);
+    }
+
+  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);
+}
+
+/**
+ * maps_contact_geocode:
+ * @contact: A #MapsContact object
+ * @callback: (scope async): A #MapsContactGeocodeCallback function
+ */
+void
+maps_contact_geocode (MapsContact                *contact,
+                      MapsContactGeocodeCallback callback)
+{
+  g_return_if_fail (MAPS_IS_CONTACT (contact));
+  g_return_if_fail (callback != NULL);
+
+  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;
+    GeocodeForward *forward;
+
+    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);
+  }
+}
+
+MapsContact *
+maps_contact_new ()
+{
+  return g_object_new (MAPS_TYPE_CONTACT, NULL);
+}
diff --git a/lib/maps-contact.h b/lib/maps-contact.h
new file mode 100644
index 0000000..7a92fa7
--- /dev/null
+++ b/lib/maps-contact.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2015 Jonas Danielsson
+ *
+ * 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>
+ */
+
+#ifndef __MAPS_CONTACT_H__
+#define __MAPS_CONTACT_H__
+
+#include <glib-object.h>
+#include <geocode-glib/geocode-glib.h>
+
+#define MAPS_TYPE_CONTACT maps_contact_get_type ()
+G_DECLARE_FINAL_TYPE(MapsContact, maps_contact, MAPS, CONTACT, GObject)
+
+typedef struct _MapsContactPrivate MapsContactPrivate;
+
+/**
+ * MapsContactGeocodeCallback:
+ * @contact: A #MapsContact object
+ */
+typedef void (*MapsContactGeocodeCallback) (MapsContact *contact);
+
+struct _MapsContact
+{
+  GObject parent_instance;
+  MapsContactPrivate *priv;
+};
+
+struct _MapsContactClass
+{
+  GObjectClass parent_class;
+};
+
+MapsContact *maps_contact_new        (void);
+void         maps_contact_add_place  (MapsContact               *contact,
+                                      GeocodePlace              *place);
+GList *      maps_contact_get_places (MapsContact               *contact);
+void         maps_contact_geocode    (MapsContact               *contact,
+                                      MapsContactGeocodeCallback callback);
+#endif
diff --git a/lib/maps-enum-types.c.template b/lib/maps-enum-types.c.template
new file mode 100644
index 0000000..188506a
--- /dev/null
+++ b/lib/maps-enum-types.c.template
@@ -0,0 +1,31 @@
+/*** BEGIN file-header ***/
+#include "maps-enum-types.h"
+
+/*** END file-header ***/
+
+/*** BEGIN file-production ***/
+/* enumerations from "@filename@" */
+/*** END file-production ***/
+
+/*** BEGIN value-header ***/
+GType
+ enum_name@_get_type (void)
+{
+    static GType etype = 0;
+    if (etype == 0) {
+        static const G Type@Value values[] = {
+/*** END value-header ***/
+
+/*** BEGIN value-production ***/
+          { @VALUENAME@, "@VALUENAME@", "@valuenick@" },
+/*** END value-production ***/
+
+/*** BEGIN value-tail ***/
+          { 0, NULL, NULL }
+       };
+       etype = g_ type@_register_static ("@EnumName@", values);
+    }
+    return etype;
+}
+
+/*** END value-tail ***/
diff --git a/lib/maps-enum-types.h.template b/lib/maps-enum-types.h.template
new file mode 100644
index 0000000..14171b2
--- /dev/null
+++ b/lib/maps-enum-types.h.template
@@ -0,0 +1,36 @@
+/*** BEGIN file-header ***/
+#ifndef __MAPS_ENUM_TYPES_H__
+#define __MAPS_ENUM_TYPES_H__
+
+#include "maps.h"
+
+G_BEGIN_DECLS
+
+/*** END file-header ***/
+
+/*** BEGIN file-production ***/
+/* enumerations from "@filename@" */
+
+/*** END file-production ***/
+
+/*** BEGIN value-header ***/
+GType @enum_name _get_type (void) G_GNUC_CONST;
+
+#define MAPS_TYPE_ ENUMSHORT@ (@enum_name _get_type())
+
+/**
+ * SECTION:maps-enum-types
+ * @short_description: Maps enumerated types
+ * @include: maps.h
+ *
+ * The enumerated types defined and used by libgnome-maps.
+ **/
+
+/*** END value-header ***/
+
+/*** BEGIN file-tail ***/
+G_END_DECLS
+
+#endif /* __MAPS_ENUM_TYPES_H__ */
+
+/*** END file-tail ***/
diff --git a/lib/maps.h b/lib/maps.h
new file mode 100644
index 0000000..244bcec
--- /dev/null
+++ b/lib/maps.h
@@ -0,0 +1,26 @@
+/*
+ * 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>
+ */
+
+#ifndef __MAPS_H__
+#define __MAPS_H__
+
+#include <glib-object.h>
+#include "maps-contact-store.h"
+#include "maps-contact.h"
+
+#endif


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