diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Makefile.am | 6 | ||||
-rw-r--r-- | lib/ephy-autocompletion-source.c | 85 | ||||
-rw-r--r-- | lib/ephy-autocompletion-source.h | 80 | ||||
-rw-r--r-- | lib/ephy-autocompletion.c | 609 | ||||
-rw-r--r-- | lib/ephy-autocompletion.h | 106 | ||||
-rw-r--r-- | lib/ephy-node-common.h | 3 | ||||
-rw-r--r-- | lib/widgets/Makefile.am | 2 | ||||
-rw-r--r-- | lib/widgets/ephy-autocompletion-window.c | 839 | ||||
-rw-r--r-- | lib/widgets/ephy-autocompletion-window.h | 89 | ||||
-rw-r--r-- | lib/widgets/ephy-location-entry.c | 876 |
10 files changed, 337 insertions, 2358 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am index bc0c0901c..7caefb55d 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -16,8 +16,6 @@ header_DATA = $(INST_H_FILES) NOINST_H_FILES = \ eel-gconf-extensions.h \ - ephy-autocompletion.h \ - ephy-autocompletion-source.h \ ephy-bonobo-extensions.h \ ephy-debug.h \ ephy-dnd.h \ @@ -44,10 +42,6 @@ INST_H_FILES = \ libephy_la_SOURCES = \ eel-gconf-extensions.c \ eel-gconf-extensions.h \ - ephy-autocompletion.c \ - ephy-autocompletion.h \ - ephy-autocompletion-source.c \ - ephy-autocompletion-source.h \ ephy-bonobo-extensions.h \ ephy-bonobo-extensions.c \ ephy-debug.c \ diff --git a/lib/ephy-autocompletion-source.c b/lib/ephy-autocompletion-source.c deleted file mode 100644 index 717b9924e..000000000 --- a/lib/ephy-autocompletion-source.c +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (C) 2002 Ricardo Fernándezs Pascual <ric@users.sourceforge.net> - * - * 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. - */ - -#include "ephy-autocompletion-source.h" -#include "ephy-marshal.h" - -static void ephy_autocompletion_source_base_init (gpointer g_class); - -GType -ephy_autocompletion_source_get_type (void) -{ - static GType autocompletion_source_type = 0; - - if (! autocompletion_source_type) - { - static const GTypeInfo autocompletion_source_info = - { - sizeof (EphyAutocompletionSourceIface), /* class_size */ - ephy_autocompletion_source_base_init, /* base_init */ - NULL, /* base_finalize */ - NULL, - NULL, /* class_finalize */ - NULL, /* class_data */ - 0, - 0, /* n_preallocs */ - NULL - }; - - autocompletion_source_type = g_type_register_static - (G_TYPE_INTERFACE, "EphyAutocompletionSource", &autocompletion_source_info, 0); - g_type_interface_add_prerequisite (autocompletion_source_type, G_TYPE_OBJECT); - } - - return autocompletion_source_type; -} - -static void -ephy_autocompletion_source_base_init (gpointer g_class) -{ - static gboolean initialized = FALSE; - - if (!initialized) - { - g_signal_new ("data-changed", - EPHY_TYPE_AUTOCOMPLETION_SOURCE, - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EphyAutocompletionSourceIface, data_changed), - NULL, NULL, - ephy_marshal_VOID__VOID, - G_TYPE_NONE, 0); - initialized = TRUE; - } -} - - -void -ephy_autocompletion_source_foreach (EphyAutocompletionSource *source, - const gchar *basic_key, - EphyAutocompletionSourceForeachFunc func, - gpointer data) -{ - (* EPHY_AUTOCOMPLETION_SOURCE_GET_IFACE (source)->foreach) (source, basic_key, func, data); -} - -void -ephy_autocompletion_source_set_basic_key (EphyAutocompletionSource *source, - const gchar *basic_key) -{ - (* EPHY_AUTOCOMPLETION_SOURCE_GET_IFACE (source)->set_basic_key) (source, basic_key); -} diff --git a/lib/ephy-autocompletion-source.h b/lib/ephy-autocompletion-source.h deleted file mode 100644 index 595708b3a..000000000 --- a/lib/ephy-autocompletion-source.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2002 Ricardo Fernándezs Pascual <ric@users.sourceforge.net> - * - * 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. - */ - -#ifndef EPHY_AUTOCOMPLETION_SOUCE_H -#define EPHY_AUTOCOMPLETION_SOUCE_H - -#include <glib-object.h> - -G_BEGIN_DECLS - -#define EPHY_TYPE_AUTOCOMPLETION_SOURCE (ephy_autocompletion_source_get_type ()) -#define EPHY_AUTOCOMPLETION_SOURCE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ - EPHY_TYPE_AUTOCOMPLETION_SOURCE, \ - EphyAutocompletionSource)) -#define EPHY_IS_AUTOCOMPLETION_SOURCE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \ - EPHY_TYPE_AUTOCOMPLETION_SOURCE)) -#define EPHY_AUTOCOMPLETION_SOURCE_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), \ - EPHY_TYPE_AUTOCOMPLETION_SOURCE, \ - EphyAutocompletionSourceIface)) - - -typedef struct _EphyAutocompletionSource EphyAutocompletionSource; -typedef struct _EphyAutocompletionSourceIface EphyAutocompletionSourceIface; -typedef void (* EphyAutocompletionSourceForeachFunc) (EphyAutocompletionSource *source, - const char *item, - const char *title, - const char *target, - gboolean is_action, - gboolean substring, - guint32 score, - gpointer data); - -struct _EphyAutocompletionSourceIface -{ - GTypeInterface g_iface; - - /* Signals */ - - /** - * Sources MUST emit this signal when theirs data changes, expecially if the - * strings are freed / modified. Otherwise, things will crash. - */ - void (* data_changed) (EphyAutocompletionSource *source); - - /* Virtual Table */ - void (* foreach) (EphyAutocompletionSource *source, - const gchar *basic_key, - EphyAutocompletionSourceForeachFunc func, - gpointer data); - void (* set_basic_key) (EphyAutocompletionSource *source, - const gchar *basic_key); -}; - -GType ephy_autocompletion_source_get_type (void); -void ephy_autocompletion_source_foreach (EphyAutocompletionSource *source, - const gchar *basic_key, - EphyAutocompletionSourceForeachFunc func, - gpointer data); -void ephy_autocompletion_source_set_basic_key (EphyAutocompletionSource *source, - const gchar *basic_key); - -G_END_DECLS - -#endif - 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; -} diff --git a/lib/ephy-autocompletion.h b/lib/ephy-autocompletion.h deleted file mode 100644 index 7a31c0c9f..000000000 --- a/lib/ephy-autocompletion.h +++ /dev/null @@ -1,106 +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. - */ - -#ifndef EPHY_AUTOCOMPLETION_H -#define EPHY_AUTOCOMPLETION_H - -#include <glib-object.h> -#include "ephy-autocompletion-source.h" - -G_BEGIN_DECLS - -/* object forward declarations */ - -typedef struct _EphyAutocompletion EphyAutocompletion; -typedef struct _EphyAutocompletionClass EphyAutocompletionClass; -typedef struct _EphyAutocompletionPrivate EphyAutocompletionPrivate; -typedef struct _EphyAutocompletionMatch EphyAutocompletionMatch; - -/** - * EphyAutocompletion object - */ - -#define EPHY_TYPE_AUTOCOMPLETION (ephy_autocompletion_get_type()) -#define EPHY_AUTOCOMPLETION(object) (G_TYPE_CHECK_INSTANCE_CAST((object), \ - EPHY_TYPE_AUTOCOMPLETION,\ - EphyAutocompletion)) -#define EPHY_AUTOCOMPLETION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), \ - EPHY_TYPE_AUTOCOMPLETION,\ - EphyAutocompletionClass)) -#define EPHY_IS_AUTOCOMPLETION(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), \ - EPHY_TYPE_AUTOCOMPLETION)) -#define EPHY_IS_AUTOCOMPLETION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), \ - EPHY_TYPE_AUTOCOMPLETION)) -#define EPHY_AUTOCOMPLETION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), \ - EPHY_TYPE_AUTOCOMPLETION,\ - EphyAutocompletionClass)) - -struct _EphyAutocompletionClass -{ - GObjectClass parent_class; - - /* signals */ - void (*sources_changed) (EphyAutocompletion *ac); -}; - -/* Remember: fields are public read-only */ -struct _EphyAutocompletion -{ - GObject parent_object; - - EphyAutocompletionPrivate *priv; -}; - -struct _EphyAutocompletionMatch -{ - const char *match; - const char *title; - const char *target; - guint offset; - gint32 score; - gboolean is_action; - gboolean substring; -}; - -/* this is a set of usual prefixes for web browsing */ -#define EPHY_AUTOCOMPLETION_USUAL_WEB_PREFIXES \ - "http://www.", \ - "http://", \ - "https://www.", \ - "https://", \ - "file://", \ - "www." - -GType ephy_autocompletion_get_type (void); -EphyAutocompletion * ephy_autocompletion_new (void); -void ephy_autocompletion_add_source (EphyAutocompletion *ac, - EphyAutocompletionSource *s); -void ephy_autocompletion_set_prefixes (EphyAutocompletion *ac, - const gchar **prefixes); -void ephy_autocompletion_set_key (EphyAutocompletion *ac, - const gchar *key); -const EphyAutocompletionMatch *ephy_autocompletion_get_matches (EphyAutocompletion *ac); -const EphyAutocompletionMatch *ephy_autocompletion_get_matches_sorted_by_score - (EphyAutocompletion *ac, - gboolean *changed); -guint ephy_autocompletion_get_num_matches (EphyAutocompletion *ac); -guint ephy_autocompletion_get_num_action_matches (EphyAutocompletion *ac); - -G_END_DECLS - -#endif diff --git a/lib/ephy-node-common.h b/lib/ephy-node-common.h index 72b550c1d..a81fafb20 100644 --- a/lib/ephy-node-common.h +++ b/lib/ephy-node-common.h @@ -37,7 +37,8 @@ enum STATES_NODE_ID = 4, HOSTS_NODE_ID = 5, PAGES_NODE_ID = 6, - ICONS_NODE_ID = 9 + ICONS_NODE_ID = 9, + SMARTBOOKMARKS_NODE_ID = 10 }; typedef enum diff --git a/lib/widgets/Makefile.am b/lib/widgets/Makefile.am index 7331079a5..6a8835728 100644 --- a/lib/widgets/Makefile.am +++ b/lib/widgets/Makefile.am @@ -14,8 +14,6 @@ noinst_LTLIBRARIES = libephywidgets.la libephywidgets_la_SOURCES = \ ephy-arrow-toolbutton.c \ ephy-arrow-toolbutton.h \ - ephy-autocompletion-window.c \ - ephy-autocompletion-window.h \ ephy-ellipsizing-label.c \ ephy-ellipsizing-label.h \ ephy-location-entry.c \ diff --git a/lib/widgets/ephy-autocompletion-window.c b/lib/widgets/ephy-autocompletion-window.c deleted file mode 100644 index 39bd9d77e..000000000 --- a/lib/widgets/ephy-autocompletion-window.c +++ /dev/null @@ -1,839 +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 <gtk/gtkcellrenderertext.h> -#include <gtk/gtktreeview.h> -#include <gtk/gtkscrolledwindow.h> -#include <gtk/gtktreeselection.h> -#include <gtk/gtkliststore.h> -#include <gtk/gtkwindow.h> -#include <gtk/gtkmain.h> -#include <gtk/gtkvbox.h> -#include <gdk/gdkkeysyms.h> -#include <gtk/gtkframe.h> - -#include "ephy-autocompletion-window.h" -#include "ephy-string.h" -#include "ephy-marshal.h" -#include "ephy-gui.h" -#include "ephy-debug.h" - -/* This is copied from gtkscrollbarwindow.c */ -#define DEFAULT_SCROLLBAR_SPACING 3 - -#define SCROLLBAR_SPACING(w) \ - (GTK_SCROLLED_WINDOW_GET_CLASS (w)->scrollbar_spacing >= 0 ? \ - GTK_SCROLLED_WINDOW_GET_CLASS (w)->scrollbar_spacing : DEFAULT_SCROLLBAR_SPACING) - -#define MAX_VISIBLE_ROWS 9 -#define MAX_COMPLETION_ALTERNATIVES 7 - -/** - * Private data - */ - -#define EPHY_AUTOCOMPLETION_WINDOW_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), EPHY_TYPE_AUTOCOMPLETION_WINDOW, EphyAutocompletionWindowPrivate)) - -struct _EphyAutocompletionWindowPrivate { - EphyAutocompletion *autocompletion; - GtkWidget *parent; - - GtkWidget *window; - GtkScrolledWindow *scrolled_window; - GtkTreeView *tree_view; - GtkTreeViewColumn *col1; - GtkTreeView *action_tree_view; - GtkTreeViewColumn *action_col1; - int sel_index; - gboolean action; - - char *selected; - - GtkListStore *list_store; - GtkListStore *action_list_store; - guint last_added_match; - int view_nitems; - - gboolean shown; -}; - -/** - * Private functions, only availble from this file - */ -static void ephy_autocompletion_window_class_init (EphyAutocompletionWindowClass *klass); -static void ephy_autocompletion_window_init (EphyAutocompletionWindow *aw); -static void ephy_autocompletion_window_finalize_impl (GObject *o); -static void ephy_autocompletion_window_init_widgets (EphyAutocompletionWindow *aw); -static void ephy_autocompletion_window_selection_changed_cb (GtkTreeSelection *treeselection, - EphyAutocompletionWindow *aw); -static gboolean ephy_autocompletion_window_button_press_event_cb (GtkWidget *widget, - GdkEventButton *event, - EphyAutocompletionWindow *aw); -static gboolean ephy_autocompletion_window_key_press_cb (GtkWidget *widget, - GdkEventKey *event, - EphyAutocompletionWindow *aw); -static void ephy_autocompletion_window_event_after_cb (GtkWidget *wid, GdkEvent *event, - EphyAutocompletionWindow *aw); -static void ephy_autocompletion_window_fill_store_chunk (EphyAutocompletionWindow *aw); - - -static gpointer g_object_class; - -enum EphyAutocompletionWindowSignalsEnum { - ACTIVATED, - SELECTED, - EPHY_AUTOCOMPLETION_WINDOW_HIDDEN, - EPHY_AUTOCOMPLETION_WINDOW_LAST_SIGNAL -}; -static gint EphyAutocompletionWindowSignals[EPHY_AUTOCOMPLETION_WINDOW_LAST_SIGNAL]; - -GType -ephy_autocompletion_window_get_type (void) -{ - static GType ephy_autocompletion_window_type = 0; - - if (ephy_autocompletion_window_type == 0) - { - static const GTypeInfo our_info = - { - sizeof (EphyAutocompletionWindowClass), - NULL, - NULL, - (GClassInitFunc) ephy_autocompletion_window_class_init, - NULL, - NULL, - sizeof (EphyAutocompletionWindow), - 0, - (GInstanceInitFunc) ephy_autocompletion_window_init - }; - - ephy_autocompletion_window_type = g_type_register_static (G_TYPE_OBJECT, - "EphyAutocompletionWindow", - &our_info, 0); - } - - return ephy_autocompletion_window_type; -} - -static void -ephy_autocompletion_window_class_init (EphyAutocompletionWindowClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - g_object_class = g_type_class_peek_parent (klass); - - object_class->finalize = ephy_autocompletion_window_finalize_impl; - - EphyAutocompletionWindowSignals[ACTIVATED] = g_signal_new ( - "activated", G_OBJECT_CLASS_TYPE (klass), - G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST | G_SIGNAL_RUN_CLEANUP, - G_STRUCT_OFFSET (EphyAutocompletionWindowClass, activated), - NULL, NULL, - ephy_marshal_VOID__STRING_INT, - G_TYPE_NONE, - 2, - G_TYPE_STRING, - G_TYPE_INT); - - EphyAutocompletionWindowSignals[SELECTED] = g_signal_new ( - "selected", G_OBJECT_CLASS_TYPE (klass), - G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST | G_SIGNAL_RUN_CLEANUP, - G_STRUCT_OFFSET (EphyAutocompletionWindowClass, selected), - NULL, NULL, - ephy_marshal_VOID__STRING_INT, - G_TYPE_NONE, - 2, - G_TYPE_STRING, - G_TYPE_INT); - - EphyAutocompletionWindowSignals[EPHY_AUTOCOMPLETION_WINDOW_HIDDEN] = g_signal_new ( - "hidden", G_OBJECT_CLASS_TYPE (klass), - G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST | G_SIGNAL_RUN_CLEANUP, - G_STRUCT_OFFSET (EphyAutocompletionWindowClass, hidden), - NULL, NULL, - ephy_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - g_type_class_add_private (object_class, sizeof (EphyAutocompletionWindowPrivate)); -} - -static void -ephy_autocompletion_window_init (EphyAutocompletionWindow *aw) -{ - EphyAutocompletionWindowPrivate *p = EPHY_AUTOCOMPLETION_WINDOW_GET_PRIVATE (aw); - GtkTreeSelection *s; - - aw->priv = p; - p->selected = NULL; - - ephy_autocompletion_window_init_widgets (aw); - - s = gtk_tree_view_get_selection (p->tree_view); - /* I would like to use GTK_SELECTION_SINGLE, but it seems to require that one - item is selected always */ - gtk_tree_selection_set_mode (s, GTK_SELECTION_MULTIPLE); - - g_signal_connect (s, "changed", G_CALLBACK (ephy_autocompletion_window_selection_changed_cb), aw); - - s = gtk_tree_view_get_selection (p->action_tree_view); - gtk_tree_selection_set_mode (s, GTK_SELECTION_MULTIPLE); - - g_signal_connect (s, "changed", G_CALLBACK (ephy_autocompletion_window_selection_changed_cb), aw); -} - -static void -ephy_autocompletion_window_finalize_impl (GObject *o) -{ - EphyAutocompletionWindow *aw = EPHY_AUTOCOMPLETION_WINDOW (o); - EphyAutocompletionWindowPrivate *p = aw->priv; - - if (p->list_store) g_object_unref (p->list_store); - if (p->action_list_store) g_object_unref (p->action_list_store); - if (p->parent) g_object_unref (p->parent); - if (p->window) gtk_widget_destroy (p->window); - - if (p->autocompletion) - { - g_signal_handlers_disconnect_matched (p->autocompletion, G_SIGNAL_MATCH_DATA, 0, 0, - NULL, NULL, aw); - g_object_unref (p->autocompletion); - } - - g_free (p->selected); - - gdk_pointer_ungrab (GDK_CURRENT_TIME); - gdk_keyboard_ungrab (GDK_CURRENT_TIME); - - G_OBJECT_CLASS (g_object_class)->finalize (o); -} - -static gboolean -set_renderer_bg_color (GtkWidget *widget, - GtkStyle *previous_style, - GtkCellRenderer *renderer) -{ - GValue v = { 0 }; - GdkColor *bg_color; - GtkStyle *style; - - g_value_init (&v, GDK_TYPE_COLOR); - g_object_get_property (G_OBJECT (renderer), "cell_background_gdk", &v); - bg_color = g_value_peek_pointer (&v); - style = gtk_widget_get_style (widget); - *bg_color = style->bg[GTK_STATE_NORMAL]; - g_object_set_property (G_OBJECT (renderer), "cell_background_gdk", &v); - - return FALSE; -} - -static void -ephy_autocompletion_window_init_widgets (EphyAutocompletionWindow *aw) -{ - EphyAutocompletionWindowPrivate *p = aw->priv; - GtkWidget *sw; - GtkCellRenderer *renderer; - GtkWidget *frame; - GtkWidget *vbox; - - p->window = gtk_window_new (GTK_WINDOW_POPUP); - gtk_window_set_resizable (GTK_WINDOW (p->window), FALSE); - - frame = gtk_frame_new (NULL); - gtk_frame_set_shadow_type (GTK_FRAME (frame), - GTK_SHADOW_OUT); - gtk_container_add (GTK_CONTAINER (p->window), frame); - gtk_widget_show (frame); - - vbox = gtk_vbox_new (FALSE, 0); - gtk_widget_show (vbox); - gtk_container_add (GTK_CONTAINER (frame), vbox); - - sw = gtk_scrolled_window_new (NULL, NULL); - gtk_box_pack_start (GTK_BOX (vbox), - sw, TRUE, TRUE, 0); - gtk_scrolled_window_set_shadow_type - (GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN); - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), - GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - p->scrolled_window = GTK_SCROLLED_WINDOW (sw); - gtk_widget_show (sw); - - p->tree_view = GTK_TREE_VIEW (gtk_tree_view_new ()); - gtk_container_add (GTK_CONTAINER (sw), GTK_WIDGET (p->tree_view)); - gtk_widget_realize (GTK_WIDGET (p->tree_view)); - - renderer = gtk_cell_renderer_text_new (); - p->col1 = gtk_tree_view_column_new (); - gtk_tree_view_column_pack_start (p->col1, renderer, TRUE); - gtk_tree_view_column_set_attributes (p->col1, renderer, - "text", 0, - NULL); - gtk_tree_view_append_column (p->tree_view, p->col1); - - gtk_tree_view_set_headers_visible (p->tree_view, FALSE); - gtk_widget_show (GTK_WIDGET(p->tree_view)); - - p->action_tree_view = GTK_TREE_VIEW (gtk_tree_view_new ()); - gtk_box_pack_start (GTK_BOX (vbox), - GTK_WIDGET (p->action_tree_view), - FALSE, TRUE, 0); - - renderer = gtk_cell_renderer_text_new (); - - set_renderer_bg_color (p->window, NULL, renderer); - g_signal_connect (G_OBJECT (p->window), "style-set", - G_CALLBACK (set_renderer_bg_color), G_OBJECT (renderer)); - - p->action_col1 = gtk_tree_view_column_new (); - gtk_tree_view_column_pack_start (p->action_col1, renderer, TRUE); - gtk_tree_view_column_set_attributes (p->action_col1, renderer, - "text", 0, - NULL); - gtk_tree_view_append_column (p->action_tree_view, p->action_col1); - - gtk_tree_view_set_headers_visible (p->action_tree_view, FALSE); - gtk_widget_show (GTK_WIDGET(p->action_tree_view)); -} - -EphyAutocompletionWindow * -ephy_autocompletion_window_new (EphyAutocompletion *ac, GtkWidget *w) -{ - EphyAutocompletionWindow *ret = g_object_new (EPHY_TYPE_AUTOCOMPLETION_WINDOW, NULL); - ephy_autocompletion_window_set_parent_widget (ret, w); - ephy_autocompletion_window_set_autocompletion (ret, ac); - return ret; -} - -void -ephy_autocompletion_window_set_parent_widget (EphyAutocompletionWindow *aw, GtkWidget *w) -{ - if (aw->priv->parent) g_object_unref (aw->priv->parent); - aw->priv->parent = g_object_ref (w); -} - -void -ephy_autocompletion_window_set_autocompletion (EphyAutocompletionWindow *aw, - EphyAutocompletion *ac) -{ - EphyAutocompletionWindowPrivate *p = aw->priv; - - if (p->autocompletion) - { - g_signal_handlers_disconnect_matched (p->autocompletion, G_SIGNAL_MATCH_DATA, 0, 0, - NULL, NULL, aw); - - g_object_unref (p->autocompletion); - - } - p->autocompletion = g_object_ref (ac); -} - -static void -ephy_autocompletion_window_selection_changed_cb (GtkTreeSelection *treeselection, - EphyAutocompletionWindow *aw) -{ - GList *l; - GtkTreeModel *model; - - if (aw->priv->selected) g_free (aw->priv->selected); - - l = gtk_tree_selection_get_selected_rows (treeselection, &model); - if (l) - { - GtkTreePath *path; - GtkTreeIter iter; - path = (GtkTreePath *)l->data; - - gtk_tree_model_get_iter (model, &iter, path); - gtk_tree_model_get (model, &iter, 1, - &aw->priv->selected, -1); - - g_list_foreach (l, (GFunc)gtk_tree_path_free, NULL); - g_list_free (l); - } - else - { - aw->priv->selected = NULL; - } -} - -static void -ephy_autocompletion_window_get_dimensions (EphyAutocompletionWindow *aw, - int *x, int *y, int *width, int *height) -{ - GtkBin *popwin; - GtkWidget *widget; - GtkScrolledWindow *popup; - gint real_height; - GtkRequisition list_requisition; - gboolean show_vscroll = FALSE; - gint avail_height; - gint min_height; - gint alloc_width; - gint work_height; - gint old_height; - gint old_width; - int row_height; - - widget = GTK_WIDGET (aw->priv->parent); - popup = GTK_SCROLLED_WINDOW (aw->priv->scrolled_window); - popwin = GTK_BIN (aw->priv->window); - - gdk_window_get_origin (widget->window, x, y); - real_height = MIN (widget->requisition.height, - widget->allocation.height); - *y += real_height; - avail_height = gdk_screen_height () - *y; - - gtk_widget_size_request (GTK_WIDGET(aw->priv->tree_view), - &list_requisition); - - alloc_width = (widget->allocation.width - - 2 * popwin->child->style->xthickness - - 2 * GTK_CONTAINER (popwin->child)->border_width - - 2 * GTK_CONTAINER (popup)->border_width - - 2 * GTK_CONTAINER (GTK_BIN (popup)->child)->border_width - - 2 * GTK_BIN (popup)->child->style->xthickness); - - work_height = (2 * popwin->child->style->ythickness + - 2 * GTK_CONTAINER (popwin->child)->border_width + - 2 * GTK_CONTAINER (popup)->border_width + - 2 * GTK_CONTAINER (GTK_BIN (popup)->child)->border_width + - 2 * GTK_BIN (popup)->child->style->ythickness); - - min_height = MIN (list_requisition.height, - popup->vscrollbar->requisition.height); - - row_height = list_requisition.height / MAX (aw->priv->view_nitems, 1); - LOG ("Real list requisition %d, Items %d", list_requisition.height, aw->priv->view_nitems) - list_requisition.height = MIN (row_height * MAX_VISIBLE_ROWS, list_requisition.height); - LOG ("Row Height %d, Fake list requisition %d", row_height, list_requisition.height) - - do - { - old_width = alloc_width; - old_height = work_height; - - if (!show_vscroll && - work_height + list_requisition.height > avail_height) - { - if (work_height + min_height > avail_height && - *y - real_height > avail_height) - { - *y -= (work_height + list_requisition.height + - real_height); - break; - } - alloc_width -= (popup->vscrollbar->requisition.width + - SCROLLBAR_SPACING (popup)); - show_vscroll = TRUE; - } - } while (old_width != alloc_width || old_height != work_height); - - *width = widget->allocation.width; - - if (*x < 0) *x = 0; - - *height = MIN (work_height + list_requisition.height, - avail_height); - - /* Action view */ - work_height = (2 * GTK_CONTAINER (popup)->border_width + - 2 * GTK_WIDGET (popup)->style->ythickness); - - if (!GTK_WIDGET_VISIBLE (aw->priv->scrolled_window)) - { - *height = work_height; - } - - gtk_widget_size_request (GTK_WIDGET(aw->priv->action_tree_view), - &list_requisition); - - if (GTK_WIDGET_VISIBLE (aw->priv->action_tree_view)) - { - *height += list_requisition.height; - } -} - -static void -ephy_autocompletion_window_fill_store_chunk (EphyAutocompletionWindow *aw) -{ - EphyAutocompletionWindowPrivate *p = aw->priv; - const EphyAutocompletionMatch *matches; - guint i; - gboolean changed; - guint nmatches; - guint last; - guint completion_nitems = 0, action_nitems = 0, substring_nitems = 0; - - START_PROFILER ("Fill store") - - nmatches = ephy_autocompletion_get_num_matches (p->autocompletion); - matches = ephy_autocompletion_get_matches_sorted_by_score (p->autocompletion, - &changed); - if (!changed) return; - - if (p->list_store) g_object_unref (p->list_store); - p->list_store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING); - - if (p->action_list_store) g_object_unref (p->action_list_store); - p->action_list_store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING); - - last = p->last_added_match = 0; - - for (i = 0; last < nmatches; i++, last++) - { - const EphyAutocompletionMatch *m = &matches[last]; - GtkTreeIter iter; - GtkListStore *store; - - if (m->is_action || m->substring || - completion_nitems <= MAX_COMPLETION_ALTERNATIVES) - { - if (m->is_action) - { - store = p->action_list_store; - action_nitems ++; - } - else if (m->substring) - { - store = p->list_store; - substring_nitems ++; - } - else - { - store = p->list_store; - completion_nitems ++; - } - - gtk_list_store_append (store, &iter); - gtk_list_store_set (store, &iter, - 0, m->title, - 1, m->target, - -1); - } - } - - p->view_nitems = substring_nitems + completion_nitems; - - gtk_widget_show (GTK_WIDGET (p->scrolled_window)); - gtk_widget_show (GTK_WIDGET (p->action_tree_view)); - if (p->view_nitems == 0) - { - gtk_widget_hide (GTK_WIDGET (p->scrolled_window)); - } - if (action_nitems == 0) - { - gtk_widget_hide (GTK_WIDGET (p->action_tree_view)); - } - - p->last_added_match = last; - - STOP_PROFILER ("Fill store") -} - -void -ephy_autocompletion_window_show (EphyAutocompletionWindow *aw) -{ - EphyAutocompletionWindowPrivate *p = aw->priv; - gint x, y, height, width; - guint nmatches; - - g_return_if_fail (p->window); - g_return_if_fail (p->autocompletion); - - nmatches = ephy_autocompletion_get_num_matches (p->autocompletion); - if (nmatches <= 0) - { - ephy_autocompletion_window_hide (aw); - return; - } - - START_PROFILER ("Showing window") - - ephy_autocompletion_window_fill_store_chunk (aw); - - gtk_tree_view_set_model (p->tree_view, GTK_TREE_MODEL (p->list_store)); - gtk_tree_view_set_model (p->action_tree_view, GTK_TREE_MODEL (p->action_list_store)); - - ephy_autocompletion_window_get_dimensions (aw, &x, &y, &width, &height); - - gtk_widget_set_size_request (GTK_WIDGET (p->window), width, - height); - gtk_window_move (GTK_WINDOW (p->window), x, y); - - if (!p->shown) - { - gtk_widget_show (p->window); - - gdk_pointer_grab (p->parent->window, TRUE, - GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK | - GDK_BUTTON_RELEASE_MASK, - NULL, NULL, GDK_CURRENT_TIME); - gdk_keyboard_grab (p->parent->window, TRUE, GDK_CURRENT_TIME); - gtk_grab_add (p->window); - - g_signal_connect (p->window, "button-press-event", - G_CALLBACK (ephy_autocompletion_window_button_press_event_cb), - aw); - g_signal_connect (p->window, "key-press-event", - G_CALLBACK (ephy_autocompletion_window_key_press_cb), - aw); - g_signal_connect (p->tree_view, "event-after", - G_CALLBACK (ephy_autocompletion_window_event_after_cb), - aw); - g_signal_connect (p->action_tree_view, "event-after", - G_CALLBACK (ephy_autocompletion_window_event_after_cb), - aw); - - p->shown = TRUE; - } - - gtk_tree_view_scroll_to_point (GTK_TREE_VIEW (p->tree_view), 0, 0); - - gtk_widget_grab_focus (GTK_WIDGET (p->tree_view)); - - STOP_PROFILER ("Showing window") -} - -static gboolean -ephy_autocompletion_window_button_press_event_cb (GtkWidget *widget, - GdkEventButton *event, - EphyAutocompletionWindow *aw) -{ - GtkWidget *event_widget; - - event_widget = gtk_get_event_widget ((GdkEvent *) event); - - /* Check to see if button press happened inside the alternatives - window. If not, destroy the window. */ - if (event_widget != aw->priv->window) - { - while (event_widget) - { - if (event_widget == aw->priv->window) - return FALSE; - event_widget = event_widget->parent; - } - } - ephy_autocompletion_window_hide (aw); - - return TRUE; -} - -static void -move_selection (EphyAutocompletionWindow *aw, int dir) -{ - int new_index; - int n_compl, n_actions, n_items; - GtkTreeModel *compl_model, *actions_model; - GtkTreeSelection *compl_sel, *actions_sel; - - compl_model = gtk_tree_view_get_model (aw->priv->tree_view); - actions_model = gtk_tree_view_get_model (aw->priv->action_tree_view); - compl_sel = gtk_tree_view_get_selection (aw->priv->tree_view); - actions_sel = gtk_tree_view_get_selection (aw->priv->action_tree_view); - - n_compl = gtk_tree_model_iter_n_children (compl_model, NULL); - n_actions = gtk_tree_model_iter_n_children (actions_model, NULL); - n_items = n_compl + n_actions; - - /* Index 0 no selection. - * Index 1 in the completion. - * Index -1 in the actions. */ - new_index = aw->priv->sel_index + dir; - - /* On overflow stay on 0/max if you are no already there. Otherwise - go on the opposite limit */ - if (new_index < 0) - { - new_index = (aw->priv->sel_index != 0) ? 0 : n_items; - } - else if (new_index > n_items) - { - new_index = (aw->priv->sel_index != n_items) ? n_items : 0; - } - - gtk_tree_selection_unselect_all (compl_sel); - gtk_tree_selection_unselect_all (actions_sel); - - if (new_index == 0) - { - } - else if (new_index > n_compl) - { - GtkTreeIter iter; - GtkTreePath *path; - - gtk_tree_selection_unselect_all (compl_sel); - gtk_tree_model_iter_nth_child (actions_model, &iter, NULL, - new_index - n_compl - 1); - gtk_tree_selection_select_iter (actions_sel, &iter); - - path = gtk_tree_model_get_path (actions_model, &iter); - gtk_tree_view_scroll_to_cell (aw->priv->action_tree_view, - path, NULL, FALSE, 0, 0); - gtk_tree_path_free (path); - - aw->priv->action = TRUE; - } - else if (new_index <= n_compl) - { - GtkTreeIter iter; - GtkTreePath *path; - - gtk_tree_selection_unselect_all (actions_sel); - gtk_tree_model_iter_nth_child (compl_model, &iter, NULL, - new_index - 1); - gtk_tree_selection_select_iter (compl_sel, &iter); - - path = gtk_tree_model_get_path (compl_model, &iter); - gtk_tree_view_scroll_to_cell (aw->priv->tree_view, - path, NULL, FALSE, 0, 0); - gtk_tree_path_free (path); - - aw->priv->action = FALSE; - } - else - { - g_assert_not_reached (); - } - - aw->priv->sel_index = new_index; -} - -static gboolean -ephy_autocompletion_window_key_press_hack (EphyAutocompletionWindow *aw, - guint keyval) -{ - switch (keyval) - { - case GDK_Up: - move_selection (aw, -1); - break; - case GDK_Down: - move_selection (aw, +1); - break; - case GDK_Page_Down: - move_selection (aw, +5); - break; - case GDK_Page_Up: - move_selection (aw, -5); - break; - case GDK_Return: - case GDK_space: - if (aw->priv->selected) - { - g_signal_emit (aw, EphyAutocompletionWindowSignals - [ACTIVATED], 0, aw->priv->selected, - aw->priv->action); - } - break; - } - - switch (keyval) - { - case GDK_Up: - case GDK_Down: - case GDK_Page_Down: - case GDK_Page_Up: - if (aw->priv->selected) - { - g_signal_emit (aw, EphyAutocompletionWindowSignals - [SELECTED], 0, aw->priv->selected, - aw->priv->action); - } - break; - default: - break; - } - - return TRUE; -} - -static gboolean -ephy_autocompletion_window_key_press_cb (GtkWidget *widget, - GdkEventKey *event, - EphyAutocompletionWindow *aw) -{ - EphyAutocompletionWindowPrivate *p = aw->priv; - GdkEventKey tmp_event; - - if (event->keyval == GDK_Up || event->keyval == GDK_Down - || event->keyval == GDK_Page_Up || event->keyval == GDK_Page_Down - || ((event->keyval == GDK_space || event->keyval == GDK_Return) - && p->selected)) - { - return ephy_autocompletion_window_key_press_hack - (aw, event->keyval); - } - - tmp_event = *event; - gtk_widget_event (p->parent, (GdkEvent *)&tmp_event); - - return TRUE; -} - -void -ephy_autocompletion_window_hide (EphyAutocompletionWindow *aw) -{ - if (aw->priv->window && aw->priv->shown) - { - gtk_widget_hide (aw->priv->window); - gtk_grab_remove (aw->priv->window); - gdk_pointer_ungrab (GDK_CURRENT_TIME); - gdk_keyboard_ungrab (GDK_CURRENT_TIME); - ephy_autocompletion_window_unselect (aw); - g_signal_emit (aw, EphyAutocompletionWindowSignals[EPHY_AUTOCOMPLETION_WINDOW_HIDDEN], 0); - aw->priv->sel_index = 0; - aw->priv->action = FALSE; - } - g_free (aw->priv->selected); - aw->priv->selected = NULL; - aw->priv->shown = FALSE; -} - -void -ephy_autocompletion_window_unselect (EphyAutocompletionWindow *aw) -{ - EphyAutocompletionWindowPrivate *p = aw->priv; - GtkTreeSelection *ts = gtk_tree_view_get_selection (p->tree_view); - gtk_tree_selection_unselect_all (ts); -} - -static void -ephy_autocompletion_window_event_after_cb (GtkWidget *wid, GdkEvent *event, - EphyAutocompletionWindow *aw) -{ - gboolean action; - EphyAutocompletionWindowPrivate *p = aw->priv; - - action = (wid == GTK_WIDGET (p->action_tree_view)); - - if (event->type == GDK_BUTTON_PRESS - && ((GdkEventButton *) event)->button == 1) - { - if (p->selected) - { - g_signal_emit (aw, EphyAutocompletionWindowSignals - [ACTIVATED], 0, p->selected, action); - } - } -} diff --git a/lib/widgets/ephy-autocompletion-window.h b/lib/widgets/ephy-autocompletion-window.h deleted file mode 100644 index 63b4a4ed3..000000000 --- a/lib/widgets/ephy-autocompletion-window.h +++ /dev/null @@ -1,89 +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. - */ - -#ifndef EPHY_AUTOCOMPLETION_WINDOW_H -#define EPHY_AUTOCOMPLETION_WINDOW_H - -#include <glib-object.h> -#include <gtk/gtkwidget.h> - -#include "ephy-autocompletion.h" - -G_BEGIN_DECLS - -/* object forward declarations */ - -typedef struct _EphyAutocompletionWindow EphyAutocompletionWindow; -typedef struct _EphyAutocompletionWindowClass EphyAutocompletionWindowClass; -typedef struct _EphyAutocompletionWindowPrivate EphyAutocompletionWindowPrivate; - -/** - * Editor object - */ - -#define EPHY_TYPE_AUTOCOMPLETION_WINDOW (ephy_autocompletion_window_get_type()) -#define EPHY_AUTOCOMPLETION_WINDOW(object) (G_TYPE_CHECK_INSTANCE_CAST((object), \ - EPHY_TYPE_AUTOCOMPLETION_WINDOW,\ - EphyAutocompletionWindow)) -#define EPHY_AUTOCOMPLETION_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), \ - EPHY_TYPE_AUTOCOMPLETION_WINDOW,\ - EphyAutocompletionWindowClass)) -#define EPHY_IS_AUTOCOMPLETION_WINDOW(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), \ - EPHY_TYPE_AUTOCOMPLETION_WINDOW)) -#define EPHY_IS_AUTOCOMPLETION_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), \ - EPHY_TYPE_AUTOCOMPLETION_WINDOW)) -#define EPHY_AUTOCOMPLETION_WINDOW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), \ - EPHY_TYPE_AUTOCOMPLETION_WINDOW,\ - EphyAutocompletionWindowClass)) - -struct _EphyAutocompletionWindowClass -{ - GObjectClass parent_class; - - /* signals */ - void (*hidden) (EphyAutocompletionWindow *aw); - void (*activated) (EphyAutocompletionWindow *aw, - const char *target, - int action); - void (*selected) (EphyAutocompletionWindow *aw, - const char *target, - int action); -}; - -/* Remember: fields are public read-only */ -struct _EphyAutocompletionWindow -{ - GObject parent_object; - - EphyAutocompletionWindowPrivate *priv; -}; - -GType ephy_autocompletion_window_get_type (void); -EphyAutocompletionWindow *ephy_autocompletion_window_new (EphyAutocompletion *ac, - GtkWidget *parent); -void ephy_autocompletion_window_set_parent_widget (EphyAutocompletionWindow *aw, - GtkWidget *w); -void ephy_autocompletion_window_set_autocompletion (EphyAutocompletionWindow *aw, - EphyAutocompletion *ac); -void ephy_autocompletion_window_show (EphyAutocompletionWindow *aw); -void ephy_autocompletion_window_hide (EphyAutocompletionWindow *aw); -void ephy_autocompletion_window_unselect (EphyAutocompletionWindow *aw); - -G_END_DECLS - -#endif diff --git a/lib/widgets/ephy-location-entry.c b/lib/widgets/ephy-location-entry.c index bca1d9790..c160a898e 100644 --- a/lib/widgets/ephy-location-entry.c +++ b/lib/widgets/ephy-location-entry.c @@ -20,106 +20,78 @@ * $Id$ */ +#include "ephy-tree-model-node.h" #include "ephy-location-entry.h" -#include "ephy-autocompletion-window.h" #include "ephy-marshal.h" -#include "eel-gconf-extensions.h" -#include "ephy-prefs.h" #include "ephy-debug.h" +#include "ephy-file-helpers.h" -#include <glib-object.h> -#include <gtk/gtkhbox.h> +#include <gtk/gtktoolbar.h> +#include <gtk/gtkliststore.h> +#include <gtk/gtkcomboboxentry.h> #include <gtk/gtkentry.h> #include <gtk/gtkwindow.h> -#include <gdk/gdkkeysyms.h> -#include <gtk/gtkmain.h> -#include <gtk/gtktoolbar.h> -#include <gtk/gtktooltips.h> -#include <libgnomeui/gnome-entry.h> +#include <gtk/gtkcellrenderertext.h> +#include <gtk/gtkcelllayout.h> +#include <gtk/gtktreemodelsort.h> #include <string.h> -/** - * Private data - */ - #define EPHY_LOCATION_ENTRY_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), EPHY_TYPE_LOCATION_ENTRY, EphyLocationEntryPrivate)) -struct _EphyLocationEntryPrivate { +struct _EphyLocationEntryPrivate +{ + EphyTreeModelNode *combo_model; GtkWidget *combo; GtkWidget *entry; char *before_completion; - EphyAutocompletion *autocompletion; - EphyAutocompletionWindow *autocompletion_window; - gboolean autocompletion_window_visible; - gint show_alternatives_timeout; - gboolean block_set_autocompletion_key; - gboolean going_to_site; gboolean user_changed; gboolean activation_mode; + EphyNodeDb *combo_db; + EphyNode *combo_root; + char *xml_file; + + guint text_col; + guint action_col; + guint keywords_col; + guint relevance_col; +}; - char *autocompletion_key; - char *last_action_target; +static char *web_prefixes [] = +{ + "http://www.", + "http://", + "https://www.", + "https://", + "www." }; +static int n_web_prefixes = G_N_ELEMENTS (web_prefixes); -#define AUTOCOMPLETION_DELAY 10 -#define SHOW_ALTERNATIVES_DELAY 100 - -/** - * Private functions, only availble from this file - */ -static void ephy_location_entry_class_init (EphyLocationEntryClass *klass); -static void ephy_location_entry_init (EphyLocationEntry *w); -static void ephy_location_entry_finalize_impl (GObject *o); -static void ephy_location_entry_construct_contents (EphyLocationEntry *w); -static gboolean ephy_location_entry_key_press_event_cb (GtkWidget *entry, GdkEventKey *event, - EphyLocationEntry *w); -static void ephy_location_entry_activate_cb (GtkEntry *entry, - EphyLocationEntry *w); -static void ephy_location_entry_autocompletion_sources_changed_cb - (EphyAutocompletion *aw, - EphyLocationEntry *w); -static gint ephy_location_entry_autocompletion_show_alternatives_to (EphyLocationEntry *w); -static void ephy_location_entry_autocompletion_window_url_activated_cb - (EphyAutocompletionWindow *aw, - const gchar *target, - int action, - EphyLocationEntry *w); -static void ephy_location_entry_list_event_after_cb (GtkWidget *list, - GdkEvent *event, - EphyLocationEntry *e); -static void ephy_location_entry_editable_changed_cb (GtkEditable *editable, - EphyLocationEntry *e); -static void ephy_location_entry_set_autocompletion_key (EphyLocationEntry *e); -static void ephy_location_entry_autocompletion_show_alternatives (EphyLocationEntry *w); -static void ephy_location_entry_autocompletion_hide_alternatives (EphyLocationEntry *w); -static void ephy_location_entry_autocompletion_window_hidden_cb - (EphyAutocompletionWindow *aw, - EphyLocationEntry *w); -static void -insert_text_cb (GtkWidget *editable, - char *new_text, - int new_text_length, - int *position, - EphyLocationEntry *w); -static void -delete_text_cb (GtkWidget *editable, - int start_pos, - int end_pos, - EphyLocationEntry *w); +static void ephy_location_entry_class_init (EphyLocationEntryClass *klass); +static void ephy_location_entry_init (EphyLocationEntry *le); +static void ephy_location_entry_finalize (GObject *o); static GObjectClass *parent_class = NULL; -/** - * Signals enums and ids - */ -enum EphyLocationEntrySignalsEnum { - ACTIVATED, +enum EphyLocationEntrySignalsEnum +{ USER_CHANGED, LAST_SIGNAL }; static gint EphyLocationEntrySignals[LAST_SIGNAL]; -#define MENU_ID "ephy-location-entry-menu-id" +enum +{ + LOCATION_HISTORY_NODE_ID = 1 +}; + +enum +{ + EPHY_NODE_LOC_HISTORY_PROP_TEXT = 1 +}; + +#define MAX_LOC_HISTORY_ITEMS 10 +#define EPHY_LOC_HISTORY_XML_ROOT "ephy_location_history" +#define EPHY_LOC_HISTORY_XML_VERSION "0.1" GType ephy_location_entry_get_type (void) @@ -172,20 +144,10 @@ ephy_location_entry_class_init (EphyLocationEntryClass *klass) parent_class = g_type_class_peek_parent (klass); - object_class->finalize = ephy_location_entry_finalize_impl; + object_class->finalize = ephy_location_entry_finalize; tool_item_class->set_tooltip = ephy_location_entry_set_tooltip; - EphyLocationEntrySignals[ACTIVATED] = g_signal_new ( - "activated", G_OBJECT_CLASS_TYPE (klass), - G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST | G_SIGNAL_RUN_CLEANUP, - G_STRUCT_OFFSET (EphyLocationEntryClass, activated), - NULL, NULL, - ephy_marshal_VOID__STRING_STRING, - G_TYPE_NONE, - 2, - G_TYPE_STRING, - G_TYPE_STRING); EphyLocationEntrySignals[USER_CHANGED] = g_signal_new ( "user_changed", G_OBJECT_CLASS_TYPE (klass), G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST | G_SIGNAL_RUN_CLEANUP, @@ -215,78 +177,30 @@ ephy_location_entry_activation_finished (EphyLocationEntry *entry) } static gboolean -location_focus_out_cb (GtkWidget *widget, GdkEventFocus *event, EphyLocationEntry *w) +location_focus_out_cb (GtkWidget *leidget, GdkEventFocus *event, EphyLocationEntry *le) { - ephy_location_entry_activation_finished (w); + ephy_location_entry_activation_finished (le); return FALSE; } static void -ephy_location_entry_init (EphyLocationEntry *w) +editable_changed_cb (GtkEditable *editable, EphyLocationEntry *e) { - EphyLocationEntryPrivate *p; - - LOG ("EphyLocationEntry initialising %p", w) - - p = EPHY_LOCATION_ENTRY_GET_PRIVATE (w); - w->priv = p; - - p->last_action_target = NULL; - p->before_completion = NULL; - p->user_changed = TRUE; - p->activation_mode = FALSE; - p->autocompletion_key = NULL; - p->autocompletion_window_visible = FALSE; - - ephy_location_entry_construct_contents (w); - - gtk_tool_item_set_expand (GTK_TOOL_ITEM (w), TRUE); - - g_signal_connect (w->priv->entry, - "focus_out_event", - G_CALLBACK (location_focus_out_cb), - w); -} - -static void -ephy_location_entry_finalize_impl (GObject *o) -{ - EphyLocationEntry *w = EPHY_LOCATION_ENTRY (o); - EphyLocationEntryPrivate *p = w->priv; + EphyLocationEntryPrivate *p = e->priv; - if (p->autocompletion) + if (p->user_changed) { - g_signal_handlers_disconnect_matched (p->autocompletion, G_SIGNAL_MATCH_DATA, 0, 0, - NULL, NULL, w); - - g_signal_handlers_disconnect_matched (p->autocompletion_window, G_SIGNAL_MATCH_DATA, 0, 0, - NULL, NULL, w); - - g_object_unref (G_OBJECT (p->autocompletion)); - g_object_unref (G_OBJECT (p->autocompletion_window)); + g_signal_emit (e, EphyLocationEntrySignals[USER_CHANGED], 0); } - - LOG ("EphyLocationEntry finalized") - - g_free (p->before_completion); - g_free (p->autocompletion_key); - - G_OBJECT_CLASS (parent_class)->finalize (o); -} - -GtkWidget * -ephy_location_entry_new (void) -{ - return GTK_WIDGET (g_object_new (EPHY_TYPE_LOCATION_ENTRY, NULL)); } static gboolean -ephy_location_entry_button_press_event_cb (GtkWidget *entry, GdkEventButton *event, EphyLocationEntry *w) +entry_button_press_cb (GtkWidget *entry, GdkEventButton *event, EphyLocationEntry *le) { if (event->button == 1 && event->type == GDK_2BUTTON_PRESS) { - ephy_location_entry_activate (w); + ephy_location_entry_activate (le); return TRUE; } @@ -294,513 +208,393 @@ ephy_location_entry_button_press_event_cb (GtkWidget *entry, GdkEventButton *eve } static void -ephy_location_entry_construct_contents (EphyLocationEntry *w) +add_to_history (EphyLocationEntry *le, const char *text) { - EphyLocationEntryPrivate *p = w->priv; - GtkWidget *hbox, *list; - - LOG ("EphyLocationEntry constructing contents %p", w) + GPtrArray *children; + int i, l, n_items, index = -1; + int *order; - hbox = gtk_hbox_new (FALSE, 0); - gtk_container_add (GTK_CONTAINER (w), hbox); - gtk_widget_show (hbox); - - p->combo = gnome_entry_new ("ephy-url-history"); - p->entry = GTK_COMBO (p->combo)->entry; - gtk_widget_show (p->combo); - gtk_box_pack_start (GTK_BOX (hbox), p->combo, TRUE, TRUE, 0); - - g_signal_connect (p->entry, "key-press-event", - G_CALLBACK (ephy_location_entry_key_press_event_cb), w); - g_signal_connect (p->entry, "insert-text", - G_CALLBACK (insert_text_cb), w); - g_signal_connect (p->entry, "delete-text", - G_CALLBACK (delete_text_cb), w); - g_signal_connect (p->entry, "button-press-event", - G_CALLBACK (ephy_location_entry_button_press_event_cb), w); - - g_signal_connect (p->entry, "activate", - G_CALLBACK (ephy_location_entry_activate_cb), w); - - g_signal_connect (p->entry, "changed", - G_CALLBACK (ephy_location_entry_editable_changed_cb), w); - - list = GTK_COMBO (p->combo)->list; + /* check if it already exists */ + children = ephy_node_get_children (le->priv->combo_root); + n_items = children->len; + for (i = 0; i < n_items; i++) + { + EphyNode *kid; + const char *node_text; + + kid = g_ptr_array_index (children, i); + node_text = ephy_node_get_property_string + (kid, EPHY_NODE_LOC_HISTORY_PROP_TEXT); + + if (strcmp (text, node_text) == 0) + { + index = i; + break; + } + } + ephy_node_thaw (le->priv->combo_root); - g_signal_connect_after (list, "event-after", - G_CALLBACK (ephy_location_entry_list_event_after_cb), w); + /* it doesnt exist, add it */ + if (index < 0) + { + GValue value = { 0, }; + EphyNode *node; -} + node = ephy_node_new (le->priv->combo_db); + g_value_init (&value, G_TYPE_STRING); + g_value_set_string (&value, text); + ephy_node_set_property (node, EPHY_NODE_LOC_HISTORY_PROP_TEXT, + &value); -static gboolean -ephy_location_ignore_prefix (EphyLocationEntry *w) -{ - const char *text; - int text_len; - int i, k; - gboolean result = FALSE; - static const gchar *prefixes[] = { - EPHY_AUTOCOMPLETION_USUAL_WEB_PREFIXES, - NULL - }; + if (n_items >= MAX_LOC_HISTORY_ITEMS) + { + EphyNode *last; - text = ephy_location_entry_get_location (w); - g_return_val_if_fail (text != NULL, FALSE); + last = ephy_node_get_nth_child + (le->priv->combo_root, n_items - 1); + ephy_node_remove_child (le->priv->combo_root, last); + } - text_len = g_utf8_strlen (text, -1); + ephy_node_add_child (le->priv->combo_root, node); + } - for (i = 0; prefixes[i] != NULL; i++) + /* move it at the top */ + n_items = ephy_node_get_n_children (le->priv->combo_root); + order = g_new0 (int, n_items); + l = 1; + if (index == -1) index = n_items -1; + for (i = 0; i < n_items; i++) { - const char *prefix = prefixes[i]; - - for (k = 0; k < g_utf8_strlen (prefix, -1); k++) + if (index != i) { - if (text_len == (k + 1) && - (strncmp (text, prefix, k + 1) == 0)) - { - result = TRUE; - } + order[i] = l; + l++; + } + else + { + order[i] = 0; } } - - return result; + ephy_node_reorder_children (le->priv->combo_root, order); + g_free (order); } -static gint -ephy_location_entry_autocompletion_show_alternatives_to (EphyLocationEntry *w) +static void +entry_activate_cb (GtkEntry *entry, EphyLocationEntry *le) { - EphyLocationEntryPrivate *p = w->priv; - - g_free (p->before_completion); - p->before_completion = gtk_editable_get_chars (GTK_EDITABLE (p->entry), 0, -1); - - if (ephy_location_ignore_prefix (w)) return FALSE; + char *content; - if (p->autocompletion) + content = gtk_editable_get_chars (GTK_EDITABLE(entry), 0, -1); + if (content) { - LOG ("Show alternatives") - ephy_location_entry_set_autocompletion_key (w); - ephy_location_entry_autocompletion_show_alternatives (w); + add_to_history (le, content); + g_free (content); } - p->show_alternatives_timeout = 0; - return FALSE; } -static void -ephy_location_entry_autocompletion_hide_alternatives (EphyLocationEntry *w) -{ - EphyLocationEntryPrivate *p = w->priv; - if (p->autocompletion_window) +static gboolean +completion_func (GtkEntryCompletion *completion, + const char *key, + GtkTreeIter *iter, + gpointer data) +{ + int i; + char *item = NULL; + char *keywords = NULL; + char *normalized_string, *normalized_keywords; + char *case_normalized_string, *case_normalized_keywords; + gboolean ret = FALSE; + EphyLocationEntry *le = EPHY_LOCATION_ENTRY (data); + GtkTreeModel *model; + + model = gtk_entry_completion_get_model (completion); + + gtk_tree_model_get (model, iter, + le->priv->text_col, &item, -1); + gtk_tree_model_get (model, iter, + le->priv->keywords_col, &keywords, -1); + + normalized_string = g_utf8_normalize (item, -1, G_NORMALIZE_ALL); + case_normalized_string = g_utf8_casefold (normalized_string, -1); + normalized_keywords = g_utf8_normalize (keywords, -1, G_NORMALIZE_ALL); + case_normalized_keywords = g_utf8_casefold (normalized_keywords, -1); + + if (!strncmp (key, case_normalized_string, strlen (key))) { - ephy_autocompletion_window_hide (p->autocompletion_window); - p->autocompletion_window_visible = FALSE; + ret = TRUE; } - - p->autocompletion_window_visible = FALSE; - - if (p->show_alternatives_timeout) + else if (strstr (case_normalized_keywords, key)) { - g_source_remove (p->show_alternatives_timeout); - p->show_alternatives_timeout = 0; + ret = TRUE; } -} - -static void -ephy_location_entry_autocompletion_show_alternatives (EphyLocationEntry *w) -{ - EphyLocationEntryPrivate *p = w->priv; + else + { + for (i = 0; i < n_web_prefixes; i++) + { + char *key_prefixed; - /* Reset it because if we do a grab on click (like when pasting - text in the location entry, the entry will lose the release - event and will not reset it. It's what gtk does for the entry - popup */ - GTK_ENTRY (p->entry)->button = 0; + key_prefixed = g_strconcat (web_prefixes[i], key, NULL); - if (p->autocompletion_window) - { - ephy_autocompletion_window_show (p->autocompletion_window); - p->autocompletion_window_visible = TRUE; - } -} + if (!strncmp (key_prefixed, case_normalized_string, + strlen (key_prefixed))) + { + ret = TRUE; + break; + } -static void -ephy_location_entry_autocompletion_unselect_alternatives (EphyLocationEntry *w) -{ - EphyLocationEntryPrivate *p = w->priv; - if (p->autocompletion_window) - { - ephy_autocompletion_window_unselect (p->autocompletion_window); + g_free (key_prefixed); + } } -} -static int -get_editable_number_of_chars (GtkEditable *editable) -{ - char *text; - int length; + g_free (item); + g_free (normalized_string); + g_free (case_normalized_string); - text = gtk_editable_get_chars (editable, 0, -1); - length = g_utf8_strlen (text, -1); - g_free (text); - return length; + return ret; } static gboolean -position_is_at_end (GtkEditable *editable) -{ - int end; - - end = get_editable_number_of_chars (editable); - return gtk_editable_get_position (editable) == end; -} - -static void -delete_text_cb (GtkWidget *editable, - int start_pos, - int end_pos, - EphyLocationEntry *w) -{ - ephy_location_entry_autocompletion_hide_alternatives (w); -} - -static void -insert_text_cb (GtkWidget *editable, - char *new_text, - int new_text_length, - int *position, - EphyLocationEntry *w) +match_selected_cb (GtkEntryCompletion *completion, + GtkTreeModel *model, + GtkTreeIter *iter, + EphyLocationEntry *le) { - EphyLocationEntryPrivate *p = w->priv; - GtkWidget *window; + char *item = NULL; - window = gtk_widget_get_toplevel (editable); - g_return_if_fail (window != NULL); - if (!GTK_WINDOW (window)->has_focus) return; + gtk_tree_model_get (model, iter, + le->priv->action_col, &item, -1); - if (p->going_to_site) return; + ephy_location_entry_set_location (le, item); + g_signal_emit_by_name (le->priv->entry, "activate"); - if (p->show_alternatives_timeout != 0) - { - g_source_remove (p->show_alternatives_timeout); - p->show_alternatives_timeout = 0; - } + g_free (item); - ephy_location_entry_autocompletion_unselect_alternatives (w); - if (position_is_at_end (GTK_EDITABLE (editable))) - { - p->show_alternatives_timeout = g_timeout_add - (SHOW_ALTERNATIVES_DELAY, - (GSourceFunc) ephy_location_entry_autocompletion_show_alternatives_to, w); - } + return TRUE; } -static gboolean -ephy_location_entry_key_press_event_cb (GtkWidget *entry, GdkEventKey *event, EphyLocationEntry *w) +static void +ephy_location_entry_construct_contents (EphyLocationEntry *le) { - EphyLocationEntryPrivate *p = w->priv; - GtkWidget *window; + EphyLocationEntryPrivate *p = le->priv; + int combo_text_col; - switch (event->keyval) - { - case GDK_Left: - case GDK_Right: - ephy_location_entry_autocompletion_hide_alternatives (w); - break; - case GDK_Escape: - ephy_location_entry_set_location (w, p->before_completion); - gtk_editable_set_position (GTK_EDITABLE (p->entry), -1); - ephy_location_entry_autocompletion_hide_alternatives (w); - break; - case GDK_Tab: - case GDK_KP_Tab: - if (p->autocompletion_window_visible) - { - ephy_location_entry_autocompletion_hide_alternatives (w); - window = gtk_widget_get_toplevel (entry); - g_signal_emit_by_name (window, "move_focus", 1); - } - break; - default: - break; - } + LOG ("EphyLocationEntry constructing contents %p", le) - return FALSE; -} + p->combo_model = ephy_tree_model_node_new (p->combo_root, NULL); + combo_text_col = ephy_tree_model_node_add_prop_column + (p->combo_model, G_TYPE_STRING, EPHY_NODE_LOC_HISTORY_PROP_TEXT); -static gboolean -ephy_location_entry_content_is_text (const char *content) -{ - return ((g_strrstr (content, ".") == NULL) && - (g_strrstr (content, "/") == NULL) && - (g_strrstr (content, ":") == NULL)); + p->combo = gtk_combo_box_entry_new (GTK_TREE_MODEL (p->combo_model), + combo_text_col); + gtk_container_add (GTK_CONTAINER (le), p->combo); + gtk_widget_show (p->combo); + p->entry = GTK_BIN (p->combo)->child; + + g_signal_connect (p->entry, "button_press_event", + G_CALLBACK (entry_button_press_cb), le); + g_signal_connect (p->entry, "changed", + G_CALLBACK (editable_changed_cb), le); + g_signal_connect (p->entry, "activate", + G_CALLBACK (entry_activate_cb), le); } static void -ephy_location_entry_activate_cb (GtkEntry *entry, EphyLocationEntry *w) +ephy_location_entry_init (EphyLocationEntry *le) { - char *content; - char *target = NULL; + EphyLocationEntryPrivate *p; - content = gtk_editable_get_chars (GTK_EDITABLE(entry), 0, -1); - if (w->priv->last_action_target && - ephy_location_entry_content_is_text (content)) - { - target = g_strdup (w->priv->last_action_target); - } - else - { - target = content; - content = NULL; - g_free ( w->priv->last_action_target); - w->priv->last_action_target = NULL; - } + LOG ("EphyLocationEntry initialising %p", le) - ephy_location_entry_autocompletion_hide_alternatives (w); + p = EPHY_LOCATION_ENTRY_GET_PRIVATE (le); + le->priv = p; - LOG ("In ephy_location_entry_activate_cb, activating %s", content) + p->user_changed = TRUE; + p->activation_mode = FALSE; + p->combo_db = ephy_node_db_new ("NodeDB"); + p->combo_root = ephy_node_new_with_id + (p->combo_db, LOCATION_HISTORY_NODE_ID); + p->xml_file = g_build_filename (ephy_dot_dir (), + "ephy-location-history.xml", + NULL); + ephy_node_db_load_from_file (p->combo_db, p->xml_file, + EPHY_LOC_HISTORY_XML_ROOT, + EPHY_LOC_HISTORY_XML_VERSION); + + ephy_location_entry_construct_contents (le); - g_signal_emit (w, EphyLocationEntrySignals[ACTIVATED], 0, content, target); - ephy_location_entry_activation_finished (w); + gtk_tool_item_set_expand (GTK_TOOL_ITEM (le), TRUE); - g_free (content); - g_free (target); + g_signal_connect (le->priv->entry, + "focus_out_event", + G_CALLBACK (location_focus_out_cb), le); } static void -ephy_location_entry_autocompletion_sources_changed_cb (EphyAutocompletion *aw, - EphyLocationEntry *w) -{ - EphyLocationEntryPrivate *p = w->priv; - - LOG ("in ephy_location_entry_autocompletion_sources_changed_cb") +save_location_history (EphyLocationEntry *le) +{ + xmlDocPtr doc; + xmlNodePtr root; + GPtrArray *children; + int i; + + xmlIndentTreeOutput = TRUE; + + doc = xmlNewDoc ("1.0"); + root = xmlNewDocNode (doc, NULL, EPHY_LOC_HISTORY_XML_ROOT, NULL); + xmlSetProp (root, "version", EPHY_LOC_HISTORY_XML_VERSION); + xmlDocSetRootElement (doc, root); + + children = ephy_node_get_children (le->priv->combo_root); + for (i = 0; i < children->len; i++) + { + EphyNode *kid; + + kid = g_ptr_array_index (children, i); + + ephy_node_save_to_xml (kid, root); + } + ephy_node_thaw (le->priv->combo_root); - if (p->show_alternatives_timeout == 0 - && p->autocompletion_window_visible) - { - p->show_alternatives_timeout = g_timeout_add - (SHOW_ALTERNATIVES_DELAY, - (GSourceFunc) ephy_location_entry_autocompletion_show_alternatives_to, w); - } + ephy_file_save_xml (le->priv->xml_file, doc); + xmlFreeDoc(doc); } -void -ephy_location_entry_set_location (EphyLocationEntry *w, - const gchar *new_location) +static void +ephy_location_entry_finalize (GObject *o) { - EphyLocationEntryPrivate *p = w->priv; - int pos; - - g_return_if_fail (new_location != NULL); - - p->user_changed = FALSE; + EphyLocationEntry *le; + + le = EPHY_LOCATION_ENTRY (o); - g_signal_handlers_block_by_func (G_OBJECT (p->entry), - delete_text_cb, w); - gtk_editable_delete_text (GTK_EDITABLE (p->entry), 0, -1); - g_signal_handlers_unblock_by_func (G_OBJECT (p->entry), - delete_text_cb, w); + save_location_history (le); + g_free (le->priv->xml_file); - g_signal_handlers_block_by_func (G_OBJECT (p->entry), - insert_text_cb, w); - gtk_editable_insert_text (GTK_EDITABLE (p->entry), new_location, strlen(new_location), - &pos); - g_signal_handlers_unblock_by_func (G_OBJECT (p->entry), - insert_text_cb, w); + LOG ("EphyLocationEntry finalized") - p->user_changed = TRUE; + G_OBJECT_CLASS (parent_class)->finalize (o); } -const char * -ephy_location_entry_get_location (EphyLocationEntry *w) +GtkWidget * +ephy_location_entry_new (void) { - return gtk_entry_get_text (GTK_ENTRY (w->priv->entry)); + return GTK_WIDGET (g_object_new (EPHY_TYPE_LOCATION_ENTRY, NULL)); } -static void -ephy_location_entry_autocompletion_window_url_selected_cb (EphyAutocompletionWindow *aw, - const char *target, - int action, - EphyLocationEntry *w) +static gint +sort_func (GtkTreeModel *model, + GtkTreeIter *a, + GtkTreeIter *b, + gpointer data) { - if (target) - { - ephy_location_entry_set_location (w, action ? w->priv->before_completion : target); - } - else - { - ephy_location_entry_set_location (w, w->priv->before_completion); - } + gint valuea, valueb; + EphyLocationEntry *le = EPHY_LOCATION_ENTRY (data); + + gtk_tree_model_get (model, a, + le->priv->relevance_col, &valuea, -1); + gtk_tree_model_get (model, b, + le->priv->relevance_col, &valueb, -1); - gtk_editable_set_position (GTK_EDITABLE (w->priv->entry), -1); + return valueb - valuea; } void -ephy_location_entry_set_autocompletion (EphyLocationEntry *w, - EphyAutocompletion *ac) -{ - EphyLocationEntryPrivate *p = w->priv; - if (p->autocompletion) - { - g_signal_handlers_disconnect_matched (p->autocompletion, G_SIGNAL_MATCH_DATA, 0, 0, - NULL, NULL, w); - - g_signal_handlers_disconnect_matched (p->autocompletion_window, G_SIGNAL_MATCH_DATA, 0, 0, - NULL, NULL, w); - - g_object_unref (G_OBJECT (p->autocompletion)); - g_object_unref (p->autocompletion_window); - } - p->autocompletion = ac; - if (p->autocompletion) - { - g_object_ref (G_OBJECT (p->autocompletion)); - p->autocompletion_window = ephy_autocompletion_window_new (p->autocompletion, - p->entry); - g_signal_connect (p->autocompletion_window, "activated", - G_CALLBACK (ephy_location_entry_autocompletion_window_url_activated_cb), - w); - - g_signal_connect (p->autocompletion_window, "selected", - G_CALLBACK (ephy_location_entry_autocompletion_window_url_selected_cb), - w); - - g_signal_connect (p->autocompletion_window, "hidden", - G_CALLBACK (ephy_location_entry_autocompletion_window_hidden_cb), - w); - - g_signal_connect (p->autocompletion, "sources-changed", - G_CALLBACK (ephy_location_entry_autocompletion_sources_changed_cb), - w); - - ephy_location_entry_set_autocompletion_key (w); - } - +ephy_location_entry_set_completion (EphyLocationEntry *le, + GtkTreeModel *model, + guint text_col, + guint action_col, + guint keywords_col, + guint relevance_col) +{ + GtkTreeModel *sort_model; + GtkEntryCompletion *completion; + GtkCellRenderer *cell; + + le->priv->text_col = text_col; + le->priv->action_col = action_col; + le->priv->keywords_col = keywords_col; + le->priv->relevance_col = relevance_col; + + sort_model = gtk_tree_model_sort_new_with_model (model); + g_object_unref (model); + gtk_tree_sortable_set_default_sort_func + (GTK_TREE_SORTABLE (sort_model), + sort_func, le, NULL); + + completion = gtk_entry_completion_new (); + gtk_entry_completion_set_model (completion, sort_model); + g_object_unref (sort_model); + gtk_entry_completion_set_match_func (completion, completion_func, le, NULL); + g_signal_connect (completion, "match_selected", + G_CALLBACK (match_selected_cb), le); + + cell = gtk_cell_renderer_text_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (completion), + cell, TRUE); + gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (completion), + cell, "text", text_col); + + gtk_entry_set_completion (GTK_ENTRY (le->priv->entry), completion); } -static void -ephy_location_entry_autocompletion_window_url_activated_cb (EphyAutocompletionWindow *aw, - const char *target, - int action, - EphyLocationEntry *w) +void +ephy_location_entry_set_location (EphyLocationEntry *le, + const gchar *new_location) { - char *content; + EphyLocationEntryPrivate *p = le->priv; - if (action) - { - if (w->priv->last_action_target) - g_free (w->priv->last_action_target); - w->priv->last_action_target = g_strdup (target); - } - else - { - ephy_location_entry_set_location (w, target); - } - - content = gtk_editable_get_chars (GTK_EDITABLE(w->priv->entry), 0, -1); - - LOG ("In location_entry_autocompletion_window_url_activated_cb, going to %s", content); + g_return_if_fail (new_location != NULL); - ephy_location_entry_autocompletion_hide_alternatives (w); + p->user_changed = FALSE; - g_signal_emit (w, EphyLocationEntrySignals[ACTIVATED], 0, - action ? content : NULL, target); + gtk_entry_set_text (GTK_ENTRY (p->entry), new_location); - g_free (content); + p->user_changed = TRUE; } -static void -ephy_location_entry_autocompletion_window_hidden_cb (EphyAutocompletionWindow *aw, - EphyLocationEntry *w) +const char * +ephy_location_entry_get_location (EphyLocationEntry *le) { - EphyLocationEntryPrivate *p = w->priv; - - LOG ("In location_entry_autocompletion_window_hidden_cb"); - - p->autocompletion_window_visible = FALSE; - - if (p->show_alternatives_timeout) - { - g_source_remove (p->show_alternatives_timeout); - p->show_alternatives_timeout = 0; - } + return gtk_entry_get_text (GTK_ENTRY (le->priv->entry)); } void -ephy_location_entry_activate (EphyLocationEntry *w) +ephy_location_entry_activate (EphyLocationEntry *le) { GtkWidget *toplevel, *toolbar; - toolbar = gtk_widget_get_ancestor (GTK_WIDGET (w), GTK_TYPE_TOOLBAR); + toolbar = gtk_widget_get_ancestor (GTK_WIDGET (le), GTK_TYPE_TOOLBAR); if (!GTK_WIDGET_VISIBLE (toolbar)) { - w->priv->activation_mode = TRUE; + le->priv->activation_mode = TRUE; gtk_widget_show (toolbar); } - toplevel = gtk_widget_get_toplevel (w->priv->entry); + toplevel = gtk_widget_get_toplevel (le->priv->entry); - gtk_editable_select_region (GTK_EDITABLE(w->priv->entry), + gtk_editable_select_region (GTK_EDITABLE(le->priv->entry), 0, -1); gtk_window_set_focus (GTK_WINDOW(toplevel), - w->priv->entry); -} - -static void -ephy_location_entry_list_event_after_cb (GtkWidget *list, - GdkEvent *event, - EphyLocationEntry *e) -{ - if (event->type == GDK_BUTTON_PRESS - && ((GdkEventButton *) event)->button == 1) - { - e->priv->going_to_site = TRUE; - } + le->priv->entry); } -static void -ephy_location_entry_editable_changed_cb (GtkEditable *editable, EphyLocationEntry *e) +void +ephy_location_entry_clear_history (EphyLocationEntry *le) { - EphyLocationEntryPrivate *p = e->priv; - - ephy_location_entry_set_autocompletion_key (e); - - if (p->going_to_site) + EphyNode *node; + + while ((node = ephy_node_get_nth_child (le->priv->combo_root, 0)) != NULL) { - const char *url = ephy_location_entry_get_location (e); - if (url && url[0] != '\0') - { - p->going_to_site = FALSE; - g_signal_emit (e, EphyLocationEntrySignals[ACTIVATED], 0, NULL, url); - } + ephy_node_unref (node); } - if (p->user_changed) - { - g_signal_emit (e, EphyLocationEntrySignals[USER_CHANGED], 0); - } + save_location_history (le); } -static void -ephy_location_entry_set_autocompletion_key (EphyLocationEntry *e) +GtkWidget * +ephy_location_entry_get_entry (EphyLocationEntry *le) { - EphyLocationEntryPrivate *p = e->priv; - if (p->autocompletion && !p->block_set_autocompletion_key) - { - GtkEditable *editable = GTK_EDITABLE (p->entry); - gint sstart, send; - gchar *text; - gtk_editable_get_selection_bounds (editable, &sstart, &send); - text = gtk_editable_get_chars (editable, 0, sstart); - ephy_autocompletion_set_key (p->autocompletion, text); - g_free (p->autocompletion_key); - p->autocompletion_key = text; - } + return le->priv->entry; } -void -ephy_location_entry_clear_history (EphyLocationEntry *w) -{ - gnome_entry_clear_history (GNOME_ENTRY (w->priv->combo)); -} |