diff options
author | Cedric Bosdonnat <cedric.bosdonnat.ooo@free.fr> | 2009-11-27 05:05:12 +0800 |
---|---|---|
committer | Milan Crha <mcrha@redhat.com> | 2009-11-27 05:07:45 +0800 |
commit | 93b157843473065b73cbaa99e998f57d39f189ad (patch) | |
tree | 57ab70a35a3f5c99b25aefae606cccb1a6244eb4 | |
parent | e64794f577ab4bf9ffed0eb88e432ff75ecddd8f (diff) | |
download | gsoc2013-evolution-93b157843473065b73cbaa99e998f57d39f189ad.tar gsoc2013-evolution-93b157843473065b73cbaa99e998f57d39f189ad.tar.gz gsoc2013-evolution-93b157843473065b73cbaa99e998f57d39f189ad.tar.bz2 gsoc2013-evolution-93b157843473065b73cbaa99e998f57d39f189ad.tar.lz gsoc2013-evolution-93b157843473065b73cbaa99e998f57d39f189ad.tar.xz gsoc2013-evolution-93b157843473065b73cbaa99e998f57d39f189ad.tar.zst gsoc2013-evolution-93b157843473065b73cbaa99e998f57d39f189ad.zip |
Bug #361156 - contacts-map plugin
Add a map showing the location of contacts when possible.
It's disabled at the moment.
-rw-r--r-- | configure.ac | 31 | ||||
-rw-r--r-- | plugins/contacts-map/Makefile.am | 31 | ||||
-rw-r--r-- | plugins/contacts-map/contacts-map.c | 216 | ||||
-rw-r--r-- | plugins/contacts-map/geo-utils.c | 102 | ||||
-rw-r--r-- | plugins/contacts-map/geo-utils.h | 28 | ||||
-rw-r--r-- | plugins/contacts-map/org-gnome-contacts-map.eplug.xml | 19 | ||||
-rw-r--r-- | po/POTFILES.in | 2 |
7 files changed, 428 insertions, 1 deletions
diff --git a/configure.ac b/configure.ac index 51e3e02e63..f3ab029f3d 100644 --- a/configure.ac +++ b/configure.ac @@ -58,6 +58,8 @@ m4_define([dbus_glib_minimum_version], [0.74]) dnl Optional Packages m4_define([nm_minimum_version],[0.7]) m4_define([hal_minimum_version], [0.5.4]) +m4_define([champlain_minimum_version], [0.4]) +m4_define([geoclue_minimum_version], [0.11.1]) m4_define([libnotify_minimum_version], [0.3.0]) m4_define([gnome_pilot_minimum_version], [2.0.15]) m4_define([gweather_minimum_version], [2.25.3]) @@ -195,6 +197,8 @@ case "$host" in DL_LIB='' SOFTOKN3_LIB='' HAL_REQUIREMENT='' + CHAMPLAIN_REQUIREMENT='' + GEOCLUE_REQUIREMENT='' ;; *) os_win32=no @@ -1154,6 +1158,28 @@ dnl ******************************** FULL_GNOME_DEPS="gconf-2.0 gthread-2.0 gobject-2.0" dnl ****************************** +dnl libchamplain and geoclue? +dnl ****************************** + +PKG_CHECK_MODULES( [CHAMPLAIN], [champlain-gtk-0.5 >= champlain_minimum_version], [HAVE_CHAMPLAIN="yes"], [HAVE_CHAMPLAIN="no"] ) +if test "x$HAVE_CHAMPLAIN" = "xno"; then + PKG_CHECK_MODULES( [CHAMPLAIN], [champlain-gtk-0.4 >= champlain_minimum_version], [HAVE_CHAMPLAIN="yes"], [HAVE_CHAMPLAIN="no"] ) +fi +PKG_CHECK_MODULES( [GEOCLUE], [geoclue >= geoclue_minimum_version], [HAVE_GEOCLUE="yes"], [HAVE_GEOCLUE="no"] ) +if test "x$HAVE_CHAMPLAIN" = "xyes" -a "x$HAVE_GEOCLUE" = "xyes"; then + AC_DEFINE( HAVE_CHAMPLAIN, 1, [champlain-gtk available] ) + CHAMPLAIN_REQUIREMENTS="champlain-gtk" + AC_DEFINE( HAVE_GEOCLUE, 1, [geoclue available] ) + GEOCLUE_REQUIREMENTS="geoclue" + CONTACTS_MAP="contacts-map" +else + CHAMPLAIN_REQUIREMENTS="" + GEOCLUE_REQUIREMENTS="" + CONTACTS_MAP="" +fi + + +dnl ****************************** dnl TNEF implementation dnl ****************************** AC_MSG_CHECKING([for yTNEF]) @@ -1462,7 +1488,7 @@ dist_plugins_standard="$plugins_standard audio-inline image-inline pst-import" plugins_experimental_always="face external-editor hula-account-setup" plugins_experimental="$plugins_experimental_always $TNEF_ATTACHMENTS" -dist_plugins_experimental="$plugins_experimental_always profiler tnef-attachments" +dist_plugins_experimental="$plugins_experimental_always profiler tnef-attachments contacts-map" dnl ****************************** dnl Profiling support @@ -1785,6 +1811,7 @@ plugins/templates/Makefile plugins/tnef-attachments/Makefile plugins/vcard-inline/Makefile plugins/webdav-account-setup/Makefile +plugins/contacts-map/Makefile smclient/Makefile smime/Makefile smime/lib/Makefile @@ -1820,4 +1847,6 @@ echo " User documentation: $with_help Mono bindings: $enable_mono Python bindings: $enable_python + Libchamplain: $HAVE_CHAMPLAIN + Geoclue: $HAVE_GEOCLUE " diff --git a/plugins/contacts-map/Makefile.am b/plugins/contacts-map/Makefile.am new file mode 100644 index 0000000000..91ff22c0bc --- /dev/null +++ b/plugins/contacts-map/Makefile.am @@ -0,0 +1,31 @@ +AM_CPPFLAGS = \ + -I$(top_srcdir) \ + -I$(top_srcdir)/widgets \ + $(EVOLUTION_ADDRESSBOOK_CFLAGS) \ + $(CHAMPLAIN_CFLAGS) \ + $(GEOCLUE_CFLAGS) + +@EVO_PLUGIN_RULE@ + +plugin_DATA = org-gnome-contacts-map.eplug +plugin_LTLIBRARIES = liborg-gnome-contacts-map.la + +liborg_gnome_contacts_map_la_SOURCES = \ + contacts-map.c \ + geo-utils.c \ + geo-utils.h + +liborg_gnome_contacts_map_la_LDFLAGS = -module -avoid-version $(NO_UNDEFINED) +liborg_gnome_contacts_map_la_LIBADD = \ + $(top_builddir)/e-util/libeutil.la \ + $(top_builddir)/shell/libeshell.la \ + $(CHAMPLAIN_LIBS) \ + $(GEOCLUE_LIBS) \ + $(EVOLUTION_ADDRESSBOOK_LIBS) + +EXTRA_DIST = org-gnome-contacts-maps.eplug.xml + +BUILT_SOURCES = $(plugin_DATA) +CLEANFILES = $(BUILT_SOURCES) + +-include $(top_srcdir)/git.mk diff --git a/plugins/contacts-map/contacts-map.c b/plugins/contacts-map/contacts-map.c new file mode 100644 index 0000000000..8961233587 --- /dev/null +++ b/plugins/contacts-map/contacts-map.c @@ -0,0 +1,216 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * This program 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + * + * Authors: + * Cedric Bosdonnat <cedric.bosdonnat@free.fr> + * + * Copyright (C) 2009 Cedric Bosdonnat (http://cedric.bosdonnat.free.fr) + * + */ +#include "geo-utils.h" + +#include <glib/gi18n.h> + +#include <libedataserver/e-source.h> +#include <libedataserverui/e-source-selector.h> + +#include <shell/e-shell-sidebar.h> +#include <shell/e-shell-view.h> +#include <shell/e-shell-window.h> + + +/* Plugin entry points */ + +gboolean addressbook_map_init (GtkUIManager *ui_manager, EShellView *shell_view); +void action_show_ebook_map (GtkAction *action, EShellView *shell_view); +void show_map_general (ESourceSelector *selector); + +/* Implementations */ + +gboolean +addressbook_map_init (GtkUIManager *ui_manager, EShellView *shell_view) +{ + EShell *shell; + EShellSettings *shell_settings; + EShellWindow *shell_window; + GtkActionGroup *action_group; + GtkAction *action; + GIcon *icon; + const gchar *tooltip; + const gchar *name; + const gchar *label; + + shell_window = e_shell_view_get_shell_window (shell_view); + shell = e_shell_window_get_shell (shell_window); + shell_settings = e_shell_get_shell_settings (shell); + + name = "contacts-map"; + label = _("Contacts map"); + tooltip = _("Show a map of all the contacts"); + action = gtk_action_new (name, NULL, tooltip, NULL); + icon = g_themed_icon_new ("gnome-globe"); + gtk_action_set_gicon (action, icon); + gtk_action_set_label (action, label); + + name = "contacts"; + action_group = e_shell_window_get_action_group (shell_window, name); + gtk_action_group_add_action (action_group, action); + + g_signal_connect ( + action, "activate", + G_CALLBACK (action_show_ebook_map), shell_view); + + g_object_unref (action); + + return TRUE; +} + + +void +action_show_ebook_map (GtkAction *action, EShellView *shell_view) +{ + EShellSidebar *shell_sidebar; + ESourceSelector *selector = NULL; + + shell_sidebar = e_shell_view_get_shell_sidebar (shell_view); + g_object_get (shell_sidebar, "selector", &selector, NULL); + g_return_if_fail (selector != NULL); + + show_map_general (selector); + + g_object_unref (selector); +} + + +void +show_map_general (ESourceSelector *selector) +{ + EBook *book; + ESource *primary_source; + EBookQuery *query; + GList *contacts, *tmp; + gchar *uri; + + GeoclueGeocode *geocoder; + GeocluePositionFields fields; + GeoclueAccuracy *accuracy; + + gdouble lat = 0; + gdouble lng = 0; + + GtkWidget *map_widget; + ChamplainView *view; + ChamplainLayer *layer; + + gdouble *min_lat = NULL; + gdouble *max_lat = NULL; + gdouble *min_lng = NULL; + gdouble *max_lng = NULL; + + primary_source = (ESource*)e_source_selector_peek_primary_selection (selector); + uri = e_source_get_uri (primary_source); + book = e_book_new_from_uri (uri, NULL); + + if (!book || !e_book_open (book, TRUE, NULL)) + { + g_warning ("Couldn't load addressbook %s", uri); + return; + } + + /* Get all the contacts with an address */ + query = e_book_query_field_exists (E_CONTACT_ADDRESS); + e_book_get_contacts (book, query, &contacts, NULL); + e_book_query_unref (query); + + init_map (&view, &map_widget); + layer = champlain_selection_layer_new (); + + geocoder = NULL; + geocoder = get_geocoder (); + if (geocoder != NULL) { + for (tmp = contacts; tmp; tmp = tmp->next) { + GError *error = NULL; + EContact *contact; + EContactAddress *addr; + GHashTable *details; + + contact = tmp->data; + + /* Get the lat & lng and add the marker asynchronously */ + addr = e_contact_get (contact, E_CONTACT_ADDRESS_HOME); + details = (GHashTable*) get_geoclue_from_address (addr); + fields = geoclue_geocode_address_to_position (geocoder, details, + &lat, &lng, NULL, &accuracy, &error); + + if (!error && + (fields & GEOCLUE_POSITION_FIELDS_LATITUDE) != 0 && + (fields & GEOCLUE_POSITION_FIELDS_LONGITUDE) != 0) { + /* Add the marker to the map */ + add_marker (layer, lat, lng, contact); + if (!min_lat) { + min_lat = g_malloc (sizeof (gdouble)); + *min_lat = lat; + } + if (!max_lat) { + max_lat = g_malloc (sizeof(gdouble)); + *max_lat = lat; + } + if (!min_lng) { + min_lng = g_malloc (sizeof (gdouble)); + *min_lng = lng; + } + if (!max_lng) { + max_lng = malloc (sizeof (gdouble)); + *max_lng = lng; + } + + /* Store the min/max lat/lng */ + get_min_max (min_lat, max_lat, + min_lng, max_lng, lat, lng); + } else if (error) { + g_warning ("Error while geocoding: %s\n", error->message); + g_error_free (error); + } + + g_hash_table_destroy (details); + g_object_unref (contact); + } + } + + champlain_view_add_layer (view, layer); + champlain_layer_show (layer); + champlain_layer_show_all_markers (CHAMPLAIN_LAYER (layer)); + + create_map_window (map_widget, _("Contacts map")); + + /* Do not ensure something visible is we have nothing */ + if (min_lat && min_lng && max_lat && max_lng) + champlain_view_ensure_visible (view, + *min_lat, *min_lng, + *max_lat, *max_lng, FALSE); + + g_free (min_lat); + g_free (max_lat); + g_free (min_lng); + g_free (max_lng); + + g_object_unref (geocoder); + + if (contacts != NULL) + g_list_free (contacts); + + g_object_unref (book); + g_free (uri); +} diff --git a/plugins/contacts-map/geo-utils.c b/plugins/contacts-map/geo-utils.c new file mode 100644 index 0000000000..3f7473cab4 --- /dev/null +++ b/plugins/contacts-map/geo-utils.c @@ -0,0 +1,102 @@ +#include "geo-utils.h" + +static gboolean is_clutter_initialized = FALSE; + +void +get_min_max (gdouble *min_lat, gdouble *max_lat, + gdouble *min_lng, gdouble *max_lng, + gdouble lat, gdouble lng) +{ + if (lat < *min_lat) + *min_lat = lat; + else if (lat > *max_lat) + *max_lat = lat; + + if (lng < *min_lng) + *min_lng = lng; + else if (lng > *max_lng) + *max_lng = lng; +} + +void +add_marker (ChamplainLayer *layer, gdouble lat, gdouble lng, EContact *contact) +{ + ClutterActor *marker; + + gchar *contact_name = e_contact_get (contact, E_CONTACT_FULL_NAME); + marker = champlain_marker_new_with_text (contact_name, "Serif 8", NULL, NULL); + g_free (contact_name); + + champlain_marker_set_use_markup (CHAMPLAIN_MARKER (marker), FALSE); + champlain_base_marker_set_position (CHAMPLAIN_BASE_MARKER (marker), lat, lng); + + champlain_layer_add_marker (layer, CHAMPLAIN_BASE_MARKER(marker)); +} + +GeoclueGeocode* +get_geocoder (void) +{ + GeoclueGeocode *geocoder = NULL; + + /* Create new GeoclueGeocode */ + geocoder = geoclue_geocode_new ("org.freedesktop.Geoclue.Providers.Yahoo", + "/org/freedesktop/Geoclue/Providers/Yahoo"); + + return geocoder; +} + +GHashTable * +get_geoclue_from_address (const EContactAddress* addr) +{ + GHashTable *address = geoclue_address_details_new (); + + g_hash_table_insert (address, g_strdup (GEOCLUE_ADDRESS_KEY_POSTALCODE), g_strdup ((*addr).code)); + g_hash_table_insert (address, g_strdup (GEOCLUE_ADDRESS_KEY_COUNTRY), g_strdup ((*addr).country)); + g_hash_table_insert (address, g_strdup (GEOCLUE_ADDRESS_KEY_LOCALITY), g_strdup ((*addr).locality)); + g_hash_table_insert (address, g_strdup (GEOCLUE_ADDRESS_KEY_STREET), g_strdup ((*addr).street)); + + return address; +} + +void +init_map (ChamplainView **view, GtkWidget **widget) +{ + if (!is_clutter_initialized) { + gtk_clutter_init (NULL, NULL); + is_clutter_initialized = TRUE; + } + + *widget = gtk_champlain_embed_new (); + *view = gtk_champlain_embed_get_view (GTK_CHAMPLAIN_EMBED (*widget)); + + champlain_view_set_show_license (*view, FALSE); + + g_object_set (G_OBJECT (*view), "scroll-mode", CHAMPLAIN_SCROLL_MODE_KINETIC, + "zoom-level", 9, NULL); +} + +void +create_map_window (GtkWidget *map_widget, const gchar *title) +{ + GtkWidget *window, *viewport; + + /* create the main, top level, window */ + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + /* give the window a 10px wide border */ + gtk_container_set_border_width (GTK_CONTAINER (window), 10); + + /* give it the title */ + gtk_window_set_title (GTK_WINDOW (window), title ); + + gtk_widget_set_size_request (map_widget, 300, 300); + + viewport = gtk_frame_new (NULL); + gtk_container_add (GTK_CONTAINER (viewport), map_widget); + + /* and insert it into the main window */ + gtk_container_add (GTK_CONTAINER (window), viewport); + + /* make sure that everything, window and label, are visible */ + gtk_widget_show_all (window); +} diff --git a/plugins/contacts-map/geo-utils.h b/plugins/contacts-map/geo-utils.h new file mode 100644 index 0000000000..65248f4893 --- /dev/null +++ b/plugins/contacts-map/geo-utils.h @@ -0,0 +1,28 @@ +#include <gtk/gtk.h> +#include <glib.h> + +#include <libebook/e-book.h> +#include <libebook/e-contact.h> + +#include <geoclue/geoclue-geocode.h> +#include <champlain/champlain.h> +#include <champlain-gtk/champlain-gtk.h> +#include <clutter-gtk/clutter-gtk.h> + +void +get_min_max (gdouble *min_lat, gdouble *max_lat, + gdouble *min_lng, gdouble *max_lng, + gdouble lat, gdouble lng); + +GeoclueGeocode *get_geocoder (void); + +void add_marker ( + ChamplainLayer *layer, + gdouble lat, gdouble lng, + EContact *contact); + +GHashTable *get_geoclue_from_address (const EContactAddress* addr); + +void init_map (ChamplainView **view, GtkWidget **widget); + +void create_map_window (GtkWidget *map_widget, const gchar *title); diff --git a/plugins/contacts-map/org-gnome-contacts-map.eplug.xml b/plugins/contacts-map/org-gnome-contacts-map.eplug.xml new file mode 100644 index 0000000000..e695979491 --- /dev/null +++ b/plugins/contacts-map/org-gnome-contacts-map.eplug.xml @@ -0,0 +1,19 @@ +<?xml version="1.0"?> +<e-plugin-list> + <e-plugin id="org.gnome.evolution.contacts_maps" type="shlib" _name="Map for contacts" + location="@PLUGINDIR@/liborg-gnome-contacts-map@SOEXT@"> + <author name="Cedric Bosdonnat" email="cedric.bosdonnat.ooo@free.fr"/> + <_description>Add a map showing the location of contacts when possible.</_description> + + <hook class="org.gnome.evolution.ui:1.0"> + <ui-manager id="org.gnome.evolution.contacts" callback="addressbook_map_init"> + <!-- Add something for contact-popup --> + <popup name="address-book-popup"> + <menuitem action="contacts-map"/> + </popup> + </ui-manager> + </hook> + + </e-plugin> +</e-plugin-list> + diff --git a/po/POTFILES.in b/po/POTFILES.in index 8079cb875e..3e1e016d4c 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -295,6 +295,8 @@ plugins/calendar-http/calendar-http.c plugins/calendar-http/org-gnome-calendar-http.eplug.xml plugins/calendar-weather/calendar-weather.c plugins/calendar-weather/org-gnome-calendar-weather.eplug.xml +plugins/contacts-map/contacts-map.c +plugins/contacts-map/org-gnome-contacts-map.eplug.xml plugins/default-mailer/apps-evolution-mail-prompts-checkdefault.schemas.in plugins/default-mailer/org-gnome-default-mailer.eplug.xml plugins/default-mailer/org-gnome-default-mailer.error.xml |