[libgweather] Adding detached location support and expanding range of cities
- From: Giovanni Campagna <gcampagna src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libgweather] Adding detached location support and expanding range of cities
- Date: Tue, 1 Jul 2014 12:57:25 +0000 (UTC)
commit 4008366893d38af6b017c81694067123cd0b3b27
Author: Saurabh <srp201201051 gmail com>
Date: Thu Jun 19 13:16:53 2014 +0530
Adding detached location support and expanding range of cities
Add detached location support and remov segmentation fault. Use
geocoding to get the geocode places for user's invalid input and then
using coordinates of the selected place find the nearest weather station
and using that create a detached location and set it as internal
location. Better handling of "Loading.." string.
https://bugzilla.gnome.org/show_bug.cgi?id=731466
libgweather/location-entry.c | 242 +++++++++++++++++++++++++++++++++++++-----
1 files changed, 216 insertions(+), 26 deletions(-)
---
diff --git a/libgweather/location-entry.c b/libgweather/location-entry.c
index cf9cf8e..a9bb05a 100644
--- a/libgweather/location-entry.c
+++ b/libgweather/location-entry.c
@@ -23,6 +23,8 @@
#endif
#include <string.h>
+#include <geocode-glib/geocode-glib.h>
+#include <gio/gio.h>
#define GWEATHER_I_KNOW_THIS_IS_UNSTABLE
#include "location-entry.h"
@@ -41,6 +43,8 @@ struct _GWeatherLocationEntryPrivate {
GWeatherLocation *location;
GWeatherLocation *top;
gboolean custom_text;
+ GCancellable *cancellable;
+ GtkTreeModel *model;
};
G_DEFINE_TYPE (GWeatherLocationEntry, gweather_location_entry, GTK_TYPE_SEARCH_ENTRY)
@@ -65,14 +69,27 @@ static void set_location_internal (GWeatherLocationEntry *entry,
GtkTreeModel *model,
GtkTreeIter *iter,
GWeatherLocation *loc);
+static GWeatherLocation *
+create_new_detached_location (GWeatherLocation *nearest_station,
+ const char *name,
+ gboolean latlon_valid,
+ gdouble latitude,
+ gdouble longitude);
+
+enum LOC
+{
+ LOC_GWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME = 0,
+ LOC_GWEATHER_LOCATION_ENTRY_COL_LOCATION,
+ LOC_GWEATHER_LOCATION_ENTRY_COL_LOCAL_COMPARE_NAME,
+ LOC_GWEATHER_LOCATION_ENTRY_COL_ENGLISH_COMPARE_NAME,
+ LOC_GWEATHER_LOCATION_ENTRY_NUM_COLUMNS
+};
-enum
+enum PLACE
{
- GWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME = 0,
- GWEATHER_LOCATION_ENTRY_COL_LOCATION,
- GWEATHER_LOCATION_ENTRY_COL_LOCAL_COMPARE_NAME,
- GWEATHER_LOCATION_ENTRY_COL_ENGLISH_COMPARE_NAME,
- GWEATHER_LOCATION_ENTRY_NUM_COLUMNS
+ PLACE_GWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME = 0,
+ PLACE_GWEATHER_LOCATION_ENTRY_COL_PLACE,
+ PLACE_GWEATHER_LOCATION_ENTRY_COL_LOCAL_COMPARE_NAME
};
static gboolean matcher (GtkEntryCompletion *completion, const char *key,
@@ -82,6 +99,7 @@ static gboolean match_selected (GtkEntryCompletion *completion,
GtkTreeIter *iter,
gpointer entry);
static void entry_changed (GWeatherLocationEntry *entry);
+static void _no_matches (GtkEntryCompletion *completion, GWeatherLocationEntry *entry);
static void
hack_filter_model_data_func (GtkCellLayout *layout,
@@ -110,7 +128,7 @@ gweather_location_entry_init (GWeatherLocationEntry *entry)
completion = gtk_entry_completion_new ();
gtk_entry_completion_set_popup_set_width (completion, FALSE);
- gtk_entry_completion_set_text_column (completion, GWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME);
+ gtk_entry_completion_set_text_column (completion, LOC_GWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME);
gtk_entry_completion_set_match_func (completion, matcher, NULL, NULL);
/* Giant Hack!
@@ -133,6 +151,9 @@ gweather_location_entry_init (GWeatherLocationEntry *entry)
g_signal_connect (completion, "match-selected",
G_CALLBACK (match_selected), entry);
+ g_signal_connect (completion, "no-matches",
+ G_CALLBACK (_no_matches), entry);
+
gtk_entry_set_completion (GTK_ENTRY (entry), completion);
g_object_unref (completion);
@@ -154,11 +175,31 @@ finalize (GObject *object)
gweather_location_unref (priv->location);
if (priv->top)
gweather_location_unref (priv->top);
+ if (priv->model)
+ g_object_unref (priv->model);
G_OBJECT_CLASS (gweather_location_entry_parent_class)->finalize (object);
}
static void
+dispose (GObject *object)
+{
+ GWeatherLocationEntry *entry;
+ GWeatherLocationEntryPrivate *priv;
+
+ entry = GWEATHER_LOCATION_ENTRY (object);
+ priv = entry->priv;
+
+ if (priv->cancellable) {
+ g_cancellable_cancel (priv->cancellable);
+ g_object_unref (priv->cancellable);
+ priv->cancellable = NULL;
+ }
+
+ G_OBJECT_CLASS (gweather_location_entry_parent_class)->dispose (object);
+}
+
+static void
gweather_location_entry_activate (GtkEntry *entry)
{
GWeatherLocationEntry *self;
@@ -195,6 +236,7 @@ gweather_location_entry_class_init (GWeatherLocationEntryClass *location_entry_c
object_class->finalize = finalize;
object_class->set_property = set_property;
object_class->get_property = get_property;
+ object_class->dispose = dispose;
entry_class->activate = gweather_location_entry_activate;
@@ -255,8 +297,21 @@ get_property (GObject *object, guint prop_id,
static void
entry_changed (GWeatherLocationEntry *entry)
{
+ GtkEntryCompletion *completion;
const gchar *text;
+ completion = gtk_entry_get_completion (GTK_ENTRY (entry));
+
+ if (entry->priv->cancellable) {
+ g_cancellable_cancel (entry->priv->cancellable);
+ g_object_unref (entry->priv->cancellable);
+ entry->priv->cancellable = NULL;
+ gtk_entry_completion_delete_action (completion, 0);
+ }
+
+ gtk_entry_completion_set_match_func (gtk_entry_get_completion (GTK_ENTRY (entry)), matcher, NULL, NULL);
+ gtk_entry_completion_set_model (gtk_entry_get_completion (GTK_ENTRY (entry)), entry->priv->model);
+
text = gtk_entry_get_text (GTK_ENTRY (entry));
if (text && *text)
@@ -283,8 +338,8 @@ set_location_internal (GWeatherLocationEntry *entry,
if (iter) {
gtk_tree_model_get (model, iter,
- GWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME, &name,
- GWEATHER_LOCATION_ENTRY_COL_LOCATION, &priv->location,
+ LOC_GWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME, &name,
+ LOC_GWEATHER_LOCATION_ENTRY_COL_LOCATION, &priv->location,
-1);
gtk_entry_set_text (GTK_ENTRY (entry), name);
priv->custom_text = FALSE;
@@ -292,7 +347,7 @@ set_location_internal (GWeatherLocationEntry *entry,
} else if (loc) {
priv->location = gweather_location_ref (loc);
gtk_entry_set_text (GTK_ENTRY (entry), loc->local_name);
- priv->custom_text = TRUE;
+ priv->custom_text = FALSE;
} else {
priv->location = NULL;
gtk_entry_set_text (GTK_ENTRY (entry), "");
@@ -336,7 +391,7 @@ gweather_location_entry_set_location (GWeatherLocationEntry *entry,
gtk_tree_model_get_iter_first (model, &iter);
do {
gtk_tree_model_get (model, &iter,
- GWEATHER_LOCATION_ENTRY_COL_LOCATION, &cmploc,
+ LOC_GWEATHER_LOCATION_ENTRY_COL_LOCATION, &cmploc,
-1);
if (gweather_location_equal (loc, cmploc)) {
set_location_internal (entry, model, &iter, NULL);
@@ -425,7 +480,7 @@ gweather_location_entry_set_city (GWeatherLocationEntry *entry,
gtk_tree_model_get_iter_first (model, &iter);
do {
gtk_tree_model_get (model, &iter,
- GWEATHER_LOCATION_ENTRY_COL_LOCATION, &cmploc,
+ LOC_GWEATHER_LOCATION_ENTRY_COL_LOCATION, &cmploc,
-1);
cmpcode = gweather_location_get_code (cmploc);
@@ -526,10 +581,10 @@ fill_location_entry_model (GtkTreeStore *store, GWeatherLocation *loc,
gtk_tree_store_append (store, &iter, NULL);
gtk_tree_store_set (store, &iter,
- GWEATHER_LOCATION_ENTRY_COL_LOCATION, children[i],
- GWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME, display_name,
- GWEATHER_LOCATION_ENTRY_COL_LOCAL_COMPARE_NAME, local_compare_name,
- GWEATHER_LOCATION_ENTRY_COL_ENGLISH_COMPARE_NAME, english_compare_name,
+ LOC_GWEATHER_LOCATION_ENTRY_COL_LOCATION, children[i],
+ LOC_GWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME, display_name,
+ LOC_GWEATHER_LOCATION_ENTRY_COL_LOCAL_COMPARE_NAME, local_compare_name,
+ LOC_GWEATHER_LOCATION_ENTRY_COL_ENGLISH_COMPARE_NAME,
english_compare_name,
-1);
g_free (display_name);
@@ -555,10 +610,10 @@ fill_location_entry_model (GtkTreeStore *store, GWeatherLocation *loc,
gtk_tree_store_append (store, &iter, NULL);
gtk_tree_store_set (store, &iter,
- GWEATHER_LOCATION_ENTRY_COL_LOCATION, loc,
- GWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME, display_name,
- GWEATHER_LOCATION_ENTRY_COL_LOCAL_COMPARE_NAME, local_compare_name,
- GWEATHER_LOCATION_ENTRY_COL_ENGLISH_COMPARE_NAME, english_compare_name,
+ LOC_GWEATHER_LOCATION_ENTRY_COL_LOCATION, loc,
+ LOC_GWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME, display_name,
+ LOC_GWEATHER_LOCATION_ENTRY_COL_LOCAL_COMPARE_NAME, local_compare_name,
+ LOC_GWEATHER_LOCATION_ENTRY_COL_ENGLISH_COMPARE_NAME, english_compare_name,
-1);
g_free (display_name);
@@ -576,6 +631,7 @@ gweather_location_entry_build_model (GWeatherLocationEntry *entry,
GWeatherLocation *top)
{
GtkTreeStore *store = NULL;
+ GtkEntryCompletion *completion;
if (top)
entry->priv->top = gweather_location_ref (top);
@@ -584,9 +640,11 @@ gweather_location_entry_build_model (GWeatherLocationEntry *entry,
store = gtk_tree_store_new (4, G_TYPE_STRING, GWEATHER_TYPE_LOCATION, G_TYPE_STRING, G_TYPE_STRING);
fill_location_entry_model (store, entry->priv->top, NULL, NULL, NULL);
- gtk_entry_completion_set_model (gtk_entry_get_completion (GTK_ENTRY (entry)),
- GTK_TREE_MODEL (store));
- g_object_unref (store);
+
+ entry->priv->model = GTK_TREE_MODEL (store);
+ completion = gtk_entry_get_completion (GTK_ENTRY (entry));
+ gtk_entry_completion_set_match_func (completion, matcher, NULL, NULL);
+ gtk_entry_completion_set_model (completion, GTK_TREE_MODEL (store));
}
static char *
@@ -668,8 +726,8 @@ matcher (GtkEntryCompletion *completion, const char *key,
gboolean match;
gtk_tree_model_get (gtk_entry_completion_get_model (completion), iter,
- GWEATHER_LOCATION_ENTRY_COL_LOCAL_COMPARE_NAME, &local_compare_name,
- GWEATHER_LOCATION_ENTRY_COL_ENGLISH_COMPARE_NAME, &english_compare_name,
+ LOC_GWEATHER_LOCATION_ENTRY_COL_LOCAL_COMPARE_NAME, &local_compare_name,
+ LOC_GWEATHER_LOCATION_ENTRY_COL_ENGLISH_COMPARE_NAME, &english_compare_name,
-1);
match = match_compare_name (key, local_compare_name) || match_compare_name (key, english_compare_name);
@@ -684,10 +742,100 @@ match_selected (GtkEntryCompletion *completion,
GtkTreeIter *iter,
gpointer entry)
{
- set_location_internal (entry, model, iter, NULL);
+ if (model != ((GWeatherLocationEntry *)entry)->priv->model) {
+ GeocodePlace *place;
+ gtk_tree_model_get (model, iter,
+ PLACE_GWEATHER_LOCATION_ENTRY_COL_PLACE, &place,
+ -1);
+ GeocodeLocation *loc = geocode_place_get_location (place);
+
+ GWeatherLocation *location;
+ location = gweather_location_find_nearest_city (NULL, geocode_location_get_latitude (loc),
geocode_location_get_longitude (loc));
+
+ location = create_new_detached_location(location, geocode_location_get_description (loc), TRUE,
+ geocode_location_get_latitude (loc) * M_PI / 180.0,
+ geocode_location_get_longitude (loc) * M_PI / 180.0);
+
+ set_location_internal (entry, model, NULL, location);
+ } else {
+ set_location_internal (entry, model, iter, NULL);
+ }
return TRUE;
}
+static gboolean
+new_matcher (GtkEntryCompletion *completion, const char *key,
+ GtkTreeIter *iter, gpointer user_data)
+{
+ return TRUE;
+}
+
+static void
+fill_store (gpointer data, gpointer user_data)
+{
+ GeocodePlace *place = GEOCODE_PLACE (data);
+ GeocodeLocation *loc = geocode_place_get_location (place);
+ GtkTreeIter iter;
+
+ gtk_tree_store_append (user_data, &iter, NULL);
+ gtk_tree_store_set (user_data, &iter,
+ PLACE_GWEATHER_LOCATION_ENTRY_COL_PLACE, place,
+ PLACE_GWEATHER_LOCATION_ENTRY_COL_DISPLAY_NAME, geocode_location_get_description
(loc),
+ PLACE_GWEATHER_LOCATION_ENTRY_COL_LOCAL_COMPARE_NAME,
geocode_location_get_description (loc),
+ -1);
+}
+
+static void
+_got_places (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GList *places;
+ GWeatherLocationEntry *self = user_data;
+ GError *error = NULL;
+ GtkTreeStore *store = NULL;
+ GtkEntryCompletion *completion = gtk_entry_get_completion (user_data);
+
+ places = geocode_forward_search_finish (GEOCODE_FORWARD (source_object), result, &error);
+ if (places == NULL) {
+ /* return without touching anything if cancelled (the entry might have been disposed) */
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+ return;
+ }
+
+ gtk_entry_completion_delete_action (completion, 0);
+ gtk_entry_completion_set_match_func (completion, matcher, NULL, NULL);
+ gtk_entry_completion_set_model (completion, self->priv->model);
+ return;
+ }
+
+ store = gtk_tree_store_new (4, G_TYPE_STRING, GEOCODE_TYPE_PLACE, G_TYPE_STRING, G_TYPE_STRING);
+ g_list_foreach (places, fill_store, store);
+ gtk_entry_completion_set_match_func (completion, new_matcher, NULL, NULL);
+ gtk_entry_completion_set_model (completion, GTK_TREE_MODEL (store));
+ gtk_entry_completion_delete_action (completion, 0);
+ g_object_unref (store);
+}
+
+static void
+_no_matches (GtkEntryCompletion *completion, GWeatherLocationEntry *entry) {
+ const gchar *key = gtk_entry_get_text(GTK_ENTRY (entry));
+ GeocodeForward *forward;
+
+ if (entry->priv->cancellable) {
+ g_cancellable_cancel (entry->priv->cancellable);
+ g_object_unref (entry->priv->cancellable);
+ entry->priv->cancellable = NULL;
+ } else {
+ gtk_entry_completion_insert_action_text (completion, 0, "Loading...");
+ }
+
+ entry->priv->cancellable = g_cancellable_new ();
+
+ forward = geocode_forward_new_for_string(key);
+ geocode_forward_search_async (forward, entry->priv->cancellable, _got_places, entry);
+}
+
/**
* gweather_location_entry_new:
* @top: the top-level location for the entry.
@@ -707,3 +855,45 @@ gweather_location_entry_new (GWeatherLocation *top)
"top", top,
NULL);
}
+
+static GWeatherLocation *
+create_new_detached_location (GWeatherLocation *nearest_station,
+ const char *name,
+ gboolean latlon_valid,
+ gdouble latitude,
+ gdouble longitude)
+{
+ GWeatherLocation *self;
+ char *normalized;
+
+ self = g_slice_new0 (GWeatherLocation);
+ self->ref_count = 1;
+ self->level = GWEATHER_LOCATION_DETACHED;
+ self->english_name = g_strdup (name);
+ self->local_name = g_strdup (name);
+
+ normalized = g_utf8_normalize (name, -1, G_NORMALIZE_ALL);
+ self->english_sort_name = g_utf8_casefold (normalized, -1);
+ self->local_sort_name = g_strdup (self->english_sort_name);
+ g_free (normalized);
+
+ self->parent = nearest_station;
+ self->children = NULL;
+
+ if (nearest_station)
+ self->station_code = g_strdup (nearest_station->station_code);
+
+ g_assert (nearest_station || latlon_valid);
+
+ if (latlon_valid) {
+ self->latlon_valid = TRUE;
+ self->latitude = latitude;
+ self->longitude = longitude;
+ } else {
+ self->latlon_valid = nearest_station->latlon_valid;
+ self->latitude = nearest_station->latitude;
+ self->longitude = nearest_station->longitude;
+ }
+
+ return self;
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]