From fd7cce60919fb86549b477a344f54a1c101af434 Mon Sep 17 00:00:00 2001 From: Jon Trowbridge Date: Thu, 16 Aug 2001 19:47:57 +0000 Subject: Added "hit_count" to ECompletionMatch. Used by search 2001-08-16 Jon Trowbridge * gal/e-text/e-completion-match.h: Added "hit_count" to ECompletionMatch. Used by search refinement/unrefinement. * gal/e-text/e-completion.c (e_completion_refine_search): Added. Handle automatic search refinements. (e_completion_unrefine_search): Added. Handle automatic search "unrefinements", or reversions. (e_completion_begin_search): Check if the refinement or unrefinement operations can be used to handle the search. Emit "request_search" at the end of the call. (e_completion_class_init): Added a new signal "request_search". "begin_search" is now purely informational, telling views that a series of matches and an "end_search" are forthcoming. * configure.in: Increment version of 0.10.99.3. svn path=/trunk/; revision=12116 --- widgets/text/e-completion.c | 211 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 204 insertions(+), 7 deletions(-) (limited to 'widgets/text/e-completion.c') diff --git a/widgets/text/e-completion.c b/widgets/text/e-completion.c index af3676e3ce..8c9adb4eba 100644 --- a/widgets/text/e-completion.c +++ b/widgets/text/e-completion.c @@ -32,6 +32,7 @@ #include "e-completion.h" enum { + E_COMPLETION_REQUEST_COMPLETION, E_COMPLETION_BEGIN_COMPLETION, E_COMPLETION_COMPLETION, E_COMPLETION_RESTART_COMPLETION, @@ -46,21 +47,32 @@ static guint e_completion_signals[E_COMPLETION_LAST_SIGNAL] = { 0 }; struct _ECompletionPrivate { gboolean searching; + gboolean done_search; + gboolean refining; gchar *search_text; GPtrArray *matches; + gint match_count; gint pos; gint limit; double min_score, max_score; + gint refinement_count; + GList *search_stack; }; +typedef struct { + gchar *text; + gint pos; +} ECompletionSearch; + static void e_completion_class_init (ECompletionClass *klass); static void e_completion_init (ECompletion *complete); static void e_completion_destroy (GtkObject *object); -static void e_completion_add_match (ECompletion *complete, ECompletionMatch *); -static void e_completion_clear_matches (ECompletion *complete); -static gboolean e_completion_sort (ECompletion *complete); -static void e_completion_restart (ECompletion *complete); +static void e_completion_add_match (ECompletion *complete, ECompletionMatch *); +static void e_completion_clear_search_stack (ECompletion *complete); +static void e_completion_clear_matches (ECompletion *complete); +static gboolean e_completion_sort (ECompletion *complete); +static void e_completion_restart (ECompletion *complete); static GtkObjectClass *parent_class; @@ -95,6 +107,15 @@ e_completion_class_init (ECompletionClass *klass) parent_class = GTK_OBJECT_CLASS (gtk_type_class (gtk_object_get_type ())); + e_completion_signals[E_COMPLETION_REQUEST_COMPLETION] = + gtk_signal_new ("request_completion", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (ECompletionClass, request_completion), + gtk_marshal_NONE__POINTER_INT_INT, + GTK_TYPE_NONE, 3, + GTK_TYPE_POINTER, GTK_TYPE_INT, GTK_TYPE_INT); + e_completion_signals[E_COMPLETION_BEGIN_COMPLETION] = gtk_signal_new ("begin_completion", GTK_RUN_LAST, @@ -174,6 +195,7 @@ e_completion_destroy (GtkObject *object) complete->priv->search_text = NULL; e_completion_clear_matches (complete); + e_completion_clear_search_stack (complete); g_ptr_array_free (complete->priv->matches, TRUE); complete->priv->matches = NULL; @@ -231,32 +253,193 @@ e_completion_clear (ECompletion *complete) g_return_if_fail (E_IS_COMPLETION (complete)); /* FIXME: do we really want _clear and _clear_matches() ? */ + + /* I think yes, because it is convenient to be able to clear our match cache + without emitting a "clear_completion" signal. -JT */ + e_completion_clear_matches (complete); + e_completion_clear_search_stack (complete); + complete->priv->refinement_count = 0; + complete->priv->match_count = 0; gtk_signal_emit (GTK_OBJECT (complete), e_completion_signals[E_COMPLETION_CLEAR_COMPLETION]); } +static void +e_completion_push_search (ECompletion *complete, const gchar *text, gint pos) +{ + ECompletionSearch *search; + + g_return_if_fail (E_IS_COMPLETION (complete)); + + search = g_new (ECompletionSearch, 1); + search->text = complete->priv->search_text; + search->pos = complete->priv->pos; + complete->priv->search_stack = g_list_prepend (complete->priv->search_stack, search); + + complete->priv->search_text = g_strdup (text); + complete->priv->pos = pos; +} + +static void +e_completion_pop_search (ECompletion *complete) +{ + ECompletionSearch *search; + GList *old_link = complete->priv->search_stack; + + g_return_if_fail (E_IS_COMPLETION (complete)); + g_return_if_fail (complete->priv->search_stack != NULL); + + g_free (complete->priv->search_text); + + search = complete->priv->search_stack->data; + complete->priv->search_text = search->text; + complete->priv->pos = search->pos; + + g_free (search); + complete->priv->search_stack = g_list_remove_link (complete->priv->search_stack, + complete->priv->search_stack); + g_list_free_1 (old_link); +} + +static void +e_completion_clear_search_stack (ECompletion *complete) +{ + GList *iter; + + g_return_if_fail (E_IS_COMPLETION (complete)); + + for (iter = complete->priv->search_stack; iter != NULL; iter = g_list_next (iter)) { + ECompletionSearch *search = iter->data; + g_free (search->text); + g_free (search); + } + g_list_free (complete->priv->search_stack); + complete->priv->search_stack = NULL; +} + +static void +e_completion_refine_search (ECompletion *comp, const gchar *text, gint pos, ECompletionRefineFn refine_fn) +{ + GPtrArray *m; + gint i; + + comp->priv->refining = TRUE; + + e_completion_push_search (comp, text, pos); + + gtk_signal_emit (GTK_OBJECT (comp), e_completion_signals[E_COMPLETION_BEGIN_COMPLETION], text, pos, comp->priv->limit); + + comp->priv->match_count = 0; + + comp->priv->searching = TRUE; + + m = comp->priv->matches; + for (i = 0; i < m->len; ++i) { + ECompletionMatch *match = g_ptr_array_index (m, i); + if (comp->priv->refinement_count == match->hit_count + && refine_fn (comp, match, text, pos)) { + ++match->hit_count; + gtk_signal_emit (GTK_OBJECT (comp), e_completion_signals[E_COMPLETION_COMPLETION], match); + ++comp->priv->match_count; + } + } + + ++comp->priv->refinement_count; + + gtk_signal_emit (GTK_OBJECT (comp), e_completion_signals[E_COMPLETION_END_COMPLETION]); + + comp->priv->searching = FALSE; + comp->priv->refining = FALSE; +} + +static void +e_completion_unrefine_search (ECompletion *comp) +{ + GPtrArray *m; + gint i; + + comp->priv->refining = TRUE; + + e_completion_pop_search (comp); + + gtk_signal_emit (GTK_OBJECT (comp), e_completion_signals[E_COMPLETION_BEGIN_COMPLETION], comp->priv->search_text, comp->priv->pos, comp->priv->limit); + + comp->priv->match_count = 0; + --comp->priv->refinement_count; + + comp->priv->searching = TRUE; + + m = comp->priv->matches; + for (i = 0; i < m->len; ++i) { + ECompletionMatch *match = g_ptr_array_index (m, i); + if (comp->priv->refinement_count <= match->hit_count) { + match->hit_count = comp->priv->refinement_count; + gtk_signal_emit (GTK_OBJECT (comp), e_completion_signals[E_COMPLETION_COMPLETION], match); + ++comp->priv->match_count; + } + } + + gtk_signal_emit (GTK_OBJECT (comp), e_completion_signals[E_COMPLETION_END_COMPLETION]); + + comp->priv->searching = FALSE; + comp->priv->refining = FALSE; +} + void e_completion_begin_search (ECompletion *complete, const gchar *text, gint pos, gint limit) { + ECompletionClass *klass; + ECompletionRefineFn refine_fn; + g_return_if_fail (complete != NULL); g_return_if_fail (E_IS_COMPLETION (complete)); g_return_if_fail (text != NULL); + klass = E_COMPLETION_CLASS (GTK_OBJECT (complete)->klass); + + if (!complete->priv->searching && complete->priv->done_search) { + + /* If the search we are requesting is the same as what we had before our last refinement, + treat the request as an unrefine. */ + if (complete->priv->search_stack != NULL) { + ECompletionSearch *search = complete->priv->search_stack->data; + if ((klass->ignore_pos_on_auto_unrefine || search->pos == pos) + && !strcmp (search->text, text)) { + e_completion_unrefine_search (complete); + return; + } + } + + if (klass->auto_refine + && (refine_fn = klass->auto_refine (complete, + complete->priv->search_text, complete->priv->pos, + text, pos))) { + e_completion_refine_search (complete, text, pos, refine_fn); + return; + } + + } + /* Stop any prior search. */ if (complete->priv->searching) e_completion_cancel_search (complete); + e_completion_clear_search_stack (complete); + g_free (complete->priv->search_text); complete->priv->search_text = g_strdup (text); complete->priv->pos = pos; complete->priv->searching = TRUE; + complete->priv->done_search = FALSE; e_completion_clear_matches (complete); complete->priv->limit = limit > 0 ? limit : G_MAXINT; + complete->priv->refinement_count = 0; gtk_signal_emit (GTK_OBJECT (complete), e_completion_signals[E_COMPLETION_BEGIN_COMPLETION], text, pos, limit); + gtk_signal_emit (GTK_OBJECT (complete), e_completion_signals[E_COMPLETION_REQUEST_COMPLETION], text, pos, limit); } void @@ -283,6 +466,15 @@ e_completion_searching (ECompletion *complete) return complete->priv->searching; } +gboolean +e_completion_refining (ECompletion *complete) +{ + g_return_val_if_fail (complete != NULL, FALSE); + g_return_val_if_fail (E_IS_COMPLETION (complete), FALSE); + + return complete->priv->refining; +} + const gchar * e_completion_search_text (ECompletion *complete) { @@ -307,7 +499,7 @@ e_completion_match_count (ECompletion *complete) g_return_val_if_fail (complete != NULL, 0); g_return_val_if_fail (E_IS_COMPLETION (complete), 0); - return complete->priv->matches->len; + return complete->priv->refinement_count > 0 ? complete->priv->match_count : complete->priv->matches->len; } void @@ -323,8 +515,12 @@ e_completion_foreach_match (ECompletion *complete, ECompletionMatchFn fn, gpoint return; m = complete->priv->matches; - for (i = 0; i < m->len; i++) - fn (g_ptr_array_index (m, i), closure); + for (i = 0; i < m->len; i++) { + ECompletionMatch *match = g_ptr_array_index (m, i); + if (match->hit_count == complete->priv->refinement_count) { + fn (match, closure); + } + } } ECompletion * @@ -445,5 +641,6 @@ e_completion_end_search (ECompletion *complete) gtk_signal_emit (GTK_OBJECT (complete), e_completion_signals[E_COMPLETION_END_COMPLETION]); complete->priv->searching = FALSE; + complete->priv->done_search = TRUE; } -- cgit v1.2.3