diff options
Diffstat (limited to 'lib/ephy-autocompletion.c')
-rw-r--r-- | lib/ephy-autocompletion.c | 609 |
1 files changed, 0 insertions, 609 deletions
diff --git a/lib/ephy-autocompletion.c b/lib/ephy-autocompletion.c deleted file mode 100644 index 6c28eaf78..000000000 --- a/lib/ephy-autocompletion.c +++ /dev/null @@ -1,609 +0,0 @@ -/* - * Copyright (C) 2002 Ricardo Fernández Pascual - * - * 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, 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. - * - * $Id$ - */ - -#include <string.h> -#include <stdlib.h> - -#include "ephy-autocompletion.h" -#include "ephy-marshal.h" -#include "ephy-debug.h" - -/** - * Private data - */ - -typedef enum { - GAS_NEEDS_REFINE, - GAS_NEEDS_FULL_UPDATE, - GAS_UPDATED -} EphyAutocompletionStatus; - -typedef struct { - EphyAutocompletionMatch *array; - guint num_matches; - guint num_action_matches; - guint array_size; -} ACMatchArray; - -#define ACMA_BASE_SIZE 10240 - -#define EPHY_AUTOCOMPLETION_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), EPHY_TYPE_AUTOCOMPLETION, EphyAutocompletionPrivate)) - -struct _EphyAutocompletionPrivate { - GSList *sources; - - guint nkeys; - gchar **keys; - guint *key_lengths; - gchar **prefixes; - guint *prefix_lengths; - - ACMatchArray matches; - EphyAutocompletionStatus status; - gboolean sorted; - gboolean changed; - - gboolean sort_alpha; -}; - -/** - * Private functions, only availble from this file - */ -static void ephy_autocompletion_class_init (EphyAutocompletionClass *klass); -static void ephy_autocompletion_init (EphyAutocompletion *e); -static void ephy_autocompletion_finalize_impl (GObject *o); -static void ephy_autocompletion_reset (EphyAutocompletion *ac); -static void ephy_autocompletion_update_matches (EphyAutocompletion *ac); -static void ephy_autocompletion_update_matches_full (EphyAutocompletion *ac); -static gboolean ephy_autocompletion_sort_by_score (EphyAutocompletion *ac); -static void ephy_autocompletion_data_changed_cb (EphyAutocompletionSource *s, - EphyAutocompletion *ac); - -static void acma_init (ACMatchArray *a); -static void acma_destroy (ACMatchArray *a); -static inline void acma_append (ACMatchArray *a, - EphyAutocompletionMatch *m, - gboolean action); -static void acma_grow (ACMatchArray *a); - - -static gpointer g_object_class; - -/** - * Signals enums and ids - */ -enum EphyAutocompletionSignalsEnum { - EPHY_AUTOCOMPLETION_SOURCES_CHANGED, - EPHY_AUTOCOMPLETION_LAST_SIGNAL -}; -static gint EphyAutocompletionSignals[EPHY_AUTOCOMPLETION_LAST_SIGNAL]; - -GType -ephy_autocompletion_get_type (void) -{ - static GType ephy_autocompletion_type = 0; - - if (ephy_autocompletion_type == 0) - { - static const GTypeInfo our_info = - { - sizeof (EphyAutocompletionClass), - NULL, - NULL, - (GClassInitFunc) ephy_autocompletion_class_init, - NULL, - NULL, - sizeof (EphyAutocompletion), - 0, - (GInstanceInitFunc) ephy_autocompletion_init - }; - - ephy_autocompletion_type = g_type_register_static (G_TYPE_OBJECT, - "EphyAutocompletion", - &our_info, 0); - } - - return ephy_autocompletion_type; -} - -static void -ephy_autocompletion_class_init (EphyAutocompletionClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - g_object_class = g_type_class_peek_parent (klass); - - object_class->finalize = ephy_autocompletion_finalize_impl; - - EphyAutocompletionSignals[EPHY_AUTOCOMPLETION_SOURCES_CHANGED] = g_signal_new ( - "sources-changed", G_OBJECT_CLASS_TYPE (klass), - G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST | G_SIGNAL_RUN_CLEANUP, - G_STRUCT_OFFSET (EphyAutocompletionClass, sources_changed), - NULL, NULL, - ephy_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - g_type_class_add_private (object_class, sizeof (EphyAutocompletionPrivate)); -} - -static void -ephy_autocompletion_init (EphyAutocompletion *ac) -{ - EphyAutocompletionPrivate *p = EPHY_AUTOCOMPLETION_GET_PRIVATE (ac); - ac->priv = p; - p->sources = NULL; - acma_init (&p->matches); - p->status = GAS_NEEDS_FULL_UPDATE; - - p->nkeys = 1; - - p->keys = g_new0 (gchar *, 2); - p->keys[0] = g_strdup (""); - p->key_lengths = g_new0 (guint, 2); - p->key_lengths[0] = 0; - - p->prefixes = g_new0 (gchar *, 2); - p->prefixes[0] = g_strdup (""); - p->prefix_lengths = g_new0 (guint, 2); - p->prefix_lengths[0] = 0; - - p->sort_alpha = TRUE; -} - -static void -ephy_autocompletion_finalize_impl (GObject *o) -{ - EphyAutocompletion *ac = EPHY_AUTOCOMPLETION (o); - EphyAutocompletionPrivate *p = ac->priv; - GSList *li; - - ephy_autocompletion_reset (ac); - - for (li = p->sources; li; li = li->next) - { - g_signal_handlers_disconnect_by_func (li->data, - ephy_autocompletion_data_changed_cb, ac); - g_object_unref (li->data); - } - - g_slist_free (p->sources); - - g_strfreev (p->keys); - g_free (p->key_lengths); - g_strfreev (p->prefixes); - g_free (p->prefix_lengths); - - G_OBJECT_CLASS (g_object_class)->finalize (o); - -} - -static void -ephy_autocompletion_reset (EphyAutocompletion *ac) -{ - EphyAutocompletionPrivate *p = ac->priv; - - START_PROFILER ("Resetting autocompletion") - - p->status = GAS_NEEDS_FULL_UPDATE; - - STOP_PROFILER ("Resetting autocompletion") -} - -EphyAutocompletion * -ephy_autocompletion_new (void) -{ - EphyAutocompletion *ret = g_object_new (EPHY_TYPE_AUTOCOMPLETION, NULL); - return ret; -} -void -ephy_autocompletion_add_source (EphyAutocompletion *ac, - EphyAutocompletionSource *s) -{ - EphyAutocompletionPrivate *p = ac->priv; - g_object_ref (G_OBJECT (s)); - p->sources = g_slist_prepend (p->sources, s); - ephy_autocompletion_reset (ac); - g_signal_connect (s, "data-changed", G_CALLBACK (ephy_autocompletion_data_changed_cb), ac); - - g_signal_emit (ac, EphyAutocompletionSignals[EPHY_AUTOCOMPLETION_SOURCES_CHANGED], 0); -} - -void -ephy_autocompletion_set_key (EphyAutocompletion *ac, - const gchar *key) -{ - EphyAutocompletionPrivate *p = ac->priv; - guint i; - guint keylen = strlen (key); - - if (strcmp (key, p->keys[0])) - { - GSList *li; - for (li = p->sources; li; li = li->next) - { - ephy_autocompletion_source_set_basic_key - (EPHY_AUTOCOMPLETION_SOURCE (li->data), key); - } - } - - LOG ("Set key %s, old key %s", key, p->keys[0]) - - if (keylen >= p->key_lengths[0] - && !strncmp (p->keys[0], key, p->key_lengths[0])) - { - if (!strcmp (key, p->keys[0])) - { - return; - } - if (p->status != GAS_NEEDS_FULL_UPDATE) - { - p->status = GAS_NEEDS_REFINE; - } - } - else - { - p->status = GAS_NEEDS_FULL_UPDATE; - } - - for (i = 0; p->prefixes[i]; ++i) - { - g_free (p->keys[i]); - p->keys[i] = g_strconcat (p->prefixes[i], key, NULL); - p->key_lengths[i] = keylen + p->prefix_lengths[i]; - } - -} - -const EphyAutocompletionMatch * -ephy_autocompletion_get_matches (EphyAutocompletion *ac) -{ - ephy_autocompletion_update_matches (ac); - return ac->priv->matches.array; -} - -const EphyAutocompletionMatch * -ephy_autocompletion_get_matches_sorted_by_score (EphyAutocompletion *ac, - gboolean *changed) -{ - *changed = ephy_autocompletion_sort_by_score (ac); - return ac->priv->matches.array; -} - -guint -ephy_autocompletion_get_num_matches (EphyAutocompletion *ac) -{ - ephy_autocompletion_update_matches (ac); - - return ac->priv->matches.num_matches; -} - -guint -ephy_autocompletion_get_num_action_matches (EphyAutocompletion *ac) -{ - return ac->priv->matches.num_matches - - ac->priv->matches.num_action_matches; -} - -static void -ephy_autocompletion_refine_matches (EphyAutocompletion *ac) -{ - EphyAutocompletionPrivate *p = ac->priv; - ACMatchArray oldmatches = p->matches; - ACMatchArray newmatches; - guint i; - gchar *key0 = p->keys[0]; - guint key0l = p->key_lengths[0]; - - START_PROFILER ("Refine matches") - - acma_init (&newmatches); - - p->changed = FALSE; - - for (i = 0; i < oldmatches.num_matches; i++) - { - EphyAutocompletionMatch *mi = &oldmatches.array[i]; - - if (mi->is_action || - (mi->match && mi->substring && g_strrstr (mi->match, p->keys[0])) || - (mi->title && mi->substring && g_strrstr (mi->title, p->keys[0])) || - !strncmp (key0, mi->title + mi->offset, key0l)) - { - acma_append (&newmatches, mi, mi->is_action); - } - else - { - p->changed = TRUE; - } - } - - acma_destroy (&oldmatches); - p->matches = newmatches; - - STOP_PROFILER ("Refine matches") -} - -static void -ephy_autocompletion_update_matches (EphyAutocompletion *ac) -{ - EphyAutocompletionPrivate *p = ac->priv; - if (p->status == GAS_UPDATED) - { - return; - } - if (p->status == GAS_NEEDS_FULL_UPDATE) - { - ephy_autocompletion_update_matches_full (ac); - } - if (p->status == GAS_NEEDS_REFINE) - { - ephy_autocompletion_refine_matches (ac); - } - - p->status = GAS_UPDATED; -} - -static void -ephy_autocompletion_update_matches_full_item (EphyAutocompletionSource *source, - const char *item, - const char *title, - const char *target, - gboolean is_action, - gboolean substring, - guint32 score, - EphyAutocompletionPrivate *p) -{ - if (substring) - { - if ((item && g_strrstr (item, p->keys[0])) || - (title && g_strrstr (title, p->keys[0]))) - { - EphyAutocompletionMatch m; - m.match = item; - m.title = title; - m.target = target; - m.is_action = is_action; - m.substring = substring; - m.offset = 0; - m.score = score; - acma_append (&p->matches, &m, is_action); - } - } - else if (is_action) - { - EphyAutocompletionMatch m; - m.match = item; - m.title = title; - m.target = target; - m.is_action = is_action; - m.substring = substring; - m.offset = 0; - m.score = score; - acma_append (&p->matches, &m, is_action); - } - else - { - guint i; - for (i = 0; p->keys[i]; ++i) - { - if (!strncmp (item, p->keys[i], p->key_lengths[i])) - { - EphyAutocompletionMatch m; - m.match = item; - m.title = title; - m.target = target; - m.is_action = is_action; - m.substring = substring; - m.offset = p->prefix_lengths[i]; - m.score = score; - acma_append (&p->matches, &m, is_action); - } - } - } -} - -static void -ephy_autocompletion_update_matches_full (EphyAutocompletion *ac) -{ - EphyAutocompletionPrivate *p = ac->priv; - GSList *li; - - START_PROFILER ("Update full") - - acma_destroy (&p->matches); - - for (li = p->sources; li; li = li->next) - { - EphyAutocompletionSource *s = EPHY_AUTOCOMPLETION_SOURCE (li->data); - g_assert (s); - ephy_autocompletion_source_foreach (s, p->keys[0], - (EphyAutocompletionSourceForeachFunc) - ephy_autocompletion_update_matches_full_item, - p); - } - - STOP_PROFILER ("Update full") - - p->sorted = FALSE; - p->changed = TRUE; - - LOG ("AC: %d matches, fully updated", p->matches.num_matches); -} - -static gint -ephy_autocompletion_compare_scores (EphyAutocompletionMatch *a, EphyAutocompletionMatch *b) -{ - /* higher scores first */ - return b->score - a->score; -} - -static gint -ephy_autocompletion_compare_scores_and_alpha (EphyAutocompletionMatch *a, EphyAutocompletionMatch *b) -{ - if (a->score == b->score) - { - return strcmp (a->title, b->title); - } - else - { - /* higher scores first */ - return b->score - a->score; - } -} - -static gboolean -ephy_autocompletion_sort_by_score (EphyAutocompletion *ac) -{ - EphyAutocompletionPrivate *p = ac->priv; - - gint (*comparer) (EphyAutocompletionMatch *m1, EphyAutocompletionMatch *m2); - - if (p->sort_alpha) - { - comparer = ephy_autocompletion_compare_scores_and_alpha; - } - else - { - comparer = ephy_autocompletion_compare_scores; - } - - ephy_autocompletion_update_matches (ac); - if (p->changed == FALSE) return FALSE; - - START_PROFILER ("Sorting") - - if (p->matches.num_matches > 0) - { - qsort (p->matches.array, p->matches.num_matches, - sizeof (EphyAutocompletionMatch), - (void *) comparer); - } - - p->sorted = TRUE; - - STOP_PROFILER ("Sorting") - - return TRUE; -} - -static void -ephy_autocompletion_data_changed_cb (EphyAutocompletionSource *s, - EphyAutocompletion *ac) -{ - LOG ("Data changed, resetting"); - ephy_autocompletion_reset (ac); - - g_signal_emit (ac, EphyAutocompletionSignals[EPHY_AUTOCOMPLETION_SOURCES_CHANGED], 0); -} - -void -ephy_autocompletion_set_prefixes (EphyAutocompletion *ac, - const gchar **prefixes) -{ - EphyAutocompletionPrivate *p = ac->priv; - guint nprefixes = 0; - gchar *oldkey = g_strdup (p->keys[0]); - guint i; - - /* count prefixes */ - while (prefixes[nprefixes]) - { - ++nprefixes; - } - - nprefixes--; - - g_strfreev (p->keys); - g_free (p->key_lengths); - g_strfreev (p->prefixes); - g_free (p->prefix_lengths); - - p->prefixes = g_new0 (gchar *, nprefixes + 2); - p->prefix_lengths = g_new0 (guint, nprefixes + 2); - p->keys = g_new0 (gchar *, nprefixes + 2); - p->key_lengths = g_new0 (guint, nprefixes + 2); - - p->prefixes[0] = g_strdup (""); - p->prefix_lengths[0] = 0; - p->keys[0] = oldkey; - p->key_lengths[0] = strlen (p->keys[0]); - - for (i = 0; i < nprefixes; ++i) - { - p->prefixes[i + 1] = g_strdup (prefixes[i]); - p->prefix_lengths[i + 1] = strlen (prefixes[i]); - p->keys[i + 1] = g_strconcat (p->prefixes[i + 1], p->keys[0], NULL); - p->key_lengths[i + 1] = p->prefix_lengths[i + 1] + p->key_lengths[0]; - } - - p->nkeys = nprefixes; -} - - -/* ACMatchArray */ - -static void -acma_init (ACMatchArray *a) -{ - a->array = NULL; - a->array_size = 0; - a->num_matches = 0; -} - -/** - * Does not free the struct itself, only its contents - */ -static void -acma_destroy (ACMatchArray *a) -{ - g_free (a->array); - a->array = NULL; - a->array_size = 0; - a->num_matches = 0; - a->num_action_matches = 0; -} - -static inline void -acma_append (ACMatchArray *a, - EphyAutocompletionMatch *m, - gboolean action) -{ - if (a->array_size == a->num_matches) - { - acma_grow (a); - } - - a->array[a->num_matches] = *m; - a->num_matches++; - if (action) a->num_action_matches++; -} - -static void -acma_grow (ACMatchArray *a) -{ - gint new_size; - EphyAutocompletionMatch *new_array; - - new_size = a->array_size + ACMA_BASE_SIZE; - new_array = g_renew (EphyAutocompletionMatch, a->array, new_size); - - a->array_size = new_size; - a->array = new_array; -} |