parent
4d94dfe842
commit
61fe4bf7cc
7 changed files with 249 additions and 2 deletions
|
@ -50,11 +50,13 @@ pkg_modules="gtk+-3.0 >= 3.12.0
|
||||||
libedataserver-1.2 >= 3.5.3
|
libedataserver-1.2 >= 3.5.3
|
||||||
goa-1.0
|
goa-1.0
|
||||||
gee-0.8
|
gee-0.8
|
||||||
geocode-glib-1.0
|
champlain-0.12
|
||||||
|
clutter-gtk-1.0
|
||||||
|
geocode-glib-1.0 >= 3.15.3
|
||||||
"
|
"
|
||||||
PKG_CHECK_MODULES(CONTACTS, [$pkg_modules])
|
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 --pkg geocode-glib-1.0"
|
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 clutter-gtk-1.0 --pkg champlain-0.12 --pkg geocode-glib-1.0"
|
||||||
AC_SUBST(CONTACTS_PACKAGES)
|
AC_SUBST(CONTACTS_PACKAGES)
|
||||||
|
|
||||||
# Optional dependency for the user accounts panel
|
# Optional dependency for the user accounts panel
|
||||||
|
|
|
@ -37,6 +37,7 @@ EXTRA_DIST = \
|
||||||
org.gnome.Contacts.search-provider.ini.in.in \
|
org.gnome.Contacts.search-provider.ini.in.in \
|
||||||
contacts.gresource.xml \
|
contacts.gresource.xml \
|
||||||
ui/app-menu.ui \
|
ui/app-menu.ui \
|
||||||
|
ui/contacts-address-map.ui \
|
||||||
ui/contacts-window.ui \
|
ui/contacts-window.ui \
|
||||||
ui/contacts-list-pane.ui \
|
ui/contacts-list-pane.ui \
|
||||||
ui/style.css \
|
ui/style.css \
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
<gresource prefix="/org/gnome/contacts">
|
<gresource prefix="/org/gnome/contacts">
|
||||||
<file compressed="true">ui/style.css</file>
|
<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/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-window.ui</file>
|
||||||
<file compressed="true" preprocess="xml-stripblanks">ui/contacts-list-pane.ui</file>
|
<file compressed="true" preprocess="xml-stripblanks">ui/contacts-list-pane.ui</file>
|
||||||
</gresource>
|
</gresource>
|
||||||
|
|
40
data/ui/contacts-address-map.ui
Normal file
40
data/ui/contacts-address-map.ui
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
<?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>
|
||||||
|
<property name="valign">start</property>
|
||||||
|
<property name="halign">start</property>
|
||||||
|
<style>
|
||||||
|
<class name="contacts-map"/>
|
||||||
|
<class name="dim-label"/>
|
||||||
|
</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>
|
|
@ -10,6 +10,10 @@ ContactsListPane.frame:dir(rtl) {
|
||||||
border-width: 0 0 0 1px;
|
border-width: 0 0 0 1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.contacts-map {
|
||||||
|
background-color: @theme_bg_color;
|
||||||
|
}
|
||||||
|
|
||||||
/* contatcs view new color */
|
/* contatcs view new color */
|
||||||
.contacts-view {
|
.contacts-view {
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
|
|
|
@ -25,6 +25,7 @@ bin_PROGRAMS = gnome-contacts
|
||||||
|
|
||||||
vala_sources = \
|
vala_sources = \
|
||||||
contacts-app.vala \
|
contacts-app.vala \
|
||||||
|
contacts-address-map.vala \
|
||||||
contacts-contact.vala \
|
contacts-contact.vala \
|
||||||
contacts-contact-sheet.vala \
|
contacts-contact-sheet.vala \
|
||||||
contacts-contact-editor.vala \
|
contacts-contact-editor.vala \
|
||||||
|
|
198
src/contacts-address-map.vala
Normal file
198
src/contacts-address-map.vala
Normal file
|
@ -0,0 +1,198 @@
|
||||||
|
/* -*- 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/>.
|
||||||
|
*
|
||||||
|
* Author: Jonas Danielsson <jonas@threetimestwo.org>
|
||||||
|
*/
|
||||||
|
|
||||||
|
using Champlain;
|
||||||
|
using Folks;
|
||||||
|
using Gdk;
|
||||||
|
using Gee;
|
||||||
|
using Geocode;
|
||||||
|
using Gtk;
|
||||||
|
using GtkClutter;
|
||||||
|
|
||||||
|
[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 = new Champlain.View ();
|
||||||
|
map_view.set_map_source (map_factory.create (MAP_SOURCE_OSM_MAPQUEST));
|
||||||
|
map_view.zoom_level = map_view.max_zoom_level - 2;
|
||||||
|
map.get_stage ().add_child (map_view);
|
||||||
|
|
||||||
|
marker_layer = new MarkerLayer ();
|
||||||
|
map_view.add_layer (marker_layer);
|
||||||
|
|
||||||
|
/* Disable all events for the map */
|
||||||
|
map.get_stage ().captured_event.connect (() => { 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 ("mark-location", 32, 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;
|
||||||
|
|
||||||
|
Idle.add ( () => {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 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);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue