From 7b226f961c3340d85cff72b2b4485677ddfddb1d Mon Sep 17 00:00:00 2001 From: Jon Trowbridge Date: Tue, 5 Jun 2001 17:53:04 +0000 Subject: Change the completion handler to use the ECompletionMatch. 2001-06-05 Jon Trowbridge * gui/component/select-names/e-select-names-manager.c (completion_handler): Change the completion handler to use the ECompletionMatch. * gui/component/select-names/e-select-names-completion.c General changes to convert for ECompletionMatch use. (emailify_match): Use extra sort keys in ECompletionMatch to let us ensure that the primary email address is always the first option, the secondary comes second, etc. There was no nice way to do this previously. (match_name): Removed code that adjusted score based on similarities between the "real name" and the e-mail address. It seemed like a good idea at the time, but produced unexpected and confusing results. svn path=/trunk/; revision=10120 --- addressbook/ChangeLog | 17 ++ .../select-names/e-select-names-completion.c | 295 ++++++++++----------- .../select-names/e-select-names-manager.c | 7 +- 3 files changed, 163 insertions(+), 156 deletions(-) (limited to 'addressbook') diff --git a/addressbook/ChangeLog b/addressbook/ChangeLog index 00816b50b8..1ecae91348 100644 --- a/addressbook/ChangeLog +++ b/addressbook/ChangeLog @@ -1,3 +1,20 @@ +2001-06-05 Jon Trowbridge + + * gui/component/select-names/e-select-names-manager.c + (completion_handler): Change the completion handler to use the + ECompletionMatch. + + * gui/component/select-names/e-select-names-completion.c + General changes to convert for ECompletionMatch use. + (emailify_match): Use extra sort keys in ECompletionMatch to let + us ensure that the primary email address is always the first + option, the secondary comes second, etc. There was no nice way to + do this previously. + (match_name): Removed code that adjusted score based on + similarities between the "real name" and the e-mail address. It + seemed like a good idea at the time, but produced unexpected and + confusing results. + 2001-06-04 Jon Trowbridge * backend/ebook/e-card-compare.c: Added. Code for testing diff --git a/addressbook/gui/component/select-names/e-select-names-completion.c b/addressbook/gui/component/select-names/e-select-names-completion.c index dbe54e8a6b..8639ca5871 100644 --- a/addressbook/gui/component/select-names/e-select-names-completion.c +++ b/addressbook/gui/component/select-names/e-select-names-completion.c @@ -87,86 +87,88 @@ static FILE *out; */ typedef gchar *(*BookQuerySExp) (ESelectNamesCompletion *); -typedef gchar *(*BookQueryMatchTester) (ESelectNamesCompletion *, EDestination *, double *score); +typedef ECompletionMatch *(*BookQueryMatchTester) (ESelectNamesCompletion *, EDestination *); -/* - * Nickname query - */ - -static gchar * -sexp_nickname (ESelectNamesCompletion *comp) +static void +our_match_destroy (ECompletionMatch *match) { - return g_strdup_printf ("(beginswith \"nickname\" \"%s\")", comp->priv->query_text); - + gtk_object_unref (GTK_OBJECT (match->user_data)); } -static gint -e_utf8_strncasecmp (const gchar *p, const gchar *q, gint len) +static ECompletionMatch * +make_match (EDestination *dest, const gchar *menu_form, double score) { - if (p == NULL || q == NULL) { - if (p) return +1; - if (q) return -1; - return 0; - } + ECompletionMatch *match = g_new0 (ECompletionMatch, 1); + e_completion_match_construct (match); - if (len < 0) - len = G_MAXINT; - - while (*p && *q && len > 0) { - gunichar cp = g_utf8_get_char (p); - gunichar cq = g_utf8_get_char (q); + e_completion_match_set_text (match, e_destination_get_name (dest), menu_form); + match->score = score; + match->sort_minor = e_destination_get_email_num (dest); - if (!(g_unichar_validate (cp) - && g_unichar_validate (cq))) - break; + match->user_data = dest; + gtk_object_ref (GTK_OBJECT (dest)); + + match->destroy = our_match_destroy; - cp = g_unichar_tolower (cp); - cq = g_unichar_tolower (cq); + return match; +} - if (cp != cq) - return (cp < cq) - (cp > cq); +static void +emailify_match (ECompletionMatch *match) +{ + EDestination *dest = E_DESTINATION (match->user_data); + ECard *card = e_destination_get_card (dest); + const gchar *email = e_destination_get_email (dest); + const gchar *menu_txt = e_completion_match_get_menu_text (match); + + if (card && card->email && e_list_length (card->email) > 1) { - p = g_utf8_next_char (p); - q = g_utf8_next_char (q); - --len; - } + if (email && strstr (menu_txt, email) == NULL) { + gchar *tmp = g_strdup_printf ("%s <%s>", menu_txt, email); + e_completion_match_set_text (match, + e_completion_match_get_match_text (match), + tmp); + g_free (tmp); + } - if (len) { - if (*p) - return +1; - else if (*q) - return -1; + match->sort_minor = e_destination_get_email_num (dest); } - - return 0; } -static gint -e_utf8_strcasecmp (const gchar *p, const gchar *q) +/* + * Nickname query + */ + +static gchar * +sexp_nickname (ESelectNamesCompletion *comp) { - return e_utf8_strncasecmp (p, q, -1); -} + return g_strdup_printf ("(beginswith \"nickname\" \"%s\")", comp->priv->query_text); +} -static gchar * -match_nickname (ESelectNamesCompletion *comp, EDestination *dest, double *score) +static ECompletionMatch * +match_nickname (ESelectNamesCompletion *comp, EDestination *dest) { + ECompletionMatch *match = NULL; gint len = strlen (comp->priv->query_text); ECard *card = e_destination_get_card (dest); + double score; if (card->nickname - && !e_utf8_strncasecmp (comp->priv->query_text, card->nickname, len)) { + && !g_utf8_strncasecmp (comp->priv->query_text, card->nickname, len)) { + ECompletionMatch *match = g_new0 (ECompletionMatch, 1); gchar *name = e_card_name_to_string (card->name); gchar *str; - *score = len * 10; /* nickname gives 10 points per matching character */ - + score = len * 10; /* nickname gives 10 points per matching character */ str = g_strdup_printf ("(%s) %s", card->nickname, name); + + match = make_match (dest, str, score); g_free (name); - return str; + g_free (str); } - return NULL; + return match; } /* @@ -179,23 +181,33 @@ sexp_email (ESelectNamesCompletion *comp) return g_strdup_printf ("(beginswith \"email\" \"%s\")", comp->priv->query_text); } -static gchar * -match_email (ESelectNamesCompletion *comp, EDestination *dest, double *score) +static ECompletionMatch * +match_email (ESelectNamesCompletion *comp, EDestination *dest) { + ECompletionMatch *match; gint len = strlen (comp->priv->query_text); ECard *card = e_destination_get_card (dest); const gchar *email = e_destination_get_email (dest); + double score; - if (email && !e_utf8_strncasecmp (comp->priv->query_text, email, len)) { + if (email && !g_utf8_strncasecmp (comp->priv->query_text, email, len)) { + gchar *name, *str; - *score = len * 2; /* 2 points for each matching character */ + + score = len * 2; /* 2 points for each matching character */ + name = e_card_name_to_string (card->name); if (name && *name) str = g_strdup_printf ("<%s> %s", email, name); else str = g_strdup (email); + + match = make_match (dest, str, score); + g_free (name); - return str; + g_free (str); + + return match; } return NULL; @@ -235,6 +247,7 @@ sexp_name (ESelectNamesCompletion *comp) g_free (cpy); g_free (strv); + return query; } @@ -258,7 +271,7 @@ match_name_fragment (const gchar *fragment, const gchar *txt) gint len = strlen (txt); while (*fragment) { - if (!e_utf8_strncasecmp (fragment, txt, len)) + if (!g_utf8_strncasecmp (fragment, txt, len)) return TRUE; while (*fragment && !isspace ((gint) *fragment)) @@ -270,14 +283,17 @@ match_name_fragment (const gchar *fragment, const gchar *txt) return FALSE; } -static gchar * -match_name (ESelectNamesCompletion *comp, EDestination *dest, double *score) +static ECompletionMatch * +match_name (ESelectNamesCompletion *comp, EDestination *dest) { + ECompletionMatch *final_match = NULL; + gchar *menu_text = NULL; ECard *card; gchar *cpy, **strv; const gchar *email; gint len, i, match_len = 0; gint match = 0, first_match = 0; + double score = 0; gboolean have_given, have_additional, have_family; card = e_destination_get_card (dest); @@ -330,28 +346,31 @@ match_name (ESelectNamesCompletion *comp, EDestination *dest, double *score) } - *score = match_len * 3; /* three points per match character */ + score = match_len * 3; /* three points per match character */ if (card->nickname) { /* We massively boost the score if the nickname exists and is the same as one of the "real" names. This keeps the nickname from matching ahead of the real name for this card. */ len = strlen (card->nickname); - if ((card->name->given && !e_utf8_strncasecmp (card->name->given, card->nickname, MIN (strlen (card->name->given), len))) - || (card->name->family && !e_utf8_strncasecmp (card->name->family, card->nickname, MIN (strlen (card->name->family), len))) - || (card->name->additional && !e_utf8_strncasecmp (card->name->additional, card->nickname, MIN (strlen (card->name->additional), len)))) - *score *= 100; + if ((card->name->given && !g_utf8_strncasecmp (card->name->given, card->nickname, MIN (strlen (card->name->given), len))) + || (card->name->family && !g_utf8_strncasecmp (card->name->family, card->nickname, MIN (strlen (card->name->family), len))) + || (card->name->additional && !g_utf8_strncasecmp (card->name->additional, card->nickname, MIN (strlen (card->name->additional), len)))) + score *= 100; } +#if 0 + /* This leads to some pretty counter-intuitive results, so I'm disabling it. */ email = e_destination_get_email (dest); if (email) { /* Do the same for the email address. */ gchar *at = strchr (email, '@'); len = at ? at-email : strlen (email); - if ((card->name->given && !e_utf8_strncasecmp (card->name->given, email, MIN (strlen (card->name->given), len))) - || (card->name->family && !e_utf8_strncasecmp (card->name->family, email, MIN (strlen (card->name->family), len))) - || (card->name->additional && !e_utf8_strncasecmp (card->name->additional, email, MIN (strlen (card->name->additional), len)))) - *score *= 100; + if ((card->name->given && !g_utf8_strncasecmp (card->name->given, email, MIN (strlen (card->name->given), len))) + || (card->name->family && !g_utf8_strncasecmp (card->name->family, email, MIN (strlen (card->name->family), len))) + || (card->name->additional && !g_utf8_strncasecmp (card->name->additional, email, MIN (strlen (card->name->additional), len)))) + score *= 100; } +#endif have_given = card->name->given && *card->name->given; have_additional = card->name->additional && *card->name->additional; @@ -360,41 +379,46 @@ match_name (ESelectNamesCompletion *comp, EDestination *dest, double *score) if (first_match == MATCHED_GIVEN_NAME) { if (have_family) - return g_strdup_printf ("%s %s", card->name->given, card->name->family); + menu_text = g_strdup_printf ("%s %s", card->name->given, card->name->family); else - return g_strdup_printf (card->name->given); + menu_text = g_strdup_printf (card->name->given); } else if (first_match == MATCHED_ADDITIONAL_NAME) { if (have_family) { - return g_strdup_printf ("%s, %s%s%s", - card->name->family, - have_given ? card->name->given : "", - have_given ? " " : "", - card->name->additional); + menu_text = g_strdup_printf ("%s, %s%s%s", + card->name->family, + have_given ? card->name->given : "", + have_given ? " " : "", + card->name->additional); } else { - return g_strdup_printf ("%s%s%s", - have_given ? card->name->given : "", - have_given ? " " : "", - card->name->additional); + menu_text = g_strdup_printf ("%s%s%s", + have_given ? card->name->given : "", + have_given ? " " : "", + card->name->additional); } } else if (first_match == MATCHED_FAMILY_NAME) { if (have_given) - return g_strdup_printf ("%s, %s %s", - card->name->family, - card->name->given, - have_additional ? card->name->additional : ""); + menu_text = g_strdup_printf ("%s, %s %s", + card->name->family, + card->name->given, + have_additional ? card->name->additional : ""); else - return g_strdup_printf (card->name->family); + menu_text = g_strdup_printf (card->name->family); + } + + if (menu_text) { + final_match = make_match (dest, menu_text, score); + g_free (menu_text); } - return NULL; + return final_match; } /* @@ -407,8 +431,8 @@ sexp_initials (ESelectNamesCompletion *comp) return NULL; } -static gchar * -match_initials (ESelectNamesCompletion *comp, EDestination *dest, double *score) +static ECompletionMatch * +match_initials (ESelectNamesCompletion *comp, EDestination *dest) { return NULL; } @@ -480,72 +504,38 @@ book_query_sexp (ESelectNamesCompletion *comp) * Sweep across all of our query rules and find the best score/match * string that applies to a given destination. */ -static gchar * -book_query_score (ESelectNamesCompletion *comp, EDestination *dest, double *score) +static ECompletionMatch * +book_query_score (ESelectNamesCompletion *comp, EDestination *dest) { - double best_score = -1; - gchar *best_string = NULL; + ECompletionMatch *best_match = NULL; gint i; - g_return_val_if_fail (score, NULL); - *score = -1; - g_return_val_if_fail (comp && E_IS_SELECT_NAMES_COMPLETION (comp), NULL); g_return_val_if_fail (dest && E_IS_DESTINATION (dest), NULL); for (i=0; ipriv->primary_only) { if (book_queries[i].tester && e_destination_get_card (dest)) - this_string = book_queries[i].tester (comp, dest, &this_score); - if (this_string) { - if (this_score > best_score) { - g_free (best_string); - best_string = this_string; - best_score = this_score; + 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 { - g_free (this_string); + e_completion_match_unref (this_match); } } } } - /* If this destination corresponds to a card w/ multiple addresses, and if the - address isn't already in the string, append it. */ - if (best_string) { - ECard *card = e_destination_get_card (dest); - if (e_list_length (card->email) > 1) { - ECardSimple *simp; - const gchar *email = e_destination_get_email (dest); - const gchar *simp_email; - - if (email && strstr (best_string, email) == NULL) { - gchar *tmp = g_strdup_printf ("%s <%s>", best_string, email); - g_free (best_string); - best_string = tmp; - } + if (best_match) + emailify_match (best_match); - /* Give a small bonus to the primary/secondary e-mail address, so that they will - always come in the correct order in the listing. */ - if (email) { - simp = e_card_simple_new (card); - simp_email = e_card_simple_get_email (simp, E_CARD_SIMPLE_EMAIL_ID_EMAIL); - if (simp_email && !e_utf8_strcasecmp (simp_email, email)) { - best_score += 0.2; - } - simp_email = e_card_simple_get_email (simp, E_CARD_SIMPLE_EMAIL_ID_EMAIL_2); - if (simp_email && !e_utf8_strcasecmp (simp_email, email)) { - best_score += 0.1; - } - gtk_object_unref (GTK_OBJECT (simp)); - } - } - } - - *score = best_score; - return best_string; + return best_match; } static void @@ -559,24 +549,20 @@ book_query_process_card_list (ESelectNamesCompletion *comp, const GList *cards) for (i=0; iemail); ++i) { EDestination *dest = e_destination_new (); const gchar *email; - gchar *match_text; - double score = -1; + ECompletionMatch *match; e_destination_set_card (dest, card, i); email = e_destination_get_email (dest); if (email && *email) { - match_text = book_query_score (comp, dest, &score); - if (match_text && score > 0) { - - e_completion_found_match_full (E_COMPLETION (comp), match_text, score, dest, - (GtkDestroyNotify) gtk_object_unref); + match = book_query_score (comp, dest); + if (match && match->score > 0) { + e_completion_found_match (E_COMPLETION (comp), match); } else { - gtk_object_unref (GTK_OBJECT (dest)); + e_completion_match_unref (match); } - g_free (match_text); - } else { + gtk_object_unref (GTK_OBJECT (dest)); } } @@ -956,7 +942,7 @@ e_select_names_completion_do_query (ESelectNamesCompletion *comp, const gchar *q can_reuse_cached_cards = (comp->priv->cached_query_text && (strlen (comp->priv->cached_query_text) <= strlen (clean)) - && !e_utf8_strncasecmp (comp->priv->cached_query_text, clean, strlen (comp->priv->cached_query_text))); + && !g_utf8_strncasecmp (comp->priv->cached_query_text, clean, strlen (comp->priv->cached_query_text))); if (can_reuse_cached_cards) { @@ -1012,7 +998,7 @@ search_override_check (SearchOverride *over, const gchar *text) if (over == NULL || text == NULL) return FALSE; - return !e_utf8_strcasecmp (over->trigger, text); + return !g_utf8_strcasecmp (over->trigger, text); } @@ -1055,11 +1041,14 @@ e_select_names_completion_begin (ECompletion *comp, const gchar *text, gint pos, if (search_override_check (&(override[j]), str)) { gint k; - for (k=0; override[j].text[k]; ++k) - e_completion_found_match (comp, override[j].text[k]); - - if (out) - fprintf (out, "aborting on override \"%s\"\n", override[j].trigger); + 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; + e_completion_found_match (comp, match); + } + e_completion_end_search (comp); return; } diff --git a/addressbook/gui/component/select-names/e-select-names-manager.c b/addressbook/gui/component/select-names/e-select-names-manager.c index 6c06624918..9361cfa836 100644 --- a/addressbook/gui/component/select-names/e-select-names-manager.c +++ b/addressbook/gui/component/select-names/e-select-names-manager.c @@ -267,17 +267,18 @@ entry_destroyed(EEntry *entry, ESelectNamesManager *manager) } static void -completion_handler (EEntry *entry, const gchar *text, gpointer user_data) +completion_handler (EEntry *entry, ECompletionMatch *match) { ESelectNamesModel *snm; EDestination *dest; gint i, pos, start_pos, len; - if (user_data == NULL) + if (match == NULL || match->user_data == NULL) return; + snm = E_SELECT_NAMES_MODEL (gtk_object_get_data (GTK_OBJECT (entry), "select_names_model")); - dest = E_DESTINATION (user_data); + dest = E_DESTINATION (match->user_data); /* Sometimes I really long for garbage collection. Reference counting makes you feel 31337, but sometimes it is just a -- cgit