diff options
Diffstat (limited to 'widgets/text/e-completion.c')
-rw-r--r-- | widgets/text/e-completion.c | 478 |
1 files changed, 0 insertions, 478 deletions
diff --git a/widgets/text/e-completion.c b/widgets/text/e-completion.c deleted file mode 100644 index a8038b8184..0000000000 --- a/widgets/text/e-completion.c +++ /dev/null @@ -1,478 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ - -/* ECompletion - A base class for text completion. - * Copyright (C) 2000, 2001 Ximian, Inc. - * - * Author: Miguel de Icaza <miguel@ximian.com> - * Adapted by Jon Trowbridge <trow@ximian.com> - * - */ - -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * 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 <string.h> /* strcmp() */ -#include <gtk/gtk.h> -#include "e-completion.h" - -enum { - E_COMPLETION_BEGIN_COMPLETION, - E_COMPLETION_COMPLETION, - E_COMPLETION_RESTART_COMPLETION, - E_COMPLETION_CANCEL_COMPLETION, - E_COMPLETION_END_COMPLETION, - E_COMPLETION_LAST_SIGNAL -}; - -static guint e_completion_signals[E_COMPLETION_LAST_SIGNAL] = { 0 }; - -typedef struct _Match Match; -struct _Match { - gchar *text; - double score; - gpointer extra_data; - GtkDestroyNotify extra_destroy; -}; - -struct _ECompletionPrivate { - gboolean searching; - gchar *search_text; - gint pos; - gint limit; - gint match_count; - GList *matches; - double min_score, max_score; -}; - -static void e_completion_class_init (ECompletionClass *klass); -static void e_completion_init (ECompletion *complete); -static void e_completion_destroy (GtkObject *object); - -static Match *match_new (const gchar *txt, double score, gpointer extra_data, GtkDestroyNotify extra_destroy); -static void match_free (Match *); -static void match_list_free (GList *); - -static void e_completion_add_match (ECompletion *complete, const gchar *txt, double score, gpointer extra_data, GtkDestroyNotify); -static void e_completion_clear_matches (ECompletion *complete); -static gboolean e_completion_sort_by_score (ECompletion *complete); -static void e_completion_restart (ECompletion *complete); - -static GtkObjectClass *parent_class; - - - -GtkType -e_completion_get_type (void) -{ - static GtkType complete_type = 0; - - if (!complete_type) { - GtkTypeInfo complete_info = { - "ECompletion", - sizeof (ECompletion), - sizeof (ECompletionClass), - (GtkClassInitFunc) e_completion_class_init, - (GtkObjectInitFunc) e_completion_init, - NULL, NULL, /* reserved */ - (GtkClassInitFunc) NULL - }; - - complete_type = gtk_type_unique (gtk_object_get_type (), &complete_info); - } - - return complete_type; -} - -static void -e_completion_class_init (ECompletionClass *klass) -{ - GtkObjectClass *object_class = (GtkObjectClass *) klass; - - parent_class = GTK_OBJECT_CLASS (gtk_type_class (gtk_object_get_type ())); - - e_completion_signals[E_COMPLETION_BEGIN_COMPLETION] = - gtk_signal_new ("begin_completion", - GTK_RUN_LAST, - object_class->type, - GTK_SIGNAL_OFFSET (ECompletionClass, begin_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_COMPLETION] = - gtk_signal_new ("completion", - GTK_RUN_LAST, - object_class->type, - GTK_SIGNAL_OFFSET (ECompletionClass, completion), - gtk_marshal_NONE__POINTER_POINTER, - GTK_TYPE_NONE, 2, - GTK_TYPE_POINTER, GTK_TYPE_POINTER); - - e_completion_signals[E_COMPLETION_RESTART_COMPLETION] = - gtk_signal_new ("restart_completion", - GTK_RUN_LAST, - object_class->type, - GTK_SIGNAL_OFFSET (ECompletionClass, restart_completion), - gtk_marshal_NONE__NONE, - GTK_TYPE_NONE, 0); - - e_completion_signals[E_COMPLETION_CANCEL_COMPLETION] = - gtk_signal_new ("cancel_completion", - GTK_RUN_LAST, - object_class->type, - GTK_SIGNAL_OFFSET (ECompletionClass, cancel_completion), - gtk_marshal_NONE__NONE, - GTK_TYPE_NONE, 0); - - e_completion_signals[E_COMPLETION_END_COMPLETION] = - gtk_signal_new ("end_completion", - GTK_RUN_LAST, - object_class->type, - GTK_SIGNAL_OFFSET (ECompletionClass, end_completion), - gtk_marshal_NONE__NONE, - GTK_TYPE_NONE, 0); - - gtk_object_class_add_signals (object_class, e_completion_signals, E_COMPLETION_LAST_SIGNAL); - - object_class->destroy = e_completion_destroy; -} - -static void -e_completion_init (ECompletion *complete) -{ - complete->priv = g_new0 (struct _ECompletionPrivate, 1); -} - -static void -e_completion_destroy (GtkObject *object) -{ - ECompletion *complete = E_COMPLETION (object); - - g_free (complete->priv->search_text); - complete->priv->search_text = NULL; - - e_completion_clear_matches (complete); - - g_free (complete->priv); - complete->priv = NULL; - - if (parent_class->destroy) - (parent_class->destroy) (object); -} - -static Match * -match_new (const gchar *text, double score, gpointer extra_data, GtkDestroyNotify extra_destroy) -{ - Match *m; - - if (text == NULL) - return NULL; - - m = g_new (Match, 1); - m->text = g_strdup (text); - m->score = score; - m->extra_data = extra_data; - m->extra_destroy = extra_destroy; - - return m; -} - -static void -match_free (Match *m) -{ - if (m) { - g_free (m->text); - if (m->extra_destroy) - m->extra_destroy (m->extra_data); - g_free (m); - } -} - -static void -match_list_free (GList *i) -{ - while (i) { - match_free ( (Match *) i->data ); - i = g_list_next (i); - } -} - -static void -e_completion_add_match (ECompletion *complete, const gchar *txt, double score, gpointer extra_data, GtkDestroyNotify extra_destroy) -{ - complete->priv->matches = g_list_append (complete->priv->matches, match_new (txt, score, extra_data, extra_destroy)); - - if (complete->priv->match_count == 0) { - - complete->priv->min_score = complete->priv->max_score = score; - - } else { - - complete->priv->min_score = MIN (complete->priv->min_score, score); - complete->priv->max_score = MAX (complete->priv->max_score, score); - - } - - ++complete->priv->match_count; -} - -static void -e_completion_clear_matches (ECompletion *complete) -{ - match_list_free (complete->priv->matches); - g_list_free (complete->priv->matches); - complete->priv->matches = NULL; - - complete->priv->match_count = 0; - - complete->priv->min_score = 0; - complete->priv->max_score = 0; -} - -void -e_completion_begin_search (ECompletion *complete, const gchar *text, gint pos, gint limit) -{ - g_return_if_fail (complete != NULL); - g_return_if_fail (E_IS_COMPLETION (complete)); - g_return_if_fail (text != NULL); - - /* Stop any prior search. */ - if (complete->priv->searching) - e_completion_cancel_search (complete); - - g_free (complete->priv->search_text); - complete->priv->search_text = g_strdup (text); - - complete->priv->pos = pos; - complete->priv->searching = TRUE; - - e_completion_clear_matches (complete); - - complete->priv->limit = limit > 0 ? limit : G_MAXINT; - - gtk_signal_emit (GTK_OBJECT (complete), e_completion_signals[E_COMPLETION_BEGIN_COMPLETION], text, pos, limit); -} - -void -e_completion_cancel_search (ECompletion *complete) -{ - g_return_if_fail (complete != NULL); - g_return_if_fail (E_IS_COMPLETION (complete)); - - /* If there is no search to cancel, just silently return. */ - if (!complete->priv->searching) - return; - - gtk_signal_emit (GTK_OBJECT (complete), e_completion_signals[E_COMPLETION_CANCEL_COMPLETION]); - - complete->priv->searching = FALSE; -} - -gboolean -e_completion_searching (ECompletion *complete) -{ - g_return_val_if_fail (complete != NULL, FALSE); - g_return_val_if_fail (E_IS_COMPLETION (complete), FALSE); - - return complete->priv->searching; -} - -const gchar * -e_completion_search_text (ECompletion *complete) -{ - g_return_val_if_fail (complete != NULL, NULL); - g_return_val_if_fail (E_IS_COMPLETION (complete), NULL); - - return complete->priv->search_text; -} - -gint -e_completion_search_text_pos (ECompletion *complete) -{ - g_return_val_if_fail (complete != NULL, -1); - g_return_val_if_fail (E_IS_COMPLETION (complete), -1); - - return complete->priv->pos; -} - -gint -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->match_count; -} - -void -e_completion_foreach_match (ECompletion *complete, ECompletionMatchFn fn, gpointer user_data) -{ - GList *i; - - g_return_if_fail (complete != NULL); - g_return_if_fail (E_IS_COMPLETION (complete)); - - if (fn == NULL) - return; - - for (i = complete->priv->matches; i != NULL; i = g_list_next (i)) { - Match *m = (Match *) i->data; - fn (m->text, m->score, m->extra_data, user_data); - } -} - -gpointer -e_completion_find_extra_data (ECompletion *complete, const gchar *text) -{ - GList *i; - - g_return_val_if_fail (complete != NULL, NULL); - g_return_val_if_fail (E_IS_COMPLETION (complete), NULL); - - for (i = complete->priv->matches; i != NULL; i = g_list_next (i)) { - Match *m = (Match *) i->data; - if (strcmp (m->text, text) == 0) - return m->extra_data; - } - - return NULL; -} - -ECompletion * -e_completion_new (void) -{ - return E_COMPLETION (gtk_type_new (e_completion_get_type ())); -} - -static gint -score_cmp_fn (gconstpointer a, gconstpointer b) -{ - double sa = ((const Match *) a)->score; - double sb = ((const Match *) b)->score; - gint cmp = (sa < sb) - (sb < sa); - if (cmp == 0) - cmp = g_strcasecmp (((const Match *) a)->text, ((const Match *) b)->text); - return cmp; -} - -static gboolean -e_completion_sort_by_score (ECompletion *complete) -{ - GList *sort_list = NULL, *i, *j; - gboolean diff; - gint count; - - /* If all scores are equal, there is nothing to do. */ - if (complete->priv->min_score == complete->priv->max_score) - return FALSE; - - for (i = complete->priv->matches; i != NULL; i = g_list_next (i)) { - sort_list = g_list_append (sort_list, i->data); - } - - sort_list = g_list_sort (sort_list, score_cmp_fn); - - - diff = FALSE; - count = 0; - i = complete->priv->matches; - j = sort_list; - while (i && j && !diff && count < complete->priv->limit) { - - if (i->data != j->data) - diff = TRUE; - - i = g_list_next (i); - j = g_list_next (j); - ++count; - } - - g_list_free (complete->priv->matches); - complete->priv->matches = sort_list; - - return diff; -} - -/* Emit a restart signal and re-declare our matches, up to the limit. */ -static void -e_completion_restart (ECompletion *complete) -{ - GList *i; - gint count = 0; - - gtk_signal_emit (GTK_OBJECT (complete), e_completion_signals[E_COMPLETION_RESTART_COMPLETION]); - - i = complete->priv->matches; - while (i != NULL && count < complete->priv->limit) { - Match *m = (Match *) i->data; - gtk_signal_emit (GTK_OBJECT (complete), e_completion_signals[E_COMPLETION_COMPLETION], m->text, m->extra_data); - - i = g_list_next (i); - ++count; - } -} - -void -e_completion_found_match (ECompletion *complete, const gchar *text) -{ - g_return_if_fail (complete); - g_return_if_fail (E_IS_COMPLETION (complete)); - g_return_if_fail (text != NULL); - - e_completion_found_match_full (complete, text, 0, NULL, NULL); -} - -void -e_completion_found_match_full (ECompletion *complete, const gchar *text, double score, gpointer extra_data, GtkDestroyNotify extra_destroy) -{ - g_return_if_fail (complete); - g_return_if_fail (E_IS_COMPLETION (complete)); - g_return_if_fail (text != NULL); - - if (! complete->priv->searching) { - g_warning ("e_completion_found_match(...,\"%s\",...) called outside of a search", text); - return; - } - - e_completion_add_match (complete, text, score, extra_data, extra_destroy); - - /* For now, do nothing when we hit the limit --- just don't announce the incoming matches. */ - if (complete->priv->match_count >= complete->priv->limit) { - return; - } - - gtk_signal_emit (GTK_OBJECT (complete), e_completion_signals[E_COMPLETION_COMPLETION], text, extra_data); -} - -void -e_completion_end_search (ECompletion *complete) -{ - g_return_if_fail (complete != NULL); - g_return_if_fail (E_IS_COMPLETION (complete)); - g_return_if_fail (complete->priv->searching); - - /* If sorting by score accomplishes anything, issue a restart right before we end. */ - if (e_completion_sort_by_score (complete)) - e_completion_restart (complete); - - gtk_signal_emit (GTK_OBJECT (complete), e_completion_signals[E_COMPLETION_END_COMPLETION]); - - complete->priv->searching = FALSE; -} - |