diff options
Diffstat (limited to 'src/contacts-shell-search-provider.vala')
-rw-r--r-- | 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 (); } } |