[gnome-contacts] SearchProvider: improve performance and add description.



commit 024738fcfcd1ee7795643c14dd4476e6cbbf53bf
Author: Niels De Graef <nielsdegraef gmail com>
Date:   Tue Dec 26 23:33:24 2017 +0100

    SearchProvider: improve performance and add description.
    
    Note that we don't need all the code from our own custom classes such as
    Contacts.Contact, we only want speed. The best way to do this is
    to put away all unnecessary operations and to just keep it simple.
    
    We're falling back to the SearchView of Folks. That means that the only
    way of improving performance, is to make SearchView better for this
    case.

 src/contacts-shell-search-provider.vala |  192 +++++++++++++++----------------
 1 files changed, 93 insertions(+), 99 deletions(-)
---
diff --git a/src/contacts-shell-search-provider.vala b/src/contacts-shell-search-provider.vala
index c47318a..1b895a9 100644
--- a/src/contacts-shell-search-provider.vala
+++ b/src/contacts-shell-search-provider.vala
@@ -1,153 +1,147 @@
-/* -*- Mode: vala; indent-tabs-mode: t; c-basic-offset: 2; tab-width: 8 -*- */
+/*
+ * Copyright (C) 2011 Alexander Larsson <alexl redhat com>
+ *
+ * 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/>.
+ */
+
 using Gee;
