[gnome-clocks] search-provider: rewrite to be stateless



commit c6681f8c69fe8b5df5b8f57d81ca0de2f13b226d
Author: Cosimo Cecchi <cosimo endlessm com>
Date:   Mon May 2 14:29:45 2016 +0800

    search-provider: rewrite to be stateless
    
    Currently the search provider carries state between searches. This is
    a source of bugs, as sometimes search results are not consistent or not
    returned at all for certain searches.
    
    This commit uses gweather_location_serialize()/deserialize() to make
    the provider stateless.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=737387

 src/search-provider.vala |  118 ++++++++++++++++++++++++++-------------------
 1 files changed, 68 insertions(+), 50 deletions(-)
---
diff --git a/src/search-provider.vala b/src/search-provider.vala
index 090d294..a98ecdf 100644
--- a/src/search-provider.vala
+++ b/src/search-provider.vala
@@ -24,9 +24,6 @@ public class SearchProvider : Object {
     [DBus (visible = false)]
     public signal void activate (uint32 timestamp);
 
-    private HashTable<string, GWeather.Location> matches;
-    private int count; // Used to make up id strings
-
     private string[] normalize_terms (string[] terms) {
         var normalized_terms = new GenericArray<string> ();
         foreach (string t in terms) {
@@ -53,80 +50,101 @@ public class SearchProvider : Object {
         return true;
     }
 
-    private async void search_locations (GWeather.Location location, string[] normalized_terms) {
+    private string serialize_location (GWeather.Location location) {
+        return location.serialize().print(false);
+    }
+
+    private GWeather.Location? deserialize_location (string str) {
+        Variant? variant;
+
+        try {
+            variant = Variant.parse(new VariantType ("(uv)"), str, null, null);
+        } catch (GLib.VariantParseError e) {
+            warning ("Malformed variant: %s", e.message);
+            return null;
+        }
+
+        var world = GWeather.Location.get_world ();
+        return world.deserialize(variant);
+    }
+
+    private async void search_locations_recurse (GWeather.Location location, string[] normalized_terms,
+                                                 GenericArray<GWeather.Location> matches) {
         GWeather.Location? []locations = location.get_children ();
         if (locations != null) {
             for (int i = 0; i < locations.length; i++) {
                 if (locations[i].get_level () == GWeather.LocationLevel.CITY) {
                     if (location_matches(locations[i], normalized_terms)) {
-                        matches.insert (count.to_string (), locations[i]);
-                        count++;
+                        matches.add (locations[i]);
                     }
                 }
 
-                yield search_locations (locations[i], normalized_terms);
+                yield search_locations_recurse (locations[i], normalized_terms, matches);
             }
         }
     }
 
-    public async string[] get_initial_result_set (string[] terms) {
-        // clear the cache
-        matches = new HashTable<string, GWeather.Location> (str_hash, str_equal);
-        count = 0;
+    private async string[] search_locations (string[] normalized_terms) {
+        var world = GWeather.Location.get_world ();
+        var matches = new GenericArray<GWeather.Location> ();
 
-        yield search_locations (GWeather.Location.get_world (), normalize_terms (terms));
+        yield search_locations_recurse (world, normalized_terms, matches);
 
-        var result = new GenericArray<string> ();
-        matches.foreach ((id, location) => {
-            result.add (id);
+        string[] result = {};
+        matches.foreach ((location) => {
+            // HACK: the search provider interface does not currently allow variants as result IDs
+            result += serialize_location (location);
         });
 
-        return result.data;
+        return result;
+    }
+
+    public async string[] get_initial_result_set (string[] terms) {
+        return yield search_locations (normalize_terms (terms));
     }
 
     public async string[] get_subsearch_result_set (string[] previous_results, string[] terms) {
-        var result = new GenericArray<string> ();
-
-        // It looks like the shell sometimes calls get_subsearch directly
-        // without calling get_initial first... not sure whether this is a
-        // gnome-shell bug or if it is by design in some condition that
-        // eludes me. Either way, if that happens, let's just fall back to
-        // a full initial search
-        if (matches == null) {
-            yield get_initial_result_set (terms);
-            matches.foreach ((id, location) => {
-                result.add (id);
-            });
-        } else {
-            var normalized_terms = normalize_terms (terms);
-
-            foreach (var id in previous_results) {
-                var location = matches.get (id);
-                if (location != null && location_matches (location, normalized_terms)) {
-                    result.add (id);
-                }
+        var normalized_terms = normalize_terms (terms);
+
+        if (previous_results.length == 0) {
+            return yield search_locations (normalized_terms);
+        }
+
+        string[] result = {};
+        foreach (var str in previous_results) {
+            var location = deserialize_location (str);
+
+            if (location != null && location_matches (location, normalized_terms)) {
+                result += (str);
             }
         }
 
-        return result.data;
+        return result;
     }
 
     public HashTable<string, Variant>[] get_result_metas (string[] results) {
         var result = new GenericArray<HashTable<string, Variant>> ();
-        foreach (var id in results) {
-            var meta = new HashTable<string, Variant> (str_hash, str_equal);;
-            var location = matches.get (id);
-            if (location != null) {
-                var item = new World.Item (location);
-                string time_label = item.time_label;
-                string day =  item.day_label;
-                if (day != null) {
-                    time_label += " " + day;
-                }
-                meta.insert ("id", id);
-                meta.insert ("name", time_label);
-                meta.insert ("description", item.name);
+        int count = 0;
+
+        foreach (var str in results) {
+            var location = deserialize_location (str);
+
+            if (location == null) {
+                continue;
             }
+
+            var meta = new HashTable<string, Variant> (str_hash, str_equal);
+            var item = new World.Item (location);
+            string time_label = item.time_label;
+            string day =  item.day_label;
+            if (day != null) {
+                time_label += " " + day;
+            }
+            count++;
+            meta.insert ("id", count.to_string());
+            meta.insert ("name", time_label);
+            meta.insert ("description", item.name);
+
             result.add (meta);
         }
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]