Contact map cleanups.

This commit is contained in:
Matthew Barnes
2013-10-31 09:35:50 -04:00
parent 8eb21abc04
commit 0baabd24ec
6 changed files with 454 additions and 434 deletions
+130 -131
View File
@@ -18,28 +18,24 @@
*
*/
#ifdef HAVE_CONFIG_H
/* This defines WITH_CONTACT_MAPS. */
#include <config.h>
#endif
#ifdef WITH_CONTACT_MAPS
#include "e-contact-map.h"
#include "e-contact-map-window.h"
#include "e-contact-marker.h"
#include <string.h>
#include <glib/gi18n.h>
#include <champlain/champlain.h>
#include <string.h>
#include <glib/gi18n.h>
#include <glib-object.h>
#include "e-contact-map.h"
#include "e-contact-marker.h"
#define E_CONTACT_MAP_WINDOW_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE \
((obj), E_TYPE_CONTACT_MAP_WINDOW, EContactMapWindowPrivate))
G_DEFINE_TYPE (EContactMapWindow, e_contact_map_window, GTK_TYPE_WINDOW)
(G_TYPE_INSTANCE_GET_PRIVATE \
((obj), E_TYPE_CONTACT_MAP_WINDOW, EContactMapWindowPrivate))
struct _EContactMapWindowPrivate {
EContactMap *map;
@@ -50,7 +46,8 @@ struct _EContactMapWindowPrivate {
GtkWidget *search_entry;
GtkListStore *completion_model;
GHashTable *hash_table; /* Hash table contact-name -> marker */
/* contact name -> marker */
GHashTable *hash_table;
GtkWidget *spinner;
gint tasks_cnt;
@@ -61,7 +58,12 @@ enum {
LAST_SIGNAL
};
static gint signals[LAST_SIGNAL] = {0};
static guint signals[LAST_SIGNAL];
G_DEFINE_TYPE (
EContactMapWindow,
e_contact_map_window,
GTK_TYPE_WINDOW)
static void
marker_doubleclick_cb (ClutterActor *actor,
@@ -78,37 +80,39 @@ marker_doubleclick_cb (ClutterActor *actor,
}
static void
book_contacts_received_cb (GObject *source_object,
GAsyncResult *result,
gpointer user_data)
contact_map_window_get_contacts_cb (GObject *source_object,
GAsyncResult *result,
gpointer user_data)
{
EContactMapWindow *window = user_data;
EBookClient *client = E_BOOK_CLIENT (source_object);
GSList *contacts = NULL, *p;
GError *error = NULL;
EContactMapWindow *window;
GSList *list = NULL, *link;
GError *local_error = NULL;
e_book_client_get_contacts_finish (client, result, &contacts, &error);
window = E_CONTACT_MAP_WINDOW (user_data);
if (error != NULL) {
e_book_client_get_contacts_finish (
E_BOOK_CLIENT (source_object),
result, &list, &local_error);
if (local_error != NULL) {
g_warning (
"%s: Failed to get contacts: %s",
G_STRFUNC, error->message);
g_error_free (error);
G_STRFUNC, local_error->message);
g_error_free (local_error);
}
for (p = contacts; p; p = p->next)
e_contact_map_add_contact (
window->priv->map, (EContact *) p->data);
for (link = list; link != NULL; link = g_slist_next (link)) {
EContact *contact = E_CONTACT (link->data);
e_contact_map_add_contact (window->priv->map, contact);
}
g_slist_free_full (contacts, (GDestroyNotify) g_object_unref);
g_object_unref (client);
g_slist_free_full (list, (GDestroyNotify) g_object_unref);
}
static void
contact_map_window_zoom_in_cb (GtkButton *button,
gpointer user_data)
EContactMapWindow *window)
{
EContactMapWindow *window = user_data;
ChamplainView *view;
view = e_contact_map_get_view (window->priv->map);
@@ -118,22 +122,23 @@ contact_map_window_zoom_in_cb (GtkButton *button,
static void
contact_map_window_zoom_out_cb (GtkButton *button,
gpointer user_data)
EContactMapWindow *window)
{
EContactMapWindow *window = user_data;
ChamplainView *view;
view = e_contact_map_get_view (window->priv->map);
champlain_view_zoom_out (view);
}
static void
zoom_level_changed_cb (ChamplainView *view,
GParamSpec *pspec,
gpointer user_data)
contact_map_window_zoom_level_changed_cb (ChamplainView *view,
GParamSpec *pspec,
EContactMapWindow *window)
{
EContactMapWindow *window = user_data;
gint zoom_level = champlain_view_get_zoom_level (view);
gint zoom_level;
zoom_level = champlain_view_get_zoom_level (view);
gtk_widget_set_sensitive (
window->priv->zoom_in_btn,
@@ -149,86 +154,90 @@ zoom_level_changed_cb (ChamplainView *view,
* that the contact has really been added to map.
*/
static void
map_contact_added_cb (EContactMap *map,
ClutterActor *marker,
gpointer user_data)
contact_map_window_contact_added_cb (EContactMap *map,
ClutterActor *marker,
EContactMapWindow *window)
{
EContactMapWindowPrivate *priv = E_CONTACT_MAP_WINDOW (user_data)->priv;
const gchar *name;
GtkListStore *list_store;
GtkTreeIter iter;
const gchar *name;
name = champlain_label_get_text (CHAMPLAIN_LABEL (marker));
g_hash_table_insert (
priv->hash_table,
window->priv->hash_table,
g_strdup (name), marker);
gtk_list_store_append (priv->completion_model, &iter);
gtk_list_store_set (
priv->completion_model, &iter,
0, name, -1);
list_store = window->priv->completion_model;
gtk_list_store_append (list_store, &iter);
gtk_list_store_set (list_store, &iter, 0, name, -1);
g_signal_connect (
marker, "double-clicked",
G_CALLBACK (marker_doubleclick_cb), user_data);
G_CALLBACK (marker_doubleclick_cb), window);
priv->tasks_cnt--;
if (priv->tasks_cnt == 0) {
gtk_spinner_stop (GTK_SPINNER (priv->spinner));
gtk_widget_hide (priv->spinner);
window->priv->tasks_cnt--;
if (window->priv->tasks_cnt == 0) {
gtk_spinner_stop (GTK_SPINNER (window->priv->spinner));
gtk_widget_hide (window->priv->spinner);
}
}
static void
map_contact_removed_cb (EContactMap *map,
const gchar *name,
gpointer user_data)
contact_map_window_contact_removed_cb (EContactMap *map,
const gchar *name,
EContactMapWindow *window)
{
EContactMapWindowPrivate *priv = E_CONTACT_MAP_WINDOW (user_data)->priv;
GtkListStore *list_store;
GtkTreeModel *tree_model;
GtkTreeIter iter;
GtkTreeModel *model = GTK_TREE_MODEL (priv->completion_model);
gboolean iter_valid;
g_hash_table_remove (priv->hash_table, name);
list_store = window->priv->completion_model;
tree_model = GTK_TREE_MODEL (list_store);
if (gtk_tree_model_get_iter_first (model, &iter)) {
do {
gchar *name_str;
gtk_tree_model_get (model, &iter, 0, &name_str, -1);
if (g_ascii_strcasecmp (name_str, name) == 0) {
g_free (name_str);
gtk_list_store_remove (priv->completion_model, &iter);
break;
}
g_free (name_str);
} while (gtk_tree_model_iter_next (model, &iter));
g_hash_table_remove (window->priv->hash_table, name);
iter_valid = gtk_tree_model_get_iter_first (tree_model, &iter);
while (iter_valid) {
gchar *name_str;
gboolean match;
gtk_tree_model_get (tree_model, &iter, 0, &name_str, -1);
match = (g_ascii_strcasecmp (name_str, name) == 0);
g_free (name_str);
if (match) {
gtk_list_store_remove (list_store, &iter);
break;
}
iter_valid = gtk_tree_model_iter_next (tree_model, &iter);
}
}
static void
map_contact_geocoding_started_cb (EContactMap *map,
ClutterActor *marker,
gpointer user_data)
contact_map_window_geocoding_started_cb (EContactMap *map,
ClutterActor *marker,
EContactMapWindow *window)
{
EContactMapWindowPrivate *priv = E_CONTACT_MAP_WINDOW (user_data)->priv;
gtk_spinner_start (GTK_SPINNER (window->priv->spinner));
gtk_widget_show (window->priv->spinner);
gtk_spinner_start (GTK_SPINNER (priv->spinner));
gtk_widget_show (priv->spinner);
priv->tasks_cnt++;
window->priv->tasks_cnt++;
}
static void
map_contact_geocoding_failed_cb (EContactMap *map,
const gchar *name,
gpointer user_data)
contact_map_window_geocoding_failed_cb (EContactMap *map,
const gchar *name,
EContactMapWindow *window)
{
EContactMapWindowPrivate *priv = E_CONTACT_MAP_WINDOW (user_data)->priv;
window->priv->tasks_cnt--;
priv->tasks_cnt--;
if (priv->tasks_cnt == 0) {
gtk_spinner_stop (GTK_SPINNER (priv->spinner));
gtk_widget_hide (priv->spinner);
if (window->priv->tasks_cnt == 0) {
gtk_spinner_stop (GTK_SPINNER (window->priv->spinner));
gtk_widget_hide (window->priv->spinner);
}
}
@@ -279,42 +288,37 @@ entry_completion_match_selected_cb (GtkEntryCompletion *widget,
return TRUE;
}
static void
contact_map_window_finalize (GObject *object)
{
EContactMapWindowPrivate *priv;
priv = E_CONTACT_MAP_WINDOW (object)->priv;
if (priv->hash_table) {
g_hash_table_destroy (priv->hash_table);
priv->hash_table = NULL;
}
/* Chain up to parent's finalize() method. */
G_OBJECT_CLASS (e_contact_map_window_parent_class)->finalize (object);
}
static void
contact_map_window_dispose (GObject *object)
{
EContactMapWindowPrivate *priv;
priv = E_CONTACT_MAP_WINDOW (object)->priv;
priv = E_CONTACT_MAP_WINDOW_GET_PRIVATE (object);
if (priv->map) {
if (priv->map != NULL) {
gtk_widget_destroy (GTK_WIDGET (priv->map));
priv->map = NULL;
}
if (priv->completion_model) {
g_object_unref (priv->completion_model);
priv->completion_model = NULL;
}
g_clear_object (&priv->completion_model);
/* Chain up to parent's dispose() method. */
G_OBJECT_CLASS (e_contact_map_window_parent_class)->dispose (object);
}
static void
contact_map_window_finalize (GObject *object)
{
EContactMapWindowPrivate *priv;
priv = E_CONTACT_MAP_WINDOW_GET_PRIVATE (object);
g_hash_table_destroy (priv->hash_table);
/* Chain up to parent's finalize() method. */
G_OBJECT_CLASS (e_contact_map_window_parent_class)->finalize (object);
}
static void
e_contact_map_window_class_init (EContactMapWindowClass *class)
{
@@ -323,8 +327,8 @@ e_contact_map_window_class_init (EContactMapWindowClass *class)
g_type_class_add_private (class, sizeof (EContactMapWindowPrivate));
object_class = G_OBJECT_CLASS (class);
object_class->finalize = contact_map_window_finalize;
object_class->dispose = contact_map_window_dispose;
object_class->finalize = contact_map_window_finalize;
signals[SHOW_CONTACT_EDITOR] = g_signal_new (
"show-contact-editor",
@@ -371,19 +375,19 @@ e_contact_map_window_init (EContactMapWindow *window)
priv->map = E_CONTACT_MAP (map);
g_signal_connect (
view, "notify::zoom-level",
G_CALLBACK (zoom_level_changed_cb), window);
G_CALLBACK (contact_map_window_zoom_level_changed_cb), window);
g_signal_connect (
map, "contact-added",
G_CALLBACK (map_contact_added_cb), window);
G_CALLBACK (contact_map_window_contact_added_cb), window);
g_signal_connect (
map, "contact-removed",
G_CALLBACK (map_contact_removed_cb), window);
G_CALLBACK (contact_map_window_contact_removed_cb), window);
g_signal_connect (
map, "geocoding-started",
G_CALLBACK (map_contact_geocoding_started_cb), window);
G_CALLBACK (contact_map_window_geocoding_started_cb), window);
g_signal_connect (
map, "geocoding-failed",
G_CALLBACK (map_contact_geocoding_failed_cb), window);
G_CALLBACK (contact_map_window_geocoding_failed_cb), window);
/* HBox container */
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 7);
@@ -455,8 +459,15 @@ e_contact_map_window_init (EContactMapWindow *window)
EContactMapWindow *
e_contact_map_window_new (void)
{
return g_object_new (
E_TYPE_CONTACT_MAP_WINDOW, NULL);
return g_object_new (E_TYPE_CONTACT_MAP_WINDOW, NULL);
}
EContactMap *
e_contact_map_window_get_map (EContactMapWindow *window)
{
g_return_val_if_fail (E_IS_CONTACT_MAP_WINDOW (window), NULL);
return window->priv->map;
}
/**
@@ -473,27 +484,15 @@ e_contact_map_window_load_addressbook (EContactMapWindow *map,
g_return_if_fail (E_IS_CONTACT_MAP_WINDOW (map));
g_return_if_fail (E_IS_BOOK_CLIENT (book_client));
/* Reference book, so that it does not get deleted before the callback is
* involved. The book is unrefed in the callback */
g_object_ref (book_client);
book_query = e_book_query_field_exists (E_CONTACT_ADDRESS);
query_string = e_book_query_to_string (book_query);
e_book_query_unref (book_query);
e_book_client_get_contacts (
book_client, query_string, NULL,
book_contacts_received_cb, map);
contact_map_window_get_contacts_cb, map);
g_free (query_string);
}
EContactMap *
e_contact_map_window_get_map (EContactMapWindow *window)
{
g_return_val_if_fail (E_IS_CONTACT_MAP_WINDOW (window), NULL);
return window->priv->map;
}
#endif /* WITH_CONTACT_MAPS */
@@ -62,17 +62,17 @@ struct _EContactMapWindow {
struct _EContactMapWindowClass {
GtkWindowClass parent_class;
void (*show_contact_editor) (EContactMapWindow *window,
const gchar *contact_uid);
void (*show_contact_editor) (EContactMapWindow *window,
const gchar *contact_uid);
};
GType e_contact_map_window_get_type (void) G_GNUC_CONST;
EContactMapWindow * e_contact_map_window_new (void);
void e_contact_map_window_load_addressbook (EContactMapWindow *window,
EBookClient *book);
EContactMap * e_contact_map_window_get_map (EContactMapWindow *window);
GType e_contact_map_window_get_type (void) G_GNUC_CONST;
EContactMapWindow *
e_contact_map_window_new (void);
EContactMap * e_contact_map_window_get_map (EContactMapWindow *window);
void e_contact_map_window_load_addressbook
(EContactMapWindow *window,
EBookClient *book);
G_END_DECLS
+78 -88
View File
@@ -73,33 +73,30 @@ G_DEFINE_TYPE (EContactMap, e_contact_map, GTK_CHAMPLAIN_TYPE_EMBED)
static void
async_context_free (AsyncContext *async_context)
{
if (async_context->map != NULL)
g_object_unref (async_context->map);
g_clear_object (&async_context->map);
g_slice_free (AsyncContext, async_context);
}
static void
contact_map_address_resolved_cb (GObject *source,
contact_map_address_resolved_cb (GObject *source_object,
GAsyncResult *result,
gpointer user_data)
{
GHashTable *resolved = NULL;
gpointer marker_ptr;
const gchar *name;
AsyncContext *async_context = user_data;
ChamplainMarkerLayer *marker_layer;
ChamplainMarker *marker;
GeocodePlace *place;
GeocodeLocation *location;
GList *search_results;
g_return_if_fail (async_context != NULL);
g_return_if_fail (E_IS_CONTACT_MAP (async_context->map));
g_return_if_fail (E_IS_CONTACT_MARKER (async_context->marker));
const gchar *name;
GError *local_error = NULL;
marker = CHAMPLAIN_MARKER (async_context->marker);
marker_layer = async_context->map->priv->marker_layer;
name = champlain_label_get_text (CHAMPLAIN_LABEL (marker));
/* If the marker_layer does not exist anymore, the map has
* probably been destroyed before this callback was launched.
@@ -110,10 +107,24 @@ contact_map_address_resolved_cb (GObject *source,
goto exit;
search_results = geocode_forward_search_finish (
GEOCODE_FORWARD (source), result, NULL);
GEOCODE_FORWARD (source_object), result, &local_error);
/* Sanity check. */
g_warn_if_fail (
((search_results != NULL) && (local_error == NULL)) ||
((search_results == NULL) && (local_error != NULL)));
/* Keep quiet if the search just came up empty. */
if (g_error_matches (local_error, GEOCODE_ERROR, GEOCODE_ERROR_NO_MATCHES)) {
g_clear_error (&local_error);
/* Leave a breadcrumb on the console for any other errors. */
} else if (local_error != NULL) {
g_warning ("%s: %s", G_STRFUNC, local_error->message);
g_clear_error (&local_error);
}
if (search_results == NULL) {
name = champlain_label_get_text (CHAMPLAIN_LABEL (marker));
g_signal_emit (
async_context->map,
signals[GEOCODING_FAILED], 0, name);
@@ -135,7 +146,6 @@ contact_map_address_resolved_cb (GObject *source,
g_list_free (search_results);
/* Store the marker in the hash table, using its label as key. */
name = champlain_label_get_text (CHAMPLAIN_LABEL (marker));
marker_ptr = g_hash_table_lookup (
async_context->map->priv->markers, name);
if (marker_ptr != NULL) {
@@ -192,47 +202,14 @@ address_to_xep (EContactAddress *address)
return hash_table;
}
static void
resolve_marker_position (EContactMap *map,
EContactMarker *marker,
EContactAddress *address)
{
GeocodeForward *geocoder;
AsyncContext *async_context;
GHashTable *hash_table;
g_return_if_fail (E_IS_CONTACT_MAP (map));
g_return_if_fail (address != NULL);
hash_table = address_to_xep (address);
geocoder = geocode_forward_new_for_params (hash_table);
g_hash_table_destroy (hash_table);
async_context = g_slice_new0 (AsyncContext);
async_context->map = g_object_ref (map);
async_context->marker = marker;
geocode_forward_search_async (
geocoder, NULL,
contact_map_address_resolved_cb,
async_context);
g_object_unref (geocoder);
g_signal_emit (map, signals[GEOCODING_STARTED], 0, marker);
}
static void
contact_map_finalize (GObject *object)
{
EContactMapPrivate *priv;
priv = E_CONTACT_MAP (object)->priv;
priv = E_CONTACT_MAP_GET_PRIVATE (object);
if (priv->markers) {
g_hash_table_destroy (priv->markers);
priv->markers = NULL;
}
g_hash_table_destroy (priv->markers);
/* Chain up to parent's finalize() method. */
G_OBJECT_CLASS (e_contact_map_parent_class)->finalize (object);
@@ -288,17 +265,16 @@ e_contact_map_class_init (EContactMapClass *class)
static void
e_contact_map_init (EContactMap *map)
{
GHashTable *hash_table;
ChamplainMarkerLayer *layer;
ChamplainView *view;
map->priv = E_CONTACT_MAP_GET_PRIVATE (map);
hash_table = g_hash_table_new_full (
g_str_hash, g_str_equal,
(GDestroyNotify) g_free, NULL);
map->priv->markers = hash_table;
map->priv->markers = g_hash_table_new_full (
(GHashFunc) g_str_hash,
(GEqualFunc) g_str_equal,
(GDestroyNotify) g_free,
(GDestroyNotify) NULL);
view = gtk_champlain_embed_get_view (GTK_CHAMPLAIN_EMBED (map));
/* This feature is somehow broken sometimes, so disable it for now */
@@ -311,8 +287,7 @@ e_contact_map_init (EContactMap *map)
GtkWidget *
e_contact_map_new (void)
{
return g_object_new (
E_TYPE_CONTACT_MAP,NULL);
return g_object_new (E_TYPE_CONTACT_MAP, NULL);
}
void
@@ -321,32 +296,43 @@ e_contact_map_add_contact (EContactMap *map,
{
EContactAddress *address;
EContactPhoto *photo;
const gchar *contact_name;
const gchar *contact_uid;
gchar *name;
g_return_if_fail (map && E_IS_CONTACT_MAP (map));
g_return_if_fail (contact && E_IS_CONTACT (contact));
g_return_if_fail (E_IS_CONTACT_MAP (map));
g_return_if_fail (E_IS_CONTACT (contact));
photo = e_contact_get (contact, E_CONTACT_PHOTO);
contact_name = e_contact_get_const (contact, E_CONTACT_FILE_AS);
contact_uid = e_contact_get_const (contact, E_CONTACT_UID);
address = e_contact_get (contact, E_CONTACT_ADDRESS_HOME);
if (address) {
name = g_strconcat (e_contact_get_const (contact, E_CONTACT_FILE_AS), " (", _("Home"), ")", NULL);
e_contact_map_add_marker (map, name, contact_uid, address, photo);
if (address != NULL) {
gchar *name;
name = g_strdup_printf (
"%s (%s)", contact_name, _("Home"));
e_contact_map_add_marker (
map, name, contact_uid, address, photo);
g_free (name);
e_contact_address_free (address);
}
address = e_contact_get (contact, E_CONTACT_ADDRESS_WORK);
if (address) {
name = g_strconcat (e_contact_get_const (contact, E_CONTACT_FILE_AS), " (", _("Work"), ")", NULL);
e_contact_map_add_marker (map, name, contact_uid, address, photo);
if (address != NULL) {
gchar *name;
name = g_strdup_printf (
"%s (%s)", contact_name, _("Work"));
e_contact_map_add_marker (
map, name, contact_uid, address, photo);
g_free (name);
e_contact_address_free (address);
}
if (photo)
if (photo != NULL)
e_contact_photo_free (photo);
}
@@ -358,15 +344,33 @@ e_contact_map_add_marker (EContactMap *map,
EContactPhoto *photo)
{
EContactMarker *marker;
GHashTable *hash_table;
GeocodeForward *geocoder;
AsyncContext *async_context;
g_return_if_fail (map && E_IS_CONTACT_MAP (map));
g_return_if_fail (name && *name);
g_return_if_fail (contact_uid && *contact_uid);
g_return_if_fail (address);
g_return_if_fail (E_IS_CONTACT_MAP (map));
g_return_if_fail (name != NULL);
g_return_if_fail (contact_uid != NULL);
g_return_if_fail (address != NULL);
marker = E_CONTACT_MARKER (e_contact_marker_new (name, contact_uid, photo));
marker = e_contact_marker_new (name, contact_uid, photo);
resolve_marker_position (map, marker, address);
hash_table = address_to_xep (address);
geocoder = geocode_forward_new_for_params (hash_table);
g_hash_table_destroy (hash_table);
async_context = g_slice_new0 (AsyncContext);
async_context->map = g_object_ref (map);
async_context->marker = marker;
geocode_forward_search_async (
geocoder, NULL,
contact_map_address_resolved_cb,
async_context);
g_object_unref (geocoder);
g_signal_emit (map, signals[GEOCODING_STARTED], 0, marker);
}
/**
@@ -379,8 +383,8 @@ e_contact_map_remove_contact (EContactMap *map,
{
ChamplainMarker *marker;
g_return_if_fail (map && E_IS_CONTACT_MAP (map));
g_return_if_fail (name && *name);
g_return_if_fail (E_IS_CONTACT_MAP (map));
g_return_if_fail (name != NULL);
marker = g_hash_table_lookup (map->priv->markers, name);
@@ -391,20 +395,6 @@ e_contact_map_remove_contact (EContactMap *map,
g_signal_emit (map, signals[CONTACT_REMOVED], 0, name);
}
void
e_contact_map_remove_marker (EContactMap *map,
ClutterActor *marker)
{
const gchar *name;
g_return_if_fail (map && E_IS_CONTACT_MAP (map));
g_return_if_fail (marker && CLUTTER_IS_ACTOR (marker));
name = champlain_label_get_text (CHAMPLAIN_LABEL (marker));
e_contact_map_remove_contact (map, name);
}
void
e_contact_map_zoom_on_marker (EContactMap *map,
ClutterActor *marker)
@@ -412,8 +402,8 @@ e_contact_map_zoom_on_marker (EContactMap *map,
ChamplainView *view;
gdouble lat, lng;
g_return_if_fail (map && E_IS_CONTACT_MAP (map));
g_return_if_fail (marker && CLUTTER_IS_ACTOR (marker));
g_return_if_fail (E_IS_CONTACT_MAP (map));
g_return_if_fail (CLUTTER_IS_ACTOR (marker));
lat = champlain_location_get_latitude (CHAMPLAIN_LOCATION (marker));
lng = champlain_location_get_longitude (CHAMPLAIN_LOCATION (marker));
+11 -21
View File
@@ -63,44 +63,34 @@ struct _EContactMap {
struct _EContactMapClass {
GtkWindowClass parent_class;
void (*contact_added) (EContactMap *map,
ClutterActor *marker);
void (*contact_removed) (EContactMap *map,
const gchar *name);
void (*geocoding_started) (EContactMap *map,
ClutterActor *marker);
void (*geocoding_failed) (EContactMap *map,
const gchar *name);
/* Signals */
void (*contact_added) (EContactMap *map,
ClutterActor *marker);
void (*contact_removed) (EContactMap *map,
const gchar *name);
void (*geocoding_started) (EContactMap *map,
ClutterActor *marker);
void (*geocoding_failed) (EContactMap *map,
const gchar *name);
};
GType e_contact_map_get_type (void) G_GNUC_CONST;
GtkWidget * e_contact_map_new (void);
void e_contact_map_add_contact (EContactMap *map,
EContact *contact);
void e_contact_map_add_marker (EContactMap *map,
const gchar *name,
const gchar *contact_uid,
EContactAddress *address,
EContactPhoto *photo);
void e_contact_map_remove_contact (EContactMap *map,
const gchar *name);
void e_contact_map_remove_marker (EContactMap *map,
ClutterActor *marker);
void e_contact_map_zoom_on_marker (EContactMap *map,
ClutterActor *marker);
ChamplainView * e_contact_map_get_view (EContactMap *map);
ChamplainView * e_contact_map_get_view (EContactMap *map);
G_END_DECLS
#endif /* WITH_CONTACT_MAPS */
#endif
#endif /* E_CONTACT_MAP_H */
+196 -152
View File
@@ -39,13 +39,16 @@
#include <string.h>
#define E_CONTACT_MARKER_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE \
((obj), E_TYPE_CONTACT_MARKER, EContactMarkerPrivate))
(G_TYPE_INSTANCE_GET_PRIVATE \
((obj), E_TYPE_CONTACT_MARKER, EContactMarkerPrivate))
G_DEFINE_TYPE (EContactMarker, e_contact_marker, CHAMPLAIN_TYPE_LABEL);
#define DEFAULT_FONT_NAME "Serif 9"
struct _EContactMarkerPrivate
{
#define RADIUS 10
#define PADDING (RADIUS / 2)
#define HALF_PI (M_PI / 2.0)
struct _EContactMarkerPrivate {
gchar *contact_uid;
ClutterActor *image;
@@ -67,14 +70,14 @@ enum {
LAST_SIGNAL
};
static gint signals[LAST_SIGNAL] = {0};
#define DEFAULT_FONT_NAME "Serif 9"
static gint signals[LAST_SIGNAL];
static ClutterColor DEFAULT_COLOR = { 0x33, 0x33, 0x33, 0xff };
#define RADIUS 10
#define PADDING (RADIUS / 2)
G_DEFINE_TYPE (
EContactMarker,
e_contact_marker,
CHAMPLAIN_TYPE_LABEL);
static gboolean
contact_marker_clicked_cb (ClutterActor *actor,
@@ -84,7 +87,7 @@ contact_marker_clicked_cb (ClutterActor *actor,
gint click_count = clutter_event_get_click_count (event);
if (click_count == 2)
g_signal_emit (E_CONTACT_MARKER (actor), signals[DOUBLE_CLICKED], 0);
g_signal_emit (actor, signals[DOUBLE_CLICKED], 0);
return TRUE;
}
@@ -157,12 +160,12 @@ draw_box (cairo_t *cr,
{
cairo_move_to (cr, RADIUS, 0);
cairo_line_to (cr, width - RADIUS, 0);
cairo_arc (cr, width - RADIUS, RADIUS, RADIUS - 1, 3 * M_PI / 2.0, 0);
cairo_arc (cr, width - RADIUS, RADIUS, RADIUS - 1, 3 * HALF_PI, 0);
cairo_line_to (cr, width, height - RADIUS);
cairo_arc (cr, width - RADIUS, height - RADIUS, RADIUS - 1, 0, M_PI / 2.0);
cairo_arc (cr, width - RADIUS, height - RADIUS, RADIUS - 1, 0, HALF_PI);
cairo_line_to (cr, point, height);
cairo_line_to (cr, 0, height + point);
cairo_arc (cr, RADIUS, RADIUS, RADIUS - 1, M_PI, 3 * M_PI / 2.0);
cairo_arc (cr, RADIUS, RADIUS, RADIUS - 1, M_PI, 3 * HALF_PI);
cairo_close_path (cr);
}
@@ -172,7 +175,6 @@ draw_shadow (EContactMarker *marker,
gint height,
gint point)
{
EContactMarkerPrivate *priv = marker->priv;
ClutterActor *shadow = NULL;
cairo_t *cr;
gdouble slope;
@@ -203,15 +205,16 @@ draw_shadow (EContactMarker *marker,
clutter_actor_set_position (shadow, 0, height / 2.0);
clutter_container_add_actor (CLUTTER_CONTAINER (priv->content_group), shadow);
clutter_container_add_actor (
CLUTTER_CONTAINER (marker->priv->content_group), shadow);
if (priv->shadow != NULL) {
if (marker->priv->shadow != NULL) {
clutter_container_remove_actor (
CLUTTER_CONTAINER (priv->content_group),
priv->shadow);
CLUTTER_CONTAINER (marker->priv->content_group),
marker->priv->shadow);
}
priv->shadow = shadow;
marker->priv->shadow = shadow;
}
static void
@@ -233,7 +236,7 @@ draw_background (EContactMarker *marker,
cairo_paint (cr);
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
/* If selected, add the selection color to the marker's color */
/* If selected, add the selection color to the marker's color */
if (champlain_marker_get_selected (CHAMPLAIN_MARKER (marker)))
color = champlain_marker_get_selection_color ();
else
@@ -275,28 +278,28 @@ draw_background (EContactMarker *marker,
static void
draw_marker (EContactMarker *marker)
{
EContactMarkerPrivate *priv = marker->priv;
ChamplainLabel *label = CHAMPLAIN_LABEL (marker);
guint height = 0, point = 0;
guint total_width = 0, total_height = 0;
ClutterText *text;
if (priv->image) {
clutter_actor_set_position (priv->image, 2 *PADDING, 2 *PADDING);
if (clutter_actor_get_parent (priv->image) == NULL)
if (marker->priv->image != NULL) {
clutter_actor_set_position (
marker->priv->image, 2 * PADDING, 2 * PADDING);
if (clutter_actor_get_parent (marker->priv->image) == NULL)
clutter_container_add_actor (
CLUTTER_CONTAINER (priv->content_group),
priv->image);
CLUTTER_CONTAINER (marker->priv->content_group),
marker->priv->image);
}
if (priv->text_actor == NULL) {
priv->text_actor = clutter_text_new_with_text (
if (marker->priv->text_actor == NULL) {
marker->priv->text_actor = clutter_text_new_with_text (
"Serif 8",
champlain_label_get_text (label));
champlain_label_set_font_name (label, "Serif 8");
}
text = CLUTTER_TEXT (priv->text_actor);
text = CLUTTER_TEXT (marker->priv->text_actor);
clutter_text_set_text (
text,
champlain_label_get_text (label));
@@ -316,20 +319,42 @@ draw_marker (EContactMarker *marker)
text,
champlain_label_get_use_markup (label));
if (priv->image) {
if (marker->priv->image != NULL) {
gfloat image_height;
gfloat image_width;
gfloat text_height;
image_height = clutter_actor_get_height (marker->priv->image);
image_width = clutter_actor_get_width (marker->priv->image);
clutter_actor_set_width (
priv->text_actor,
clutter_actor_get_width (priv->image));
total_height = clutter_actor_get_height (priv->image) + 2 *PADDING +
clutter_actor_get_height (priv->text_actor) + 2 *PADDING;
total_width = clutter_actor_get_width (priv->image) + 4 *PADDING;
marker->priv->text_actor, image_width);
text_height = clutter_actor_get_height (
marker->priv->text_actor);
total_height =
text_height + 2 * PADDING +
image_height + 2 * PADDING;
total_width = image_width + 4 * PADDING;
clutter_actor_set_position (
priv->text_actor, PADDING,
clutter_actor_get_height (priv->image) + 2 *PADDING + 3);
marker->priv->text_actor,
PADDING, image_height + 2 * PADDING + 3);
} else {
total_height = clutter_actor_get_height (priv->text_actor) + 2 *PADDING;
total_width = clutter_actor_get_width (priv->text_actor) + 4 *PADDING;
clutter_actor_set_position (priv->text_actor, 2 * PADDING, PADDING);
gfloat text_height;
gfloat text_width;
text_height = clutter_actor_get_height (
marker->priv->text_actor);
text_width = clutter_actor_get_width (
marker->priv->text_actor);
total_height = text_height + 2 * PADDING;
total_width = text_width + 4 * PADDING;
clutter_actor_set_position (
marker->priv->text_actor,
2 * PADDING, PADDING);
}
height += 2 * PADDING;
@@ -337,33 +362,40 @@ draw_marker (EContactMarker *marker)
total_height = height;
clutter_text_set_color (
CLUTTER_TEXT (priv->text_actor),
CLUTTER_TEXT (marker->priv->text_actor),
(champlain_marker_get_selected (CHAMPLAIN_MARKER (marker)) ?
champlain_marker_get_selection_text_color () :
champlain_label_get_text_color (CHAMPLAIN_LABEL (marker))));
if (clutter_actor_get_parent (priv->text_actor) == NULL)
if (clutter_actor_get_parent (marker->priv->text_actor) == NULL)
clutter_container_add_actor (
CLUTTER_CONTAINER (priv->content_group),
priv->text_actor);
CLUTTER_CONTAINER (marker->priv->content_group),
marker->priv->text_actor);
if (priv->text_actor == NULL && priv->image == NULL) {
if (marker->priv->text_actor == NULL && marker->priv->image == NULL) {
total_width = 6 * PADDING;
total_height = 6 * PADDING;
}
point = (total_height + 2 * PADDING) / 4.0;
priv->total_width = total_width;
priv->total_height = total_height;
marker->priv->total_width = total_width;
marker->priv->total_height = total_height;
draw_shadow (marker, total_width, total_height, point);
draw_background (marker, total_width, total_height, point);
if (priv->text_actor != NULL && priv->background != NULL)
clutter_actor_raise (priv->text_actor, priv->background);
if (priv->image != NULL && priv->background != NULL)
clutter_actor_raise (priv->image, priv->background);
if (marker->priv->background != NULL) {
if (marker->priv->text_actor != NULL)
clutter_actor_raise (
marker->priv->text_actor,
marker->priv->background);
if (marker->priv->image != NULL)
clutter_actor_raise (
marker->priv->image,
marker->priv->background);
}
clutter_actor_set_anchor_point (CLUTTER_ACTOR (marker), 0, total_height + point);
clutter_actor_set_anchor_point (
CLUTTER_ACTOR (marker), 0, total_height + point);
}
static gboolean
@@ -391,62 +423,101 @@ queue_redraw (EContactMarker *marker)
}
static void
allocate (ClutterActor *self,
const ClutterActorBox *box,
ClutterAllocationFlags flags)
notify_selected (GObject *gobject,
G_GNUC_UNUSED GParamSpec *pspec,
G_GNUC_UNUSED gpointer user_data)
{
ClutterActorBox child_box;
EContactMarkerPrivate *priv = E_CONTACT_MARKER (self)->priv;
CLUTTER_ACTOR_CLASS (e_contact_marker_parent_class)->allocate (self, box, flags);
child_box.x1 = 0;
child_box.x2 = box->x2 - box->x1;
child_box.y1 = 0;
child_box.y2 = box->y2 - box->y1;
clutter_actor_allocate (CLUTTER_ACTOR (priv->content_group), &child_box, flags);
queue_redraw (E_CONTACT_MARKER (gobject));
}
static void
paint (ClutterActor *self)
contact_marker_dispose (GObject *object)
{
EContactMarkerPrivate *priv = E_CONTACT_MARKER (self)->priv;
EContactMarkerPrivate *priv;
clutter_actor_paint (CLUTTER_ACTOR (priv->content_group));
priv = E_CONTACT_MARKER_GET_PRIVATE (object);
priv->background = NULL;
priv->shadow = NULL;
priv->text_actor = NULL;
if (priv->redraw_id > 0) {
g_source_remove (priv->redraw_id);
priv->redraw_id = 0;
}
if (priv->content_group != NULL) {
clutter_actor_unparent (CLUTTER_ACTOR (priv->content_group));
priv->content_group = NULL;
}
/* Chain up to parent's dispose() method. */
G_OBJECT_CLASS (e_contact_marker_parent_class)->dispose (object);
}
static void
map (ClutterActor *self)
contact_marker_finalize (GObject *object)
{
EContactMarkerPrivate *priv = E_CONTACT_MARKER (self)->priv;
EContactMarkerPrivate *priv;
CLUTTER_ACTOR_CLASS (e_contact_marker_parent_class)->map (self);
priv = E_CONTACT_MARKER_GET_PRIVATE (object);
clutter_actor_map (CLUTTER_ACTOR (priv->content_group));
g_free (priv->contact_uid);
/* Chain up to parent's finalize() method. */
G_OBJECT_CLASS (e_contact_marker_parent_class)->finalize (object);
}
static void
unmap (ClutterActor *self)
contact_marker_map (ClutterActor *actor)
{
EContactMarkerPrivate *priv = E_CONTACT_MARKER (self)->priv;
EContactMarker *marker;
CLUTTER_ACTOR_CLASS (e_contact_marker_parent_class)->unmap (self);
marker = E_CONTACT_MARKER (actor);
clutter_actor_unmap (CLUTTER_ACTOR (priv->content_group));
/* Chain up to parent's map() method. */
CLUTTER_ACTOR_CLASS (e_contact_marker_parent_class)->map (actor);
clutter_actor_map (CLUTTER_ACTOR (marker->priv->content_group));
}
static void
pick (ClutterActor *self,
const ClutterColor *color)
contact_marker_unmap (ClutterActor *actor)
{
EContactMarkerPrivate *priv = E_CONTACT_MARKER (self)->priv;
EContactMarker *marker;
marker = E_CONTACT_MARKER (actor);
/* Chain up to parent's unmap() method. */
CLUTTER_ACTOR_CLASS (e_contact_marker_parent_class)->unmap (actor);
clutter_actor_unmap (CLUTTER_ACTOR (marker->priv->content_group));
}
static void
contact_marker_paint (ClutterActor *actor)
{
EContactMarker *marker;
marker = E_CONTACT_MARKER (actor);
clutter_actor_paint (CLUTTER_ACTOR (marker->priv->content_group));
}
static void
contact_marker_pick (ClutterActor *actor,
const ClutterColor *color)
{
EContactMarker *marker;
gfloat width, height;
if (!clutter_actor_should_pick_paint (self))
if (!clutter_actor_should_pick_paint (actor))
return;
width = priv->total_width;
height = priv->total_height;
marker = E_CONTACT_MARKER (actor);
width = marker->priv->total_width;
height = marker->priv->total_height;
cogl_path_new ();
@@ -470,64 +541,47 @@ pick (ClutterActor *self,
}
static void
notify_selected (GObject *gobject,
G_GNUC_UNUSED GParamSpec *pspec,
G_GNUC_UNUSED gpointer user_data)
contact_marker_allocate (ClutterActor *actor,
const ClutterActorBox *box,
ClutterAllocationFlags flags)
{
queue_redraw (E_CONTACT_MARKER (gobject));
}
EContactMarker *marker;
ClutterActorBox child_box;
static void
e_contact_marker_finalize (GObject *object)
{
EContactMarkerPrivate *priv = E_CONTACT_MARKER (object)->priv;
marker = E_CONTACT_MARKER (actor);
if (priv->contact_uid) {
g_free (priv->contact_uid);
priv->contact_uid = NULL;
}
/* Chain up to parent's allocate() method. */
CLUTTER_ACTOR_CLASS (e_contact_marker_parent_class)->
allocate (actor, box, flags);
if (priv->redraw_id) {
g_source_remove (priv->redraw_id);
priv->redraw_id = 0;
}
child_box.x1 = 0;
child_box.x2 = box->x2 - box->x1;
child_box.y1 = 0;
child_box.y2 = box->y2 - box->y1;
G_OBJECT_CLASS (e_contact_marker_parent_class)->finalize (object);
}
static void
e_contact_marker_dispose (GObject *object)
{
EContactMarkerPrivate *priv = E_CONTACT_MARKER (object)->priv;
priv->background = NULL;
priv->shadow = NULL;
priv->text_actor = NULL;
if (priv->content_group) {
clutter_actor_unparent (CLUTTER_ACTOR (priv->content_group));
priv->content_group = NULL;
}
G_OBJECT_CLASS (e_contact_marker_parent_class)->dispose (object);
clutter_actor_allocate (
CLUTTER_ACTOR (marker->priv->content_group),
&child_box, flags);
}
static void
e_contact_marker_class_init (EContactMarkerClass *class)
{
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (class);
GObjectClass *object_class = G_OBJECT_CLASS (class);
GObjectClass *object_class;
ClutterActorClass *actor_class;
g_type_class_add_private (class, sizeof (EContactMarkerPrivate));
object_class->dispose = e_contact_marker_dispose;
object_class->finalize = e_contact_marker_finalize;
object_class = G_OBJECT_CLASS (class);
object_class->dispose = contact_marker_dispose;
object_class->finalize = contact_marker_finalize;
actor_class->paint = paint;
actor_class->allocate = allocate;
actor_class->map = map;
actor_class->unmap = unmap;
actor_class->pick = pick;
actor_class = CLUTTER_ACTOR_CLASS (class);
actor_class->map = contact_marker_map;
actor_class->unmap = contact_marker_unmap;
actor_class->paint = contact_marker_paint;
actor_class->pick = contact_marker_pick;
actor_class->allocate = contact_marker_allocate;
signals[DOUBLE_CLICKED] = g_signal_new (
"double-clicked",
@@ -542,26 +596,15 @@ e_contact_marker_class_init (EContactMarkerClass *class)
static void
e_contact_marker_init (EContactMarker *marker)
{
EContactMarkerPrivate *priv;
marker->priv = E_CONTACT_MARKER_GET_PRIVATE (marker);
priv = E_CONTACT_MARKER_GET_PRIVATE (marker);
marker->priv = priv;
priv->contact_uid = NULL;
priv->image = NULL;
priv->background = NULL;
priv->shadow = NULL;
priv->text_actor = NULL;
priv->content_group = CLUTTER_GROUP (clutter_group_new ());
priv->redraw_id = 0;
marker->priv->content_group = CLUTTER_GROUP (clutter_group_new ());
clutter_actor_set_parent (
CLUTTER_ACTOR (priv->content_group), CLUTTER_ACTOR (marker));
CLUTTER_ACTOR (marker->priv->content_group),
CLUTTER_ACTOR (marker));
clutter_actor_queue_relayout (CLUTTER_ACTOR (marker));
priv->total_width = 0;
priv->total_height = 0;
g_signal_connect (
marker, "notify::selected",
G_CALLBACK (notify_selected), NULL);
@@ -570,23 +613,24 @@ e_contact_marker_init (EContactMarker *marker)
G_CALLBACK (contact_marker_clicked_cb), NULL);
}
ClutterActor *
EContactMarker *
e_contact_marker_new (const gchar *name,
const gchar *contact_uid,
EContactPhoto *photo)
{
ClutterActor *marker = CLUTTER_ACTOR (g_object_new (E_TYPE_CONTACT_MARKER, NULL));
EContactMarkerPrivate *priv = E_CONTACT_MARKER (marker)->priv;
EContactMarker *marker;
g_return_val_if_fail (name && *name, NULL);
g_return_val_if_fail (contact_uid && *contact_uid, NULL);
g_return_val_if_fail (name != NULL, NULL);
g_return_val_if_fail (contact_uid != NULL, NULL);
marker = g_object_new (E_TYPE_CONTACT_MARKER, NULL);
champlain_label_set_text (CHAMPLAIN_LABEL (marker), name);
priv->contact_uid = g_strdup (contact_uid);
if (photo)
priv->image = contact_photo_to_texture (photo);
marker->priv->contact_uid = g_strdup (contact_uid);
if (photo != NULL)
marker->priv->image = contact_photo_to_texture (photo);
queue_redraw (E_CONTACT_MARKER (marker));
queue_redraw (marker);
return marker;
}
@@ -594,7 +638,7 @@ e_contact_marker_new (const gchar *name,
const gchar *
e_contact_marker_get_contact_uid (EContactMarker *marker)
{
g_return_val_if_fail (marker && E_IS_CONTACT_MARKER (marker), NULL);
g_return_val_if_fail (E_IS_CONTACT_MARKER (marker), NULL);
return marker->priv->contact_uid;
}
+30 -33
View File
@@ -25,60 +25,57 @@
#ifdef WITH_CONTACT_MAPS
#include <libebook/libebook.h>
#include <clutter/clutter.h>
#include <champlain/champlain.h>
#include <glib-object.h>
#include <clutter/clutter.h>
#include <libebook/libebook.h>
/* Standard GObject macros */
#define E_TYPE_CONTACT_MARKER \
(e_contact_marker_get_type ())
#define E_CONTACT_MARKER(obj) \
(G_TYPE_CHECK_INSTANCE_CAST \
((obj), E_TYPE_CONTACT_MARKER, EContactMarker))
#define E_CONTACT_MARKER_CLASS(cls) \
(G_TYPE_CHECK_CLASS_CAST \
((cls), E_TYPE_CONTACT_MARKER, EContactMarkerClass))
#define E_IS_CONTACT_MARKER(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE \
((obj), E_TYPE_CONTACT_MARKER))
#define E_IS_CONTACT_MARKER_CLASS(cls) \
(G_TYPE_CHECK_CLASS_TYPE \
((cls), E_TYPE_CONTACT_MARKER))
#define E_CONTACT_MARKER_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS \
((obj), E_TYPE_CONTACT_MARKER, EContactMarkerClass))
G_BEGIN_DECLS
#define E_TYPE_CONTACT_MARKER e_contact_marker_get_type ()
#define E_CONTACT_MARKER(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_CONTACT_MARKER, EContactMarker))
#define E_CONTACT_MARKER_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_CONTACT_MARKER, EContactMarkerClass))
#define E_IS_CONTACT_MARKER(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_CONTACT_MARKER))
#define E_IS_CONTACT_MARKER_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE ((klass), E_TYPE_CONTACT_MARKER))
#define E_CONTACT_MARKER_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS ((obj), E_TYPE_CONTACT_MARKER, EContactMarkerClass))
typedef struct _EContactMarkerPrivate EContactMarkerPrivate;
typedef struct _EContactMarker EContactMarker;
typedef struct _EContactMarkerClass EContactMarkerClass;
typedef struct _EContactMarkerPrivate EContactMarkerPrivate;
struct _EContactMarker
{
struct _EContactMarker {
ChamplainLabel parent;
EContactMarkerPrivate *priv;
};
struct _EContactMarkerClass
{
struct _EContactMarkerClass {
ChamplainLabelClass parent_class;
void (*double_clicked) (ClutterActor *actor);
};
GType e_contact_marker_get_type (void);
ClutterActor * e_contact_marker_new (const gchar *name,
GType e_contact_marker_get_type (void) G_GNUC_CONST;
EContactMarker *
e_contact_marker_new (const gchar *name,
const gchar *contact_uid,
EContactPhoto *photo);
const gchar * e_contact_marker_get_contact_uid (EContactMarker *marker);
const gchar * e_contact_marker_get_contact_uid
(EContactMarker *marker);
G_END_DECLS
#endif /* WITH_CONTACT_MAPS */
#endif
#endif /* E_CONTACT_MARKER_H */