summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNiels De Graef <nielsdegraef@gmail.com>2017-12-26 23:33:24 +0100
committerNiels De Graef <nielsdegraef@gmail.com>2017-12-26 23:33:24 +0100
commit024738fcfcd1ee7795643c14dd4476e6cbbf53bf (patch)
tree110b0591f4e9a19f92cbdf47a63ae47f104eeed3
parent062acef135a62b530697a8454efa35ce3cdff5a0 (diff)
downloadgnome-contacts-024738fcfcd1ee7795643c14dd4476e6cbbf53bf.tar.gz
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.
-rw-r--r--src/contacts-shell-search-provider.vala192
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 ();
}
}