From 890b0f0278c284b3f72b17b2a320d7f443683d77 Mon Sep 17 00:00:00 2001 From: Marco Pesenti Gritti Date: Sat, 11 Oct 2003 17:41:26 +0000 Subject: Merge completion branch --- lib/widgets/ephy-location-entry.c | 876 +++++++++++++++----------------------- 1 file changed, 335 insertions(+), 541 deletions(-) (limited to 'lib/widgets/ephy-location-entry.c') 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 -#include +#include +#include +#include #include #include -#include -#include -#include -#include -#include +#include +#include +#include #include -/** - * 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)); -} -- cgit v1.2.3