aboutsummaryrefslogtreecommitdiff
path: root/src/timezone-completion.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/timezone-completion.c')
-rw-r--r--src/timezone-completion.c103
1 files changed, 71 insertions, 32 deletions
diff --git a/src/timezone-completion.c b/src/timezone-completion.c
index f570c33..aaf6bdc 100644
--- a/src/timezone-completion.c
+++ b/src/timezone-completion.c
@@ -58,14 +58,33 @@ static void timezone_completion_finalize (GObject *object);
G_DEFINE_TYPE (TimezoneCompletion, timezone_completion, GTK_TYPE_ENTRY_COMPLETION);
+static gboolean
+match_func (GtkEntryCompletion *completion, const gchar *key,
+ GtkTreeIter *iter, gpointer user_data)
+{
+ // geonames does the work for us
+ return TRUE;
+}
+
static void
save_and_use_model (TimezoneCompletion * completion, GtkTreeModel * model)
{
TimezoneCompletionPrivate * priv = TIMEZONE_COMPLETION_GET_PRIVATE(completion);
- g_hash_table_insert (priv->request_table, g_strdup (priv->request_text), g_object_ref (model));
+ g_hash_table_insert (priv->request_table, g_strdup (priv->request_text), g_object_ref_sink (model));
+
+ if (model == priv->initial_model)
+ gtk_entry_completion_set_match_func (GTK_ENTRY_COMPLETION (completion), NULL, NULL, NULL);
+ else
+ gtk_entry_completion_set_match_func (GTK_ENTRY_COMPLETION (completion), match_func, NULL, NULL);
+
gtk_entry_completion_set_model (GTK_ENTRY_COMPLETION (completion), model);
gtk_entry_completion_complete (GTK_ENTRY_COMPLETION (completion));
+
+ /* By this time, the changed signal has come and gone. We didn't give a
+ model to use, so no popup appeared for user. Poke the entry again to show
+ popup in 300ms. */
+ g_signal_emit_by_name (priv->entry, "changed");
}
static void
@@ -74,6 +93,9 @@ json_parse_ready (GObject *object, GAsyncResult *res, gpointer user_data)
TimezoneCompletion * completion = TIMEZONE_COMPLETION (user_data);
TimezoneCompletionPrivate * priv = TIMEZONE_COMPLETION_GET_PRIVATE(completion);
GError * error = NULL;
+ const gchar * prev_name = NULL;
+ const gchar * prev_admin1 = NULL;
+ const gchar * prev_country = NULL;
json_parser_load_from_stream_finish (JSON_PARSER (object), res, &error);
@@ -98,8 +120,12 @@ json_parse_ready (GObject *object, GAsyncResult *res, gpointer user_data)
JsonReader * reader = json_reader_new (json_parser_get_root (JSON_PARSER (object)));
- if (!json_reader_is_array (reader))
+ if (!json_reader_is_array (reader)) {
+ g_warning ("Could not parse geoname JSON data");
+ save_and_use_model (completion, priv->initial_model);
+ g_object_unref (G_OBJECT (reader));
return;
+ }
gint i, count = json_reader_count_elements (reader);
for (i = 0; i < count; ++i) {
@@ -112,6 +138,7 @@ json_parse_ready (GObject *object, GAsyncResult *res, gpointer user_data)
const gchar * country = NULL;
const gchar * longitude = NULL;
const gchar * latitude = NULL;
+ gboolean skip = FALSE;
if (json_reader_read_member (reader, "name")) {
name = json_reader_get_string_value (reader);
json_reader_end_member (reader);
@@ -133,23 +160,37 @@ json_parse_ready (GObject *object, GAsyncResult *res, gpointer user_data)
json_reader_end_member (reader);
}
- GtkTreeIter iter;
- gtk_list_store_append (store, &iter);
- gtk_list_store_set (store, &iter,
- TIMEZONE_COMPLETION_ZONE, NULL,
- TIMEZONE_COMPLETION_NAME, name,
- TIMEZONE_COMPLETION_ADMIN1, admin1,
- TIMEZONE_COMPLETION_COUNTRY, country,
- TIMEZONE_COMPLETION_LONGITUDE, longitude,
- TIMEZONE_COMPLETION_LATITUDE, latitude,
- -1);
+ if (g_strcmp0(name, prev_name) == 0 &&
+ g_strcmp0(admin1, prev_admin1) == 0 &&
+ g_strcmp0(country, prev_country) == 0) {
+ // Sometimes the data will have duplicate entries that only differ
+ // in longitude and latitude. e.g. "rio de janeiro", "wellington"
+ skip = TRUE;
+ }
+
+ if (!skip) {
+ GtkTreeIter iter;
+ gtk_list_store_append (store, &iter);
+ gtk_list_store_set (store, &iter,
+ TIMEZONE_COMPLETION_ZONE, NULL,
+ TIMEZONE_COMPLETION_NAME, name,
+ TIMEZONE_COMPLETION_ADMIN1, admin1,
+ TIMEZONE_COMPLETION_COUNTRY, country,
+ TIMEZONE_COMPLETION_LONGITUDE, longitude,
+ TIMEZONE_COMPLETION_LATITUDE, latitude,
+ -1);
+ }
+
+ prev_name = name;
+ prev_admin1 = admin1;
+ prev_country = country;
}
json_reader_end_element (reader);
}
save_and_use_model (completion, GTK_TREE_MODEL (store));
- g_object_unref (G_OBJECT (store));
+ g_object_unref (G_OBJECT (reader));
}
static void
@@ -189,15 +230,6 @@ request_zones (TimezoneCompletion * completion)
return FALSE;
}
- const gchar * text = gtk_entry_get_text (priv->entry);
-
- gpointer data;
- if (g_hash_table_lookup_extended (priv->request_table, text, NULL, &data)) {
- gtk_entry_completion_set_model (GTK_ENTRY_COMPLETION (completion), GTK_TREE_MODEL (data));
- gtk_entry_completion_complete (GTK_ENTRY_COMPLETION (completion));
- return FALSE;
- }
-
/* Cancel any ongoing request */
if (priv->cancel) {
g_cancellable_cancel (priv->cancel);
@@ -205,6 +237,7 @@ request_zones (TimezoneCompletion * completion)
}
g_free (priv->request_text);
+ const gchar * text = gtk_entry_get_text (priv->entry);
priv->request_text = g_strdup (text);
gchar * escaped = g_uri_escape_string (text, NULL, FALSE);
@@ -225,7 +258,18 @@ entry_changed (GtkEntry * entry, TimezoneCompletion * completion)
if (priv->queued_request) {
g_source_remove (priv->queued_request);
}
- priv->queued_request = g_timeout_add (300, (GSourceFunc)request_zones, completion);
+
+ /* See if we've already got this one */
+ const gchar * text = gtk_entry_get_text (priv->entry);
+ gpointer data;
+ if (g_hash_table_lookup_extended (priv->request_table, text, NULL, &data)) {
+ gtk_entry_completion_set_model (GTK_ENTRY_COMPLETION (completion), GTK_TREE_MODEL (data));
+ }
+ else {
+ priv->queued_request = g_timeout_add (300, (GSourceFunc)request_zones, completion);
+ gtk_entry_completion_set_model (GTK_ENTRY_COMPLETION (completion), NULL);
+ }
+ gtk_entry_completion_complete (GTK_ENTRY_COMPLETION (completion));
}
void
@@ -233,6 +277,10 @@ timezone_completion_watch_entry (TimezoneCompletion * completion, GtkEntry * ent
{
TimezoneCompletionPrivate * priv = TIMEZONE_COMPLETION_GET_PRIVATE (completion);
+ if (priv->queued_request) {
+ g_source_remove (priv->queued_request);
+ priv->queued_request = 0;
+ }
if (priv->entry) {
g_source_remove (priv->changed_id);
g_object_remove_weak_pointer (G_OBJECT (priv->entry), (gpointer *)&priv->entry);
@@ -317,14 +365,6 @@ data_func (GtkCellLayout *cell_layout, GtkCellRenderer *cell,
g_value_unset (&country_val);
}
-static gboolean
-match_func (GtkEntryCompletion *completion, const gchar *key,
- GtkTreeIter *iter, gpointer user_data)
-{
- // geonames does the work for us
- return TRUE;
-}
-
static void
timezone_completion_class_init (TimezoneCompletionClass *klass)
{
@@ -345,7 +385,6 @@ timezone_completion_init (TimezoneCompletion * self)
priv->initial_model = GTK_TREE_MODEL (get_initial_model ());
- gtk_entry_completion_set_match_func (GTK_ENTRY_COMPLETION (self), match_func, NULL, NULL);
g_object_set (G_OBJECT (self),
"text-column", TIMEZONE_COMPLETION_NAME,
"popup-set-width", FALSE,