+using Folks;
 
 [DBus (name = "org.gnome.Shell.SearchProvider2")]
 public class Contacts.SearchProvider : Object {
-  SearchProviderApp app;
-  Store store;
-  Gee.HashMap<string, Contact> contacts_map;
-  private uint next_id;
+  private SearchProviderApp app;
+  private IndividualAggregator aggregator;
+  private SimpleQuery query;
+  private Variant serialized_fallback_icon;
 
   public SearchProvider (SearchProviderApp app) {
-    this.app = app;
-    if (!ensure_eds_accounts (false))
-      app.quit ();
-    store = new Store ();
-    contacts_map = new Gee.HashMap<string, Contact> ();
-    next_id = 0;
-
-    store.changed.connect ( (c) => {
-       contacts_map.set(c.get_data<string> ("search-id"), c);
-      });
-    store.added.connect ( (c) => {
-       var id = next_id++.to_string ();
-       c.set_data ("search-id", id);
-       contacts_map.set(id, c);
-      });
-    store.removed.connect ( (c) => {
-       contacts_map.unset(c.get_data<string> ("search-id"));
-      });
-  }
+    // Do this first, since this will be the slowest (and is async anyway)
+    this.aggregator = IndividualAggregator.dup ();
+    this.aggregator.prepare.begin ();
 
-  private static int compare_contacts (Contact a, Contact b) {
-    int a_prio = a.is_main ? 0 : -1;
-    int b_prio = b.is_main ? 0 : -1;
+    this.app = app;
+    this.serialized_fallback_icon = new ThemedIcon.from_names ({"avatar-default-symbolic"}).serialize ();;
 
-    if (a_prio > b_prio)
-      return -1;
-    if (a_prio < b_prio)
-      return 1;
+    var matched_fields = Query.MATCH_FIELDS_NAMES;
+    foreach (var field in Query.MATCH_FIELDS_ADDRESSES)
+      matched_fields += field;
+    this.query = new SimpleQuery ("", matched_fields);
 
-    if (is_set (a.display_name) && is_set (b.display_name))
-      return a.display_name.collate (b.display_name);
+    if (!ensure_eds_accounts (false))
+      this.app.quit ();
+  }
 
-    // Sort empty names last
-    if (is_set (a.display_name))
-      return -1;
-    if (is_set (b.display_name))
-      return 1;
+  public async string[] GetInitialResultSet (string[] terms) {
+    return yield do_search (terms);
+  }
 
-    return 0;
+  public async string[] GetSubsearchResultSet (string[] previous_results, string[] new_terms) {
+    return yield do_search (new_terms);
   }
 
   private async string[] do_search (string[] terms) {
-    app.hold ();
-    string[] normalized_terms =
-    Utils.canonicalize_for_search (string.joinv(" ", terms)).split(" ");
-
-    var matches = new ArrayList<Contact> ();
-    foreach (var c in store.get_contacts ()) {
-      if (c.is_hidden)
-       continue;
+    this.app.hold ();
 
-      if (c.contains_strings (normalized_terms))
-       matches.add (c);
+    // Make the query and search view
+    query.query_string = string.joinv(" ", terms);
+    var search_view = new SearchView (aggregator, query);
+    try {
+      yield search_view.prepare ();
+    } catch (Error e) {
+      error ("Couldn't load SearchView: %s", e.message);
+    }
+    var results = new string[search_view.individuals.size];
+    var i = 0;
+    foreach (var individual in search_view.individuals) {
+      results[i] = individual.id;
+      i++;
     }
 
-    matches.sort((CompareDataFunc<Contact>) compare_contacts);
-
-    var results = new string[matches.size];
-    for (int i = 0; i < matches.size; i++)
-      results[i] = matches[i].get_data ("search-id");
-    app.release ();
+    this.app.release ();
     return results;
   }
 
-  public async string[] GetInitialResultSet (string[] terms) {
-    return yield do_search (terms);
-  }
-
-  public async string[] GetSubsearchResultSet (string[] previous_results,
-                                              string[] new_terms) {
-    return yield do_search (new_terms);
+  public async HashTable<string, Variant>[] GetResultMetas (string[] ids) {
+    return yield get_metas (ids);
   }
 
   private async HashTable<string, Variant>[] get_metas (owned string[] ids) {
-    app.hold ();
+    this.app.hold ();
+
     var results = new ArrayList<HashTable> ();
     foreach (var id in ids) {
-      var contact = contacts_map.get (id);
-
-      if (contact == null)
+      Individual indiv = null;
+      try {
+        indiv = yield aggregator.look_up_individual (id);
+      } catch (Error e) {
+        continue;
+      }
+      if (indiv == null)
         continue;
 
       var meta = new HashTable<string, Variant> (str_hash, str_equal);
-      meta.insert ("id", new Variant.string (id));
+      meta["id"] = new Variant.string (id);
+      meta["name"] = new Variant.string (indiv.display_name);
+      meta["icon"] = (indiv.avatar != null)? indiv.avatar.serialize () : serialized_fallback_icon;
+
+      // Make a description based the first email address/phone nr/... we can find
+      var description = new StringBuilder ();
+
+      var email = Utils.get_first<EmailFieldDetails> (indiv.email_addresses);
+      if (email != null && email.value != null && email.value != "")
+        description.append (email.value);
 
-      meta.insert ("name", new Variant.string (contact.display_name));
+      var phone = Utils.get_first<PhoneFieldDetails> (indiv.phone_numbers);
+      if (phone != null && phone.value != null && phone.value != "") {
+        if (description.len > 0)
+          description.append (" / ");
+        description.append (phone.value);
+      }
+
+      meta["description"] = description.str;
 
-      if (contact.avatar_icon_data != null)
-        meta.insert ("icon", contact.avatar_icon_data);
-      else
-        meta.insert ("icon", new ThemedIcon ("avatar-default").serialize ());
       results.add (meta);
     }
-    app.release ();
+    this.app.release ();
     return results.to_array ();
   }
 
-  public async HashTable<string, Variant>[] GetResultMetas (string[] ids) {
-    return yield get_metas (ids);
-  }
-
-  public void ActivateResult (string search_id, string[] terms, uint32 timestamp) {
-    app.hold ();
+  public void ActivateResult (string id, string[] terms, uint32 timestamp) {
+    this.app.hold ();
 
-    var contact = contacts_map.get (search_id);
-
-    if (contact == null) {
-      app.release ();
-      return;
-    }
-
-    string id = contact.individual.id;
     try {
-      if (!Process.spawn_command_line_async ("gnome-contacts -i " + id))
-        stderr.printf ("Failed to launch contact with id '%s'\n", id);
+      Process.spawn_command_line_async ("gnome-contacts -i " + id);
     } catch (SpawnError e) {
-      stderr.printf ("Failed to launch contact with id '%s'\n", id);
+      stderr.printf ("Failed to launch contact with id '%s': %s\n.", id, e.message);
     }
-
-    app.release ();
+    this.app.release ();
   }
 
   public void LaunchSearch (string[] terms, uint32 timestamp) {
-    app.hold ();
+    this.app.hold ();
 
     debug ("LaunchSearch (%s)", string.joinv (", ", terms));
 
     try {
-      string[] args = {};
-      args += "gnome-contacts";
-      args += "--search";
+      string[] args = { "gnome-contacts", "--search" };
       args += string.joinv (" ", terms);
-      if (!Process.spawn_async (null, args, null, SpawnFlags.SEARCH_PATH, null, null))
-       stderr.printf ("Failed to launch Contacts for search\n");
+      Process.spawn_async (null, args, null, SpawnFlags.SEARCH_PATH, null, null);
     } catch (SpawnError error) {
       stderr.printf ("Failed to launch Contacts for search\n");
     }
 
-    app.release ();
+    this.app.release ();
   }
 }
 


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