diff options
This commit was manufactured by cvs2svn to create tagRELEASE-2_8_0
'RELEASE-2_8_0'.
svn path=/tags/RELEASE-2_8_0/; revision=23849
Diffstat (limited to 'addressbook/gui/component/select-names/e-select-names-completion.c')
-rw-r--r-- | addressbook/gui/component/select-names/e-select-names-completion.c | 1231 |
1 files changed, 0 insertions, 1231 deletions
diff --git a/addressbook/gui/component/select-names/e-select-names-completion.c b/addressbook/gui/component/select-names/e-select-names-completion.c deleted file mode 100644 index 39b5f7a008..0000000000 --- a/addressbook/gui/component/select-names/e-select-names-completion.c +++ /dev/null @@ -1,1231 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ - -/* - * e-select-names-completion.c - * - * Copyright (C) 2001 Ximian, Inc. - * - * Developed by Jon Trowbridge <trow@ximian.com> - */ - -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA. - */ - -#include <config.h> -#include "e-select-names-completion.h" - -#include <ctype.h> -#include <stdio.h> -#include <string.h> -#include <math.h> - -#include <gtk/gtksignal.h> - -#include <libebook/e-contact.h> -#include <addressbook/util/eab-book-util.h> -#include <addressbook/util/eab-destination.h> -#include <addressbook/gui/merging/eab-contact-compare.h> - -typedef struct { - EBook *book; - guint book_view_tag; - EBookView *book_view; - ESelectNamesCompletion *comp; - guint contacts_added_tag; - guint seq_complete_tag; - gboolean sequence_complete_received; - - gchar *cached_query_text; - GList *cached_cards; - gboolean cache_complete; - -} ESelectNamesCompletionBookData; - -struct _ESelectNamesCompletionPrivate { - - ESelectNamesTextModel *text_model; - - GList *book_data; - gint books_not_ready; - gint pending_completion_seq; - - gchar *waiting_query; - gint waiting_pos, waiting_limit; - gchar *query_text; - - gboolean match_contact_lists; - - gint minimum_query_length; -}; - -static void e_select_names_completion_class_init (ESelectNamesCompletionClass *); -static void e_select_names_completion_init (ESelectNamesCompletion *); -static void e_select_names_completion_dispose (GObject *object); - -static void e_select_names_completion_got_book_view_cb (EBook *book, EBookStatus status, EBookView *view, gpointer user_data); -static void e_select_names_completion_contacts_added_cb (EBookView *, const GList *cards, gpointer user_data); -static void e_select_names_completion_seq_complete_cb (EBookView *, EBookViewStatus status, gpointer user_data); - -static void e_select_names_completion_do_query (ESelectNamesCompletion *, const gchar *query_text, gint pos, gint limit); - -static void e_select_names_completion_handle_request (ECompletion *, const gchar *txt, gint pos, gint limit); -static void e_select_names_completion_end (ECompletion *); - -static GObjectClass *parent_class; - -static FILE *out; - -/* - * - * Query builders - * - */ - -typedef gchar *(*BookQuerySExp) (ESelectNamesCompletion *); -typedef ECompletionMatch *(*BookQueryMatchTester) (ESelectNamesCompletion *, EABDestination *); - -static int -utf8_casefold_collate_len (const gchar *str1, const gchar *str2, int len) -{ - gchar *s1 = g_utf8_casefold(str1, len); - gchar *s2 = g_utf8_casefold(str2, len); - int rv; - - rv = g_utf8_collate (s1, s2); - - g_free (s1); - g_free (s2); - - return rv; -} - -static int -utf8_casefold_collate (const gchar *str1, const gchar *str2) -{ - return utf8_casefold_collate_len (str1, str2, -1); -} - -static void -our_match_destroy (ECompletionMatch *match) -{ - g_object_unref (match->user_data); -} - -static ECompletionMatch * -make_match (EABDestination *dest, const gchar *menu_form, double score) -{ - ECompletionMatch *match; -#if notyet - EContact *contact = eab_destination_get_contact (dest); -#endif - - match = e_completion_match_new (eab_destination_get_name (dest), menu_form, score); - - e_completion_match_set_text (match, eab_destination_get_name (dest), menu_form); - - /* Reject any match that has null text fields. */ - if (! (e_completion_match_get_match_text (match) && e_completion_match_get_menu_text (match))) { - g_object_unref (match); - return NULL; - } - -#if notyet - /* XXX toshok - EContact doesn't have the use_score stuff */ - /* Since we sort low to high, we negate so that larger use scores will come first */ - match->sort_major = contact ? -floor (e_contact_get_use_score (contact)) : 0; -#else - match->sort_major = 0; -#endif - - match->sort_minor = eab_destination_get_email_num (dest); - - match->user_data = dest; - g_object_ref (dest); - - match->destroy = our_match_destroy; - - return match; -} - -/* - * Nickname query - */ - -static gchar * -sexp_nickname (ESelectNamesCompletion *comp) -{ - gchar *query = g_strdup_printf ("(beginswith \"nickname\" \"%s\")", comp->priv->query_text); - - return query; -} - -static ECompletionMatch * -match_nickname (ESelectNamesCompletion *comp, EABDestination *dest) -{ - ECompletionMatch *match = NULL; - gint len; - EContact *contact = eab_destination_get_contact (dest); - double score; - const char *nickname; - - nickname = e_contact_get_const (contact, E_CONTACT_NICKNAME); - if (nickname == NULL) - return NULL; - - len = g_utf8_strlen (comp->priv->query_text, -1); - if (nickname && !utf8_casefold_collate_len (comp->priv->query_text, nickname, len)) { - const gchar *name; - gchar *str; - - score = len * 2; /* nickname gives 2 points per matching character */ - - if (len == g_utf8_strlen (nickname, -1)) /* boost score on an exact match */ - score *= 10; - - name = eab_destination_get_name (dest); - if (name && *name) - str = g_strdup_printf ("'%s' %s <%s>", nickname, name, eab_destination_get_email (dest)); - else - str = g_strdup_printf ("'%s' <%s>", nickname, eab_destination_get_email (dest)); - - match = make_match (dest, str, score); - g_free (str); - } - - return match; -} - -/* - * E-Mail Query - */ - -static gchar * -sexp_email (ESelectNamesCompletion *comp) -{ - return g_strdup_printf ("(beginswith \"email\" \"%s\")", comp->priv->query_text); -} - -static ECompletionMatch * -match_email (ESelectNamesCompletion *comp, EABDestination *dest) -{ - ECompletionMatch *match; - gint len = strlen (comp->priv->query_text); - const gchar *name = eab_destination_get_name (dest); - const gchar *email = eab_destination_get_email (dest); - double score; - - if (email - && !utf8_casefold_collate_len (comp->priv->query_text, email, len) - && !eab_destination_is_evolution_list (dest)) { - - gchar *str; - - score = len * 2; /* 2 points for each matching character */ - - if (name && *name) - str = g_strdup_printf ("<%s> %s", email, name); - else - str = g_strdup (email); - - match = make_match (dest, str, score); - - g_free (str); - - return match; - } - - return NULL; -} - -/* - * Name Query - */ - -static gchar * -name_style_query (ESelectNamesCompletion *comp, const gchar *field) -{ - if (comp && comp->priv->query_text && *comp->priv->query_text) { - gchar *cpy = g_strdup (comp->priv->query_text), *c; - gchar **strv; - gchar *query; - gint i, count=0; - - for (c = cpy; *c; ++c) { - if (*c == ',') - *c = ' '; - } - - strv = g_strsplit (cpy, " ", 0); - for (i=0; strv[i]; ++i) { - gchar *old; - ++count; - g_strstrip (strv[i]); - old = strv[i]; - strv[i] = g_strdup_printf ("(beginswith \"%s\" \"%s\")", field, old); - g_free (old); - } - - if (count == 1) { - query = strv[0]; - strv[0] = NULL; - } else { - gchar *joined = g_strjoinv (" ", strv); - query = g_strdup_printf ("(and %s)", joined); - g_free (joined); - } - - g_free (cpy); - g_strfreev (strv); - - return query; - } - - return NULL; -} - -static gchar * -sexp_name (ESelectNamesCompletion *comp) -{ - return name_style_query (comp, "full_name"); -} - -static ECompletionMatch * -match_name (ESelectNamesCompletion *comp, EABDestination *dest) -{ - ECompletionMatch *final_match = NULL; - gchar *menu_text = NULL; - EContact *contact; - const gchar *email; - gint match_len = 0; - EABContactMatchType match; - EABContactMatchPart first_match; - double score = 0; - gboolean have_given, have_additional, have_family; - EContactName *contact_name; - - contact = eab_destination_get_contact (dest); - - contact_name = e_contact_get (contact, E_CONTACT_NAME); - if (!contact_name) - return NULL; - - email = eab_destination_get_email (dest); - - match = eab_contact_compare_name_to_string_full (contact, comp->priv->query_text, TRUE /* yes, allow partial matches */, - NULL, &first_match, &match_len); - - if (match <= EAB_CONTACT_MATCH_NONE) { - e_contact_name_free (contact_name); - return NULL; - } - - score = match_len * 3; /* three points per match character */ - - have_given = contact_name->given && *contact_name->given; - have_additional = contact_name->additional && *contact_name->additional; - have_family = contact_name->family && *contact_name->family; - - if (e_contact_get (contact, E_CONTACT_IS_LIST)) { - - menu_text = e_contact_name_to_string (contact_name); - - } else if (first_match == EAB_CONTACT_MATCH_PART_GIVEN_NAME) { - - if (have_family) - menu_text = g_strdup_printf ("%s %s <%s>", contact_name->given, contact_name->family, email); - else - menu_text = g_strdup_printf ("%s <%s>", contact_name->given, email); - - } else if (first_match == EAB_CONTACT_MATCH_PART_ADDITIONAL_NAME) { - - if (have_given) { - - menu_text = g_strdup_printf ("%s%s%s, %s <%s>", - contact_name->additional, - have_family ? " " : "", - have_family ? contact_name->family : "", - contact_name->given, - email); - } else { - - menu_text = g_strdup_printf ("%s%s%s <%s>", - contact_name->additional, - have_family ? " " : "", - have_family ? contact_name->family : "", - email); - } - - } else if (first_match == EAB_CONTACT_MATCH_PART_FAMILY_NAME) { - - if (have_given) - menu_text = g_strdup_printf ("%s, %s%s%s <%s>", - contact_name->family, - contact_name->given, - have_additional ? " " : "", - have_additional ? contact_name->additional : "", - email); - else - menu_text = g_strdup_printf ("%s <%s>", contact_name->family, email); - - } else { /* something funny happened */ - - menu_text = g_strdup_printf ("<%s> ???", email); - - } - - if (menu_text) { - g_strstrip (menu_text); - final_match = make_match (dest, menu_text, score); - g_free (menu_text); - } - - e_contact_name_free (contact_name); - - return final_match; -} - -/* - * File As Query - */ - -static gchar * -sexp_file_as (ESelectNamesCompletion *comp) -{ - return name_style_query (comp, "file_as"); -} - -static ECompletionMatch * -match_file_as (ESelectNamesCompletion *comp, EABDestination *dest) -{ - const gchar *name; - const gchar *email; - gchar *cpy, **strv, *menu_text; - gint i, len; - double score = 0.00001; - ECompletionMatch *match; - - name = eab_destination_get_name (dest); - email = eab_destination_get_email (dest); - - if (!(name && *name)) - return NULL; - - cpy = g_strdup (comp->priv->query_text); - strv = g_strsplit (cpy, " ", 0); - - for (i=0; strv[i] && score > 0; ++i) { - len = g_utf8_strlen (strv[i], -1); - if (!utf8_casefold_collate_len (name, strv[i], len)) - score += len; /* one point per character of the match */ - else - score = 0; - } - - g_free (cpy); - g_strfreev (strv); - - if (score <= 0) - return NULL; - - menu_text = g_strdup_printf ("%s <%s>", name, email); - g_strstrip (menu_text); - match = make_match (dest, menu_text, score); - g_free (menu_text); - - return match; -} - -typedef struct _BookQuery BookQuery; -struct _BookQuery { - BookQuerySExp builder; - BookQueryMatchTester tester; -}; - -static BookQuery book_queries[] = { - { sexp_nickname, match_nickname}, - { sexp_email, match_email }, - { sexp_name, match_name }, - { sexp_file_as, match_file_as }, -}; -static gint book_query_count = sizeof (book_queries) / sizeof (BookQuery); - -/* - * Build up a big compound sexp corresponding to all of our queries. - */ -static gchar * -book_query_sexp (ESelectNamesCompletion *comp) -{ - gint i, j; - gchar **queryv, *query; - - g_return_val_if_fail (comp && E_IS_SELECT_NAMES_COMPLETION (comp), NULL); - - if (! (comp->priv->query_text && *comp->priv->query_text)) - return NULL; - - queryv = g_new0 (gchar *, book_query_count+1); - for (i=0, j=0; i<book_query_count; ++i) { - queryv[j] = book_queries[i].builder (comp); - if (queryv[j]) - ++j; - } - - if (j == 0) { - query = NULL; - } else if (j == 1) { - query = queryv[0]; - queryv[0] = NULL; - } else { - gchar *tmp = g_strjoinv (" ", queryv); - query = g_strdup_printf ("(or %s)", tmp); - g_free (tmp); - } - - for (i=0; i<book_query_count; ++i) - g_free (queryv[i]); - g_free (queryv); - - return query; -} - -/* - * Sweep across all of our query rules and find the best score/match - * string that applies to a given destination. - */ -static ECompletionMatch * -book_query_score (ESelectNamesCompletion *comp, EABDestination *dest) -{ - ECompletionMatch *best_match = NULL; - gint i; - - g_return_val_if_fail (E_IS_SELECT_NAMES_COMPLETION (comp), NULL); - g_return_val_if_fail (EAB_IS_DESTINATION (dest), NULL); - - if (! (comp->priv->query_text && *comp->priv->query_text)) - return NULL; - - for (i=0; i<book_query_count; ++i) { - - ECompletionMatch *this_match = NULL; - - if (book_queries[i].tester && eab_destination_get_contact (dest)) { - this_match = book_queries[i].tester (comp, dest); - } - - if (this_match) { - if (best_match == NULL || this_match->score > best_match->score) { - e_completion_match_unref (best_match); - best_match = this_match; - } else { - e_completion_match_unref (this_match); - } - } - } - - return best_match; -} - -static void -book_query_process_card_list (ESelectNamesCompletion *comp, const GList *contacts) -{ - while (contacts) { - EContact *contact = E_CONTACT (contacts->data); - - if (e_contact_get (contact, E_CONTACT_IS_LIST)) { - - if (comp->priv->match_contact_lists) { - - EABDestination *dest = eab_destination_new (); - ECompletionMatch *match; - eab_destination_set_contact (dest, contact, 0); - match = book_query_score (comp, dest); - if (match && match->score > 0) { - e_completion_found_match (E_COMPLETION (comp), match); - } else { - e_completion_match_unref (match); - } - g_object_unref (dest); - - } - - } - else { - GList *email = e_contact_get (contact, E_CONTACT_EMAIL); - if (email) { - GList *iter; - gint i; - for (i=0, iter = email; iter; ++i, iter = iter->next) { - EABDestination *dest = eab_destination_new (); - gchar *e; - ECompletionMatch *match; - - eab_destination_set_contact (dest, contact, i); - e = iter->data; - - if (e && *e) { - - match = book_query_score (comp, dest); - if (match && match->score > 0) { - e_completion_found_match (E_COMPLETION (comp), match); - } else { - e_completion_match_unref (match); - } - } - - g_object_unref (dest); - } - } - g_list_foreach (email, (GFunc)g_free, NULL); - g_list_free (email); - } - - contacts = contacts->next; - } -} - -/* - * - * ESelectNamesCompletion code - * - */ - - -GType -e_select_names_completion_get_type (void) -{ - static GType type = 0; - - if (!type) { - static const GTypeInfo info = { - sizeof (ESelectNamesCompletionClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc) e_select_names_completion_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (ESelectNamesCompletion), - 0, /* n_preallocs */ - (GInstanceInitFunc) e_select_names_completion_init, - }; - - type = g_type_register_static (e_completion_get_type (), "ESelectNamesCompletion", &info, 0); - } - - return type; -} - -static void -e_select_names_completion_class_init (ESelectNamesCompletionClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - ECompletionClass *completion_class = E_COMPLETION_CLASS (klass); - - parent_class = g_type_class_peek_parent (klass); - - object_class->dispose = e_select_names_completion_dispose; - - completion_class->request_completion = e_select_names_completion_handle_request; - completion_class->end_completion = e_select_names_completion_end; - - if (getenv ("EVO_DEBUG_SELECT_NAMES_COMPLETION")) { - out = fopen ("/tmp/evo-debug-select-names-completion", "w"); - if (out) - setvbuf (out, NULL, _IONBF, 0); - } -} - -static void -e_select_names_completion_init (ESelectNamesCompletion *comp) -{ - comp->priv = g_new0 (struct _ESelectNamesCompletionPrivate, 1); - comp->priv->match_contact_lists = TRUE; -} - -static void -e_select_names_completion_clear_book_data (ESelectNamesCompletion *comp) -{ - GList *l; - - for (l = comp->priv->book_data; l; l = l->next) { - ESelectNamesCompletionBookData *book_data = l->data; - - if (book_data->contacts_added_tag) { - g_signal_handler_disconnect (book_data->book_view, book_data->contacts_added_tag); - book_data->contacts_added_tag = 0; - } - - if (book_data->seq_complete_tag) { - g_signal_handler_disconnect (book_data->book_view, book_data->seq_complete_tag); - book_data->seq_complete_tag = 0; - } - - g_object_unref (book_data->book); - - if (book_data->book_view) { - e_book_view_stop (book_data->book_view); - g_object_unref (book_data->book_view); - } - - g_free (book_data->cached_query_text); - g_list_foreach (book_data->cached_cards, (GFunc)g_object_unref, NULL); - g_list_free (book_data->cached_cards); - - g_free (book_data); - } - g_list_free (comp->priv->book_data); - comp->priv->book_data = NULL; -} - -static void -e_select_names_completion_dispose (GObject *object) -{ - ESelectNamesCompletion *comp = E_SELECT_NAMES_COMPLETION (object); - - if (comp->priv) { - if (comp->priv->text_model) - g_object_unref (comp->priv->text_model); - - e_select_names_completion_clear_book_data (comp); - - g_free (comp->priv->waiting_query); - g_free (comp->priv->query_text); - - g_free (comp->priv); - comp->priv = NULL; - } - - if (parent_class->dispose) - parent_class->dispose (object); -} - - -/* - * - * EBook/EBookView Callbacks & Query Stuff - * - */ - -static gchar * -clean_query_text (const gchar *s) -{ - gchar *q = g_new (gchar, strlen(s)+1), *t; - - t = q; - while (*s) { - if (*s != ',' && *s != '"') { - *t = *s; - ++t; - } - ++s; - } - *t = '\0'; - - g_strstrip (q); - - return q; -} - -static void -e_select_names_completion_clear_cache (ESelectNamesCompletionBookData *book_data) -{ - if (out) - fprintf (out, "** clearing cache on book %s\n", e_book_get_uri (book_data->book)); - - g_free (book_data->cached_query_text); - g_list_foreach (book_data->cached_cards, (GFunc)g_object_unref, NULL); - g_list_free (book_data->cached_cards); - - book_data->cached_query_text = NULL; - book_data->cached_cards = NULL; -} - -static void -e_select_names_completion_done (ESelectNamesCompletion *comp) -{ - g_free (comp->priv->query_text); - comp->priv->query_text = NULL; - - e_completion_end_search (E_COMPLETION (comp)); /* That's all folks! */ - - /* Need to launch a new completion if another one is pending. */ - if (comp->priv->waiting_query) { - gchar *s = comp->priv->waiting_query; - comp->priv->waiting_query = NULL; - e_completion_begin_search (E_COMPLETION (comp), s, comp->priv->waiting_pos, comp->priv->waiting_limit); - g_free (s); - } -} - -static void -e_select_names_completion_got_book_view_cb (EBook *book, EBookStatus status, EBookView *view, gpointer user_data) -{ - ESelectNamesCompletion *comp; - ESelectNamesCompletionBookData *book_data; - - book_data = (ESelectNamesCompletionBookData*)user_data; - comp = book_data->comp; - - if (status != E_BOOK_ERROR_OK) { - comp->priv->pending_completion_seq--; - if (!comp->priv->pending_completion_seq) - e_select_names_completion_done (comp); - return; - } - - book_data->book_view_tag = 0; - - if (book_data->contacts_added_tag) { - g_signal_handler_disconnect (book_data->book_view, book_data->contacts_added_tag); - book_data->contacts_added_tag = 0; - } - if (book_data->seq_complete_tag) { - g_signal_handler_disconnect (book_data->book_view, book_data->seq_complete_tag); - book_data->seq_complete_tag = 0; - } - - g_object_ref (view); - if (book_data->book_view) { - e_book_view_stop (book_data->book_view); - g_object_unref (book_data->book_view); - } - book_data->book_view = view; - - book_data->contacts_added_tag = - g_signal_connect (view, - "contacts_added", - G_CALLBACK (e_select_names_completion_contacts_added_cb), - book_data); - - book_data->seq_complete_tag = - g_signal_connect (view, - "sequence_complete", - G_CALLBACK (e_select_names_completion_seq_complete_cb), - book_data); - - e_book_view_start (view); - - book_data->sequence_complete_received = FALSE; -} - -static void -e_select_names_completion_contacts_added_cb (EBookView *book_view, const GList *cards, gpointer user_data) -{ - ESelectNamesCompletionBookData *book_data = user_data; - ESelectNamesCompletion *comp = book_data->comp; - - if (e_completion_searching (E_COMPLETION (comp))) { - book_query_process_card_list (comp, cards); - - /* Save the list of matching cards. */ - while (cards) { - book_data->cached_cards = g_list_prepend (book_data->cached_cards, cards->data); - g_object_ref (cards->data); - cards = g_list_next (cards); - } - } -} - -static void -e_select_names_completion_seq_complete_cb (EBookView *book_view, EBookViewStatus status, gpointer user_data) -{ - ESelectNamesCompletionBookData *book_data = user_data; - ESelectNamesCompletion *comp = book_data->comp; - - if (out) - fprintf (out, "** got sequence_complete (status = %d) on book %s\n", status, e_book_get_uri (book_data->book)); - - /* - * We aren't searching, but the addressbook has changed -- clear our card cache so that - * future completion requests will take the changes into account. - */ - if (! e_completion_searching (E_COMPLETION (comp))) { - if (out) - fprintf (out, "\t we weren't searching, clearing the cache\n"); - e_select_names_completion_clear_cache (book_data); - return; - } - - if (book_data->cached_query_text - && status == E_BOOK_ERROR_OK - && !book_data->cache_complete - && !strcmp (book_data->cached_query_text, comp->priv->query_text)) - book_data->cache_complete = TRUE; - - if (out) - fprintf (out, "\tending search, book_data->cache_complete == %d\n", book_data->cache_complete); - - if (!book_data->sequence_complete_received) { - book_data->sequence_complete_received = TRUE; - - if (book_data->contacts_added_tag) { - g_signal_handler_disconnect (book_data->book_view, book_data->contacts_added_tag); - book_data->contacts_added_tag = 0; - } - if (book_data->seq_complete_tag) { - g_signal_handler_disconnect (book_data->book_view, book_data->seq_complete_tag); - book_data->seq_complete_tag = 0; - } - - if (out) - fprintf (out, "\t %d remaining book view's\n", comp->priv->pending_completion_seq - 1); - - comp->priv->pending_completion_seq --; - if (comp->priv->pending_completion_seq > 0) - return; - } - - e_select_names_completion_done (comp); -} - -static void -e_select_names_completion_stop_query (ESelectNamesCompletion *comp) -{ - GList *l; - - g_return_if_fail (comp && E_IS_SELECT_NAMES_COMPLETION (comp)); - - if (out) - fprintf (out, "stopping query\n"); - - if (comp->priv->waiting_query) { - if (out) - fprintf (out, "stopped waiting query\n"); - g_free (comp->priv->waiting_query); - comp->priv->waiting_query = NULL; - } - - g_free (comp->priv->query_text); - comp->priv->query_text = NULL; - - for (l = comp->priv->book_data; l; l = l->next) { - ESelectNamesCompletionBookData *book_data = l->data; - if (book_data->book_view_tag) { -#if notyet - e_book_cancel (book_data->book, book_data->book_view_tag); -#endif - book_data->book_view_tag = 0; - } - if (book_data->book_view) { - if (book_data->contacts_added_tag) { - g_signal_handler_disconnect (book_data->book_view, book_data->contacts_added_tag); - book_data->contacts_added_tag = 0; - } - if (book_data->seq_complete_tag) { - g_signal_handler_disconnect (book_data->book_view, book_data->seq_complete_tag); - book_data->seq_complete_tag = 0; - } - - e_book_view_stop (book_data->book_view); - g_object_unref (book_data->book_view); - book_data->book_view = NULL; - } - } - - comp->priv->pending_completion_seq = 0; -} - -static void -e_select_names_completion_start_query (ESelectNamesCompletion *comp, const gchar *query_text) -{ - g_return_if_fail (comp && E_IS_SELECT_NAMES_COMPLETION (comp)); - g_return_if_fail (query_text); - - e_select_names_completion_stop_query (comp); /* Stop any prior queries. */ - - if (comp->priv->books_not_ready == 0) { - gchar *sexp; - - if (strlen (query_text) < comp->priv->minimum_query_length) { - e_completion_end_search (E_COMPLETION (comp)); - return; - } - - g_free (comp->priv->query_text); - comp->priv->query_text = g_strdup (query_text); - - sexp = book_query_sexp (comp); - if (sexp && *sexp) { - GList *l; - - if (out) - fprintf (out, "\n\n**** starting query: \"%s\"\n", comp->priv->query_text); - - for (l = comp->priv->book_data; l; l = l->next) { - ESelectNamesCompletionBookData *book_data = l->data; - gboolean can_reuse_cached_cards; - - if (out) { - fprintf (out, - "book == %s[\n" - "\tbook_data->cached_query_text == `%s'\n" - "\tbook_data->cache_complete == %d\n" - "\tbook_data->cached_cards == %p\n", - e_book_get_uri (book_data->book), - book_data->cached_query_text, - book_data->cache_complete, - book_data->cached_cards); - } - - /* for lack of a better place, we invalidate the cache here if we - notice that the text is different. */ - if (book_data->cached_query_text - && (strlen (book_data->cached_query_text) > strlen (query_text) - || utf8_casefold_collate_len (book_data->cached_query_text, query_text, - strlen (book_data->cached_query_text)))) - book_data->cache_complete = FALSE; - - can_reuse_cached_cards = (book_data->cached_query_text - && book_data->cache_complete - && book_data->cached_cards != NULL); - - if (can_reuse_cached_cards) { - - if (out) - fprintf (out, "\t*** can reuse cached cards (%d cards cached)!\n", g_list_length (book_data->cached_cards)); - - if (out) - fprintf (out, "\tusing existing query info: %s (vs %s)\n", query_text, book_data->cached_query_text); - book_query_process_card_list (comp, book_data->cached_cards); - } - else { - e_select_names_completion_clear_cache (book_data); - book_data->cached_query_text = g_strdup (query_text); - - book_data->book_view_tag = e_book_async_get_book_view (book_data->book, - sexp, - e_select_names_completion_got_book_view_cb, book_data); - comp->priv->pending_completion_seq++; - } - - if (out) - fprintf (out, "]\n"); - } - - /* if we looped through all the books - and were able to complete based - solely on our cached cards, signal - that the search is over. */ - if (!comp->priv->pending_completion_seq) - e_select_names_completion_done (E_SELECT_NAMES_COMPLETION (comp)); - } else { - g_free (comp->priv->query_text); - comp->priv->query_text = NULL; - } - g_free (sexp); - - } else { - - comp->priv->waiting_query = g_strdup (query_text); - - } -} - -static void -e_select_names_completion_do_query (ESelectNamesCompletion *comp, const gchar *query_text, gint pos, gint limit) -{ - gchar *clean; - - g_return_if_fail (comp != NULL); - g_return_if_fail (E_IS_SELECT_NAMES_COMPLETION (comp)); - - clean = clean_query_text (query_text); - if (! (clean && *clean)) { - g_free (clean); - e_completion_end_search (E_COMPLETION (comp)); - return; - } - - if (out) - fprintf (out, "do_query: %s => %s\n", query_text, clean); - - e_select_names_completion_start_query (comp, clean); - g_free (clean); -} - - -/* - * - * Completion Search Override - a Framework for Christian-Resurrection-Holiday Edible-Chicken-Ova - * - */ - -typedef struct _SearchOverride SearchOverride; -struct _SearchOverride { - const gchar *trigger; - const gchar *text[4]; -}; -static SearchOverride override[] = { - { "why?", { "\"I must create a system, or be enslaved by another man's.\"", - " -- Wiliam Blake, \"Jerusalem\"", - NULL } }, - { "easter-egg?", { "What were you expecting, a flight simulator?", NULL } }, - { NULL, { NULL } } }; - -static gboolean -search_override_check (SearchOverride *over, const gchar *text) -{ - /* The g_utf8_validate is needed because as of 2001-06-11, - * EText doesn't translate from locale->UTF8 when you paste - * into it. - */ - if (over == NULL || text == NULL || !g_utf8_validate (text, -1, NULL)) - return FALSE; - - return !utf8_casefold_collate (over->trigger, text); -} - - -/* - * - * Completion Callbacks - * - */ - -static void -e_select_names_completion_handle_request (ECompletion *comp, const gchar *text, gint pos, gint limit) -{ - ESelectNamesCompletion *selcomp = E_SELECT_NAMES_COMPLETION (comp); - const gchar *str; - gint index, j; - - g_return_if_fail (comp != NULL); - g_return_if_fail (E_IS_SELECT_NAMES_COMPLETION (comp)); - g_return_if_fail (text != NULL); - - if (out) { - fprintf (out, "\n\n**** requesting completion\n"); - fprintf (out, "text=\"%s\" pos=%d limit=%d\n", text, pos, limit); - } - - e_select_names_model_text_pos (selcomp->priv->text_model->source, - selcomp->priv->text_model->seplen, - pos, &index, NULL, NULL); - str = index >= 0 ? e_select_names_model_get_string (selcomp->priv->text_model->source, index) : NULL; - - if (out) - fprintf (out, "index=%d str=\"%s\"\n", index, str); - - if (str == NULL || *str == '\0') { - if (out) - fprintf (out, "aborting empty query\n"); - e_completion_end_search (comp); - return; - } - - for (j=0; override[j].trigger; ++j) { - if (search_override_check (&(override[j]), str)) { - gint k; - - for (k=0; override[j].text[k]; ++k) { - ECompletionMatch *match = g_new (ECompletionMatch, 1); - e_completion_match_construct (match); - e_completion_match_set_text (match, text, override[j].text[k]); - match->score = 1 / (double) (k + 1); - e_completion_found_match (comp, match); - } - - e_completion_end_search (comp); - return; - } - } - - e_select_names_completion_do_query (selcomp, str, pos, limit); -} - -static void -e_select_names_completion_end (ECompletion *comp) -{ - g_return_if_fail (comp != NULL); - g_return_if_fail (E_IS_COMPLETION (comp)); - - if (out) - fprintf (out, "completion ended\n"); -} - -/* - * - * Our Pseudo-Constructor - * - */ - -ECompletion * -e_select_names_completion_new (ESelectNamesTextModel *text_model) -{ - ESelectNamesCompletion *comp; - - g_return_val_if_fail (E_IS_SELECT_NAMES_TEXT_MODEL (text_model), NULL); - - comp = g_object_new (E_TYPE_SELECT_NAMES_COMPLETION, NULL); - - comp->priv->text_model = text_model; - g_object_ref (text_model); - - return E_COMPLETION (comp); -} - -void -e_select_names_completion_add_book (ESelectNamesCompletion *comp, EBook *book) -{ - ESelectNamesCompletionBookData *book_data; - - g_return_if_fail (book != NULL); - - book_data = g_new0 (ESelectNamesCompletionBookData, 1); - book_data->book = book; - book_data->comp = comp; - g_object_ref (book_data->book); - comp->priv->book_data = g_list_append (comp->priv->book_data, book_data); - - /* XXX toshok - this doesn't work properly. need to rethink this next bit. */ - /* if the user is typing as we're adding books, restart the - query after the new book has been added */ - if (comp->priv->query_text && *comp->priv->query_text) { - char *query_text = g_strdup (comp->priv->query_text); - e_select_names_completion_stop_query (comp); - e_select_names_completion_start_query (comp, query_text); - g_free (query_text); - } -} - -void -e_select_names_completion_clear_books (ESelectNamesCompletion *comp) -{ - e_select_names_completion_stop_query (comp); - e_select_names_completion_clear_book_data (comp); -} - -void -e_select_names_completion_set_minimum_query_length (ESelectNamesCompletion *comp, int query_length) -{ - g_return_if_fail (E_IS_SELECT_NAMES_COMPLETION (comp)); - comp->priv->minimum_query_length = query_length; -} - -gboolean -e_select_names_completion_get_match_contact_lists (ESelectNamesCompletion *comp) -{ - g_return_val_if_fail (E_IS_SELECT_NAMES_COMPLETION (comp), FALSE); - return comp->priv->match_contact_lists; -} - - -void -e_select_names_completion_set_match_contact_lists (ESelectNamesCompletion *comp, gboolean x) -{ - g_return_if_fail (E_IS_SELECT_NAMES_COMPLETION (comp)); - comp->priv->match_contact_lists = x; -} - |