Commit 01abacdc authored by Emmanuel Milou's avatar Emmanuel Milou
Browse files

Make the search asynchronous

parent a7154567
......@@ -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){
......
......@@ -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){
......
......@@ -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);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment