diff options
author | Jonas Danielsson <jonas@threetimestwo.org> | 2014-12-16 07:45:33 -0500 |
---|---|---|
committer | Jonas Danielsson <jonas@threetimestwo.org> | 2014-12-16 07:45:33 -0500 |
commit | 9ec57f6dc6a66acd1f4e8f0b1ecd202491caa8df (patch) | |
tree | 509d7a9917aa5c360e6687fd63b732d1c054dba3 | |
parent | b8fb54534e33e863aecd20af516bd4b16ef2d313 (diff) | |
parent | 2bc3aae06ec98d9e93126531750295d975bc1bbf (diff) | |
download | gnome-contacts-wip/map-widget.tar.gz |
Merge branch 'fixup' into wip/map-widgetwip/map-widget
src/contacts-app.vala
-rw-r--r-- | configure.ac | 4 | ||||
-rw-r--r-- | data/Makefile.am | 1 | ||||
-rw-r--r-- | data/contacts.gresource.xml | 1 | ||||
-rw-r--r-- | data/ui/contacts-address-map.ui | 37 | ||||
-rw-r--r-- | data/ui/style.css | 5 | ||||
-rw-r--r-- | src/Makefile.am | 1 | ||||
-rw-r--r-- | src/contacts-address-map.vala | 206 | ||||
-rw-r--r-- | src/contacts-app.vala | 2 | ||||
-rw-r--r-- | src/contacts-contact-sheet.vala | 7 | ||||
-rw-r--r-- | src/contacts-contact.vala | 34 |
10 files changed, 296 insertions, 2 deletions
diff --git a/configure.ac b/configure.ac index a7702fa..72c4f3b 100644 --- a/configure.ac +++ b/configure.ac @@ -50,10 +50,12 @@ pkg_modules="gtk+-3.0 >= 3.12.0 libedataserver-1.2 >= 3.5.3 goa-1.0 gee-0.8 + champlain-gtk-0.12 + geocode-glib-1.0 " PKG_CHECK_MODULES(CONTACTS, [$pkg_modules]) -CONTACTS_PACKAGES="--pkg gtk+-3.0 --pkg gio-2.0 --pkg gio-unix-2.0 --pkg folks --pkg folks-telepathy --pkg folks-eds --pkg libnotify" +CONTACTS_PACKAGES="--pkg gtk+-3.0 --pkg gio-2.0 --pkg gio-unix-2.0 --pkg folks --pkg folks-telepathy --pkg folks-eds --pkg libnotify --pkg clutter-1.0 --pkg champlain-0.12 --pkg champlain-gtk-0.12 --pkg geocode-glib-1.0" AC_SUBST(CONTACTS_PACKAGES) # Optional dependency for the user accounts panel diff --git a/data/Makefile.am b/data/Makefile.am index 821828c..89fda4d 100644 --- a/data/Makefile.am +++ b/data/Makefile.am @@ -37,6 +37,7 @@ EXTRA_DIST = \ org.gnome.Contacts.search-provider.ini.in.in \ contacts.gresource.xml \ ui/app-menu.ui \ + ui/contacts-address-map.ui \ ui/contacts-window.ui \ ui/contacts-list-pane.ui \ ui/style.css \ diff --git a/data/contacts.gresource.xml b/data/contacts.gresource.xml index 2b1ba03..98bfee4 100644 --- a/data/contacts.gresource.xml +++ b/data/contacts.gresource.xml @@ -3,6 +3,7 @@ <gresource prefix="/org/gnome/contacts"> <file compressed="true">ui/style.css</file> <file compressed="true" preprocess="xml-stripblanks">ui/app-menu.ui</file> + <file compressed="true" preprocess="xml-stripblanks">ui/contacts-address-map.ui</file> <file compressed="true" preprocess="xml-stripblanks">ui/contacts-window.ui</file> <file compressed="true" preprocess="xml-stripblanks">ui/contacts-list-pane.ui</file> </gresource> diff --git a/data/ui/contacts-address-map.ui b/data/ui/contacts-address-map.ui new file mode 100644 index 0000000..60069cc --- /dev/null +++ b/data/ui/contacts-address-map.ui @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="UTF-8"?> +<interface> + <!-- interface-requires gtk+ 3.10 --> + <template class="ContactsAddressMap" parent="GtkFrame"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="hexpand">False</property> + <property name="hexpand_set">True</property> + <property name="shadow_type">in</property> + <property name="width_request">300</property> + <property name="height_request">300</property> + <style> + <class name="contacts-map"/> + </style> + <child> + <object class="GtkStack" id="map_stack"> + <property name="visible">True</property> + <child> + <object class="GtkImage" id="map_icon"> + <property name="name">mark-location-image</property> + <property name="visible">True</property> + <property name="halign">center</property> + <property name="valign">center</property> + <property name="icon-name">mark-location-symbolic</property> + <property name="pixel-size">48</property> + </object> + </child> + <child> + <object class="GtkGrid" id="map_grid"> + <property name="orientation">vertical</property> + <property name="visible">True</property> + </object> + </child> + </object> + </child> + </template> +</interface> diff --git a/data/ui/style.css b/data/ui/style.css index 92647a7..8432977 100644 --- a/data/ui/style.css +++ b/data/ui/style.css @@ -10,6 +10,11 @@ ContactsListPane.frame:dir(rtl) { border-width: 0 0 0 1px; } +.contacts-map { + background-color: @theme_bg_color; + color: gray; +} + /* contatcs view new color */ .contacts-view { background-color: transparent; diff --git a/src/Makefile.am b/src/Makefile.am index a175980..87a4431 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -25,6 +25,7 @@ bin_PROGRAMS = gnome-contacts vala_sources = \ contacts-app.vala \ + contacts-address-map.vala \ contacts-contact.vala \ contacts-contact-sheet.vala \ contacts-contact-editor.vala \ diff --git a/src/contacts-address-map.vala b/src/contacts-address-map.vala new file mode 100644 index 0000000..7c97ff9 --- /dev/null +++ b/src/contacts-address-map.vala @@ -0,0 +1,206 @@ +/* -*- Mode: vala; indent-tabs-mode: t; c-basic-offset: 2; tab-width: 8 -*- */ +/* + * + * This program 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. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +using Champlain; +using Folks; +using Geocode; +using Gee; +using Gtk; +using GtkChamplain; + +[GtkTemplate (ui = "/org/gnome/contacts/ui/contacts-address-map.ui")] +public class Contacts.AddressMap : Frame { + + [GtkChild] + private Stack map_stack; + + [GtkChild] + private Grid map_grid; + + [GtkChild] + private Gtk.Image map_icon; + + private Set<PostalAddressFieldDetails> addresses; + private GLib.List<Place> found_places; + private Champlain.View map_view; + private MarkerLayer marker_layer; + private Mutex mutex; + private ulong alloc_id = 0; + + public AddressMap (Contact c, Set<PostalAddressFieldDetails> postal_addresses) { + var map = new Embed (); + var map_factory = MapSourceFactory.dup_default (); + map_grid.add (map); + + map_view = map.get_view (); + map_view.set_map_source (map_factory.create (MAP_SOURCE_OSM_MAPQUEST)); + map_view.zoom_level = map_view.max_zoom_level - 2; + + marker_layer = new MarkerLayer (); + map_view.add_layer (marker_layer); + + /* This is a hack to make sure we do not get the FLEUR + * drag cursor on click. Ideally champlain would let us + * turn this of with a property. */ + map.get_child ().button_press_event.connect (() => { + map.get_child ().get_window ().set_cursor (null); + return false; + }); + + /* Do not propagate event to the Champlain clutter stage */ + map_view.get_stage ().captured_event.connect (() => { return true; }); + + map.button_press_event.connect(() => { + activate_action ("org.gnome.Maps", + "show-contact", + new Variant ("s", c.individual.id), + Gtk.get_current_event_time ()); + return true; + }); + + addresses = postal_addresses; + found_places = new GLib.List<Place>(); + mutex = Mutex (); + } + + public void load () { + map_stack.visible_child = map_icon; + var geocodes = 0; + + foreach (var addr in addresses) { + Contact.geocode_address.begin (addr.value, (object, res) => { + mutex.lock (); + + var place = Contact.geocode_address.end (res); + geocodes++; + + if (place != null) + found_places.prepend (place); + + if (geocodes == addresses.size && found_places.length () > 0) + show_map (); + + mutex.unlock (); + }); + } + } + + private void show_pin () { + var theme = IconTheme.get_default (); + var actor = new Clutter.Actor (); + + try { + var pixbuf = theme.load_icon ("maps-pin", 0, 0); + var image = new Clutter.Image (); + + image.set_data (pixbuf.get_pixels (), + Cogl.PixelFormat.RGBA_8888, + pixbuf.get_width (), + pixbuf.get_height (), + pixbuf.get_rowstride ()); + + + actor.set_content (image); + actor.set_size (pixbuf.get_width (), + pixbuf.get_height ()); + } catch (GLib.Error e) { + /* No good things to do here */ + } + + var marker = new Marker (); + var place = found_places.nth_data (0); + + marker.latitude = place.location.latitude; + marker.longitude = place.location.longitude; + + marker.add_child (actor); + marker_layer.add_marker (marker); + } + + private void show_labels () { + foreach (var place in found_places) { + var label = new Champlain.Label (); + + /* Getting street address resolution (house number) + * from OpenStreetMap is quite rare unfortunately */ + if (place.street_address != null) + label.text = place.street_address; + else + label.text = place.street; + + label.latitude = place.location.latitude; + label.longitude = place.location.longitude; + marker_layer.add_marker(label); + } + } + + void on_allocation_changed () { + if (alloc_id == 0) + return; + + var markers = (marker_layer as Clutter.Actor).get_children (); + if ((markers.nth_data (0) as Marker).height == 0) + return; + + marker_layer.disconnect (alloc_id); + alloc_id = 0; + + if (found_places.length () == 1) { + var place = found_places.nth_data (0); + + map_view.center_on (place.location.latitude, + place.location.longitude); + } else { + var bbox = new Champlain.BoundingBox (); + + /* Make sure that the markers are visible */ + foreach (var marker in markers) { + var x = map_view.longitude_to_x ((marker as Marker).longitude); + var y = map_view.latitude_to_y ((marker as Marker).latitude); + + /* 256 is the only supported tile size in Champlain */ + var lat = map_view.y_to_latitude (y - marker.height * 256); + var lon = map_view.x_to_longitude (x + marker.width * 256); + + bbox.extend (lat, lon); + bbox.extend ((marker as Marker).latitude, + (marker as Marker).longitude); + } + map_view.ensure_visible (bbox, false); + } + } + + private void show_map () { + if (found_places.length () == 0) { + map_stack.visible_child = map_icon; + return; + } + + if (found_places.length () == 1) { + show_pin (); + } else { + show_labels (); + } + + map_stack.visible_child = map_grid; + + /* We need to make sure that the markers knows about their width + * before we calculate the visible bounding box and show + * the markers.*/ + alloc_id = marker_layer.allocation_changed.connect (on_allocation_changed); + } +} diff --git a/src/contacts-app.vala b/src/contacts-app.vala index 5dc270b..34b921d 100644 --- a/src/contacts-app.vala +++ b/src/contacts-app.vala @@ -267,7 +267,7 @@ public class Contacts.App : Gtk.Application { public override void activate () { var icon_theme = IconTheme.get_default (); - icon_theme.append_search_path(Config.PKGDATADIR + "/icons"); + icon_theme.append_search_path (Config.PKGDATADIR + "/icons"); /* window creation code */ if (window == null) { diff --git a/src/contacts-contact-sheet.vala b/src/contacts-contact-sheet.vala index 0582615..37b7330 100644 --- a/src/contacts-contact-sheet.vala +++ b/src/contacts-contact-sheet.vala @@ -221,6 +221,13 @@ public class Contacts.ContactSheet : Grid { } add_row_with_label (ref i, TypeSet.general.format_type (addr), all_strs); } + + if (addr_details.postal_addresses.size > 0) { + var map = new AddressMap (c, addr_details.postal_addresses); + map.load (); + attach (map, 1, i, 1, 1); + i++; + } } if (i != 3) diff --git a/src/contacts-contact.vala b/src/contacts-contact.vala index b3c14da..4078a75 100644 --- a/src/contacts-contact.vala +++ b/src/contacts-contact.vala @@ -20,6 +20,7 @@ using Gtk; using Folks; using Gee; using TelepathyGLib; +using Geocode; public errordomain ContactError { NOT_IMPLEMENTED, @@ -672,6 +673,39 @@ public class Contacts.Contact : GLib.Object { return res; } + public static async Place geocode_address (PostalAddress addr) { + SourceFunc callback = geocode_address.callback; + var params = new HashTable<string, GLib.Value?>(str_hash, str_equal); + + if (is_set (addr.street)) + params.insert("street", addr.street); + + if (is_set (addr.locality)) + params.insert("locality", addr.locality); + + if (is_set (addr.region)) + params.insert("region", addr.region); + + if (is_set (addr.country)) + params.insert("country", addr.country); + + Place? place = null; + var forward = new Forward.for_params (params); + forward.search_async.begin (null, (object, res) => { + try { + var places = forward.search_async.end (res); + + place = places.nth_data (0); + callback (); + } catch (GLib.Error e) { + debug ("No geocode result found for contact"); + callback (); + } + }); + yield; + return place; + } + public static string[] format_address (PostalAddress addr) { string[] lines = {}; |