From 01abacdc80cedd878e44eeb773a7338f3d972bd7 Mon Sep 17 00:00:00 2001 From: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com> Date: Fri, 6 Mar 2009 15:01:15 -0500 Subject: [PATCH] Make the search asynchronous --- sflphone-gtk/src/calltree.c | 66 +++--- sflphone-gtk/src/contactlist/eds.c | 344 +++++++++++++++++++---------- sflphone-gtk/src/contactlist/eds.h | 7 + 3 files changed, 274 insertions(+), 143 deletions(-) diff --git a/sflphone-gtk/src/calltree.c b/sflphone-gtk/src/calltree.c index 1092acc8c2..61ce18b7d4 100644 --- a/sflphone-gtk/src/calltree.c +++ b/sflphone-gtk/src/calltree.c @@ -222,15 +222,46 @@ show_history_tab(GtkToggleToolButton *toggle_tool_button UNUSED, toolbar_update_buttons(); gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(histfilter)); +} + + static void +handler_async_search (GList *hits, gpointer user_data) { + + GtkTreeSelection *sel; + GList *i; + + for (i = hits; i != NULL; i = i->next) + { + Hit *entry; + entry = i->data; + if (entry) + { + /* Create entry for business phone information */ + create_new_entry_in_contactlist (entry->name, entry->phone_business, CONTACT_PHONE_BUSINESS); + /* Create entry for home phone information */ + create_new_entry_in_contactlist (entry->name, entry->phone_home, CONTACT_PHONE_HOME); + /* Create entry for mobile phone information */ + create_new_entry_in_contactlist (entry->name, entry->phone_mobile, CONTACT_PHONE_MOBILE); + } + free_hit(entry); + } + g_list_free(hits); + + active_calltree = contacts; + gtk_widget_hide(current_calls->tree); + gtk_widget_hide(history->tree); + gtk_widget_show(contacts->tree); + + sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (active_calltree->view)); + g_signal_emit_by_name(sel, "changed"); + toolbar_update_buttons(); + } static void show_contacts_tab(GtkToggleToolButton *toggle_tool_button UNUSED, gpointer user_data UNUSED) { - GtkTreeSelection *sel; - GList *results; - GList *i; call_t *j; gchar* msg; @@ -250,33 +281,10 @@ show_contacts_tab(GtkToggleToolButton *toggle_tool_button UNUSED, call_list_reset(contacts); // do a synchronous search - results = search_sync (gtk_entry_get_text(GTK_ENTRY(filter_entry)), 50); - - for (i = results; i != NULL; i = i->next) - { - Hit *entry; - entry = i->data; - if (entry) - { - /* Create entry for business phone information */ - create_new_entry_in_contactlist (entry->name, entry->phone_business, CONTACT_PHONE_BUSINESS); - /* Create entry for home phone information */ - create_new_entry_in_contactlist (entry->name, entry->phone_home, CONTACT_PHONE_HOME); - /* Create entry for mobile phone information */ - create_new_entry_in_contactlist (entry->name, entry->phone_mobile, CONTACT_PHONE_MOBILE); - } - free_hit(entry); - } - g_list_free(results); - - active_calltree = contacts; - gtk_widget_hide(current_calls->tree); - gtk_widget_hide(history->tree); - gtk_widget_show(contacts->tree); + //results = search_sync (gtk_entry_get_text(GTK_ENTRY(filter_entry)), 50); - sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (active_calltree->view)); - g_signal_emit_by_name(sel, "changed"); - toolbar_update_buttons(); + // do an asynchronous search + search_async (gtk_entry_get_text (GTK_ENTRY (filter_entry)), 50, &handler_async_search, NULL); } void create_new_entry_in_contactlist (gchar *contact_name, gchar *contact_phone, contact_type_t type){ diff --git a/sflphone-gtk/src/contactlist/eds.c b/sflphone-gtk/src/contactlist/eds.c index 6a9cfc8613..f9e64c0e00 100644 --- a/sflphone-gtk/src/contactlist/eds.c +++ b/sflphone-gtk/src/contactlist/eds.c @@ -30,12 +30,20 @@ #include <pango/pango.h> #include "eds.h" +typedef struct _Handler_And_Data { + SearchAsyncHandler handler; + gpointer user_data; + GList *hits; + int max_results_remaining; + int book_views_remaining; +} Handler_And_Data; + static GSList *books = NULL; static EContactField search_fields[] = { E_CONTACT_FULL_NAME, E_CONTACT_PHONE_BUSINESS, E_CONTACT_NICKNAME, 0 }; static int n_search_fields = G_N_ELEMENTS (search_fields) - 1; -void + void free_hit (Hit *h) { g_free (h->name); @@ -48,154 +56,262 @@ free_hit (Hit *h) /** * Split a string of tokens separated by whitespace into an array of tokens. */ -static GArray * + static GArray * split_query_string (const gchar *str) { - GArray *parts = g_array_sized_new (FALSE, FALSE, sizeof (char *), 2); - PangoLogAttr *attrs; - guint str_len = strlen (str), word_start = 0, i; - - attrs = g_new0 (PangoLogAttr, str_len + 1); - /* TODO: do we need to specify a particular language or is NULL ok? */ - pango_get_log_attrs (str, -1, -1, NULL, attrs, str_len + 1); - - for (i = 0; i < str_len + 1; i++) { - char *start_word, *end_word, *word; - if (attrs[i].is_word_end) { - start_word = g_utf8_offset_to_pointer (str, word_start); - end_word = g_utf8_offset_to_pointer (str, i); - word = g_strndup (start_word, end_word - start_word); - g_array_append_val (parts, word); - } - if (attrs[i].is_word_start) { - word_start = i; + GArray *parts = g_array_sized_new (FALSE, FALSE, sizeof (char *), 2); + PangoLogAttr *attrs; + guint str_len = strlen (str), word_start = 0, i; + + attrs = g_new0 (PangoLogAttr, str_len + 1); + /* TODO: do we need to specify a particular language or is NULL ok? */ + pango_get_log_attrs (str, -1, -1, NULL, attrs, str_len + 1); + + for (i = 0; i < str_len + 1; i++) { + char *start_word, *end_word, *word; + if (attrs[i].is_word_end) { + start_word = g_utf8_offset_to_pointer (str, word_start); + end_word = g_utf8_offset_to_pointer (str, i); + word = g_strndup (start_word, end_word - start_word); + g_array_append_val (parts, word); + } + if (attrs[i].is_word_start) { + word_start = i; + } } - } - g_free (attrs); - return parts; + g_free (attrs); + return parts; } /** * Create a query which looks for the specified string in a contact's full name, email addresses and * nick name. */ -static EBookQuery* + static EBookQuery* create_query (const char* s) { - EBookQuery *query; - GArray *parts = split_query_string (s); - EBookQuery ***field_queries; - EBookQuery **q; - guint j; - int i; - - q = g_new0 (EBookQuery *, n_search_fields); - field_queries = g_new0 (EBookQuery **, n_search_fields); - - for (i = 0; i < n_search_fields; i++) { - field_queries[i] = g_new0 (EBookQuery *, parts->len); - for (j = 0; j < parts->len; j++) { - field_queries[i][j] = e_book_query_field_test (search_fields[i], E_BOOK_QUERY_CONTAINS, g_array_index (parts, gchar *, j)); + EBookQuery *query; + GArray *parts = split_query_string (s); + EBookQuery ***field_queries; + EBookQuery **q; + guint j; + int i; + + q = g_new0 (EBookQuery *, n_search_fields); + field_queries = g_new0 (EBookQuery **, n_search_fields); + + for (i = 0; i < n_search_fields; i++) { + field_queries[i] = g_new0 (EBookQuery *, parts->len); + for (j = 0; j < parts->len; j++) { + field_queries[i][j] = e_book_query_field_test (search_fields[i], E_BOOK_QUERY_CONTAINS, g_array_index (parts, gchar *, j)); + } + q[i] = e_book_query_and (parts->len, field_queries[i], TRUE); } - q[i] = e_book_query_and (parts->len, field_queries[i], TRUE); - } - g_array_free (parts, TRUE); + g_array_free (parts, TRUE); - query = e_book_query_or (n_search_fields, q, TRUE); + query = e_book_query_or (n_search_fields, q, TRUE); - for (i = 0; i < n_search_fields; i++) { - g_free (field_queries[i]); - } - g_free (field_queries); - g_free (q); + for (i = 0; i < n_search_fields; i++) { + g_free (field_queries[i]); + } + g_free (field_queries); + g_free (q); - return query; + return query; } /** * Initialize address book */ -void + void init (void) { - GSList *list, *l; - ESourceList *source_list; - source_list = e_source_list_new_for_gconf_default ("/apps/evolution/addressbook/sources"); - - if (source_list == NULL) { - return; - } - list = e_source_list_peek_groups (source_list); - - for (l = list; l != NULL; l = l->next) { - ESourceGroup *group = l->data; - GSList *sources = NULL, *m; - sources = e_source_group_peek_sources (group); - for (m = sources; m != NULL; m = m->next) { - ESource *source = m->data; - EBook *book = e_book_new (source, NULL); - if (book != NULL) { - books = g_slist_prepend (books, book); - e_book_open(book, TRUE, NULL); - } + GSList *list, *l; + ESourceList *source_list; + source_list = e_source_list_new_for_gconf_default ("/apps/evolution/addressbook/sources"); + + if (source_list == NULL) { + return; } - } + list = e_source_list_peek_groups (source_list); - g_object_unref (source_list); + for (l = list; l != NULL; l = l->next) { + ESourceGroup *group = l->data; + GSList *sources = NULL, *m; + sources = e_source_group_peek_sources (group); + for (m = sources; m != NULL; m = m->next) { + ESource *source = m->data; + EBook *book = e_book_new (source, NULL); + if (book != NULL) { + books = g_slist_prepend (books, book); + e_book_open(book, TRUE, NULL); + } + } + } + + g_object_unref (source_list); } /** * Do a synchronized search in EDS address book */ -GList * + GList * search_sync (const char *query, - int max_results) + int max_results) +{ + GSList *iter = NULL; + GList *contacts = NULL; + GList *hits = NULL; + + EBookQuery* book_query = create_query (query); + for (iter = books; iter != NULL; iter = iter->next) { + if (max_results <= 0) { + break; + } + EBook *book = (EBook *) iter->data; + e_book_get_contacts (book, book_query, &contacts, NULL); + for (; contacts != NULL; contacts = g_list_next (contacts)) { + EContact *contact; + Hit *hit; + gchar *number; + + contact = E_CONTACT (contacts->data); + hit = g_new0 (Hit, 1); + + /* Get business phone information */ + fetch_information_from_contact (contact, E_CONTACT_PHONE_BUSINESS, &number); + hit->phone_business = g_strdup (number); + + /* Get home phone information */ + fetch_information_from_contact (contact, E_CONTACT_PHONE_HOME, &number); + hit->phone_home = g_strdup (number); + + /* Get mobile phone information */ + fetch_information_from_contact (contact, E_CONTACT_PHONE_MOBILE, &number); + hit->phone_mobile = g_strdup (number); + + hit->name = g_strdup ((char*) e_contact_get_const (contact, E_CONTACT_NAME_OR_ORG)); + if(! hit->name) + hit->name = ""; + + hits = g_list_append (hits, hit); + max_results--; + if (max_results <= 0) { + break; + } + } + } + e_book_query_unref (book_query); + + return hits; +} + + static void +view_finish (EBookView *book_view, Handler_And_Data *had) { - GSList *iter = NULL; - GList *contacts = NULL; - GList *hits = NULL; - - EBookQuery* book_query = create_query (query); - for (iter = books; iter != NULL; iter = iter->next) { - if (max_results <= 0) { - break; + SearchAsyncHandler had_handler = had->handler; + GList *had_hits = had->hits; + gpointer had_user_data = had->user_data; + g_free (had); + + g_return_if_fail (book_view != NULL); + g_object_unref (book_view); + + had_handler (had_hits, had_user_data); +} + + static void +view_contacts_added_cb (EBookView *book_view, GList *contacts, gpointer user_data) +{ + Handler_And_Data *had = (Handler_And_Data *) user_data; + if (had->max_results_remaining <= 0) { + e_book_view_stop (book_view); + had->book_views_remaining--; + if (had->book_views_remaining == 0) { + view_finish (book_view, had); + return; + } } - EBook *book = (EBook *) iter->data; - e_book_get_contacts (book, book_query, &contacts, NULL); for (; contacts != NULL; contacts = g_list_next (contacts)) { - EContact *contact; - Hit *hit; - gchar *number; - - contact = E_CONTACT (contacts->data); - hit = g_new0 (Hit, 1); - - /* Get business phone information */ - fetch_information_from_contact (contact, E_CONTACT_PHONE_BUSINESS, &number); - hit->phone_business = g_strdup (number); - - /* Get home phone information */ - fetch_information_from_contact (contact, E_CONTACT_PHONE_HOME, &number); - hit->phone_home = g_strdup (number); - - /* Get mobile phone information */ - fetch_information_from_contact (contact, E_CONTACT_PHONE_MOBILE, &number); - hit->phone_mobile = g_strdup (number); - - hit->name = g_strdup ((char*) e_contact_get_const (contact, E_CONTACT_NAME_OR_ORG)); - if(! hit->name) - hit->name = ""; - - hits = g_list_append (hits, hit); - max_results--; - if (max_results <= 0) { - break; - } + EContact *contact; + Hit *hit; + gchar *number; + + contact = E_CONTACT (contacts->data); + hit = g_new (Hit, 1); + + //hit->pixbuf = pixbuf_from_contact (contact); + /* Get business phone information */ + fetch_information_from_contact (contact, E_CONTACT_PHONE_BUSINESS, &number); + hit->phone_business = g_strdup (number); + + /* Get home phone information */ + fetch_information_from_contact (contact, E_CONTACT_PHONE_HOME, &number); + hit->phone_home = g_strdup (number); + + /* Get mobile phone information */ + fetch_information_from_contact (contact, E_CONTACT_PHONE_MOBILE, &number); + hit->phone_mobile = g_strdup (number); + + hit->name = g_strdup ((char*) e_contact_get_const (contact, E_CONTACT_NAME_OR_ORG)); + if(! hit->name) + hit->name = ""; + + had->hits = g_list_append (had->hits, hit); + had->max_results_remaining--; + if (had->max_results_remaining <= 0) { + e_book_view_stop (book_view); + had->book_views_remaining--; + if (had->book_views_remaining == 0) { + view_finish (book_view, had); + } + break; + } + } +} + + static void +view_completed_cb (EBookView *book_view, EBookViewStatus status, gpointer user_data) +{ + Handler_And_Data *had = (Handler_And_Data *) user_data; + had->book_views_remaining--; + if (had->book_views_remaining == 0) { + view_finish (book_view, had); + } +} + + void +search_async (const char *query, + int max_results, + SearchAsyncHandler handler, + gpointer user_data) +{ + GSList *iter; + + EBookQuery* book_query = create_query (query); + + Handler_And_Data *had = g_new (Handler_And_Data, 1); + had->handler = handler; + had->user_data = user_data; + had->hits = NULL; + had->max_results_remaining = max_results; + had->book_views_remaining = 0; + for (iter = books; iter != NULL; iter = iter->next) { + EBook *book = (EBook *) iter->data; + EBookView *book_view = NULL; + e_book_get_book_view (book, book_query, NULL, max_results, &book_view, NULL); + if (book_view != NULL) { + had->book_views_remaining++; + g_signal_connect (book_view, "contacts_added", (GCallback) view_contacts_added_cb, had); + g_signal_connect (book_view, "sequence_complete", (GCallback) view_completed_cb, had); + e_book_view_start (book_view); + } + } + if (had->book_views_remaining == 0) { + g_free (had); } - } - e_book_query_unref (book_query); - return hits; + e_book_query_unref (book_query); } void fetch_information_from_contact (EContact *contact, EContactField field, gchar **info){ diff --git a/sflphone-gtk/src/contactlist/eds.h b/sflphone-gtk/src/contactlist/eds.h index 55cbbe8ae9..84a14bb149 100644 --- a/sflphone-gtk/src/contactlist/eds.h +++ b/sflphone-gtk/src/contactlist/eds.h @@ -44,8 +44,15 @@ typedef struct _Hit void free_hit (Hit *h); +typedef void (* SearchAsyncHandler) (GList *hits, gpointer user_data); + void init (void); +void search_async (const char *query, + int max_results, + SearchAsyncHandler handler, + gpointer user_data); + GList * search_sync (const char *query, int max_results); void fetch_information_from_contact (EContact *contact, EContactField field, gchar **info); -- GitLab