From 87092babefbc0e8ea4925da9f54e055d6ce62c8e Mon Sep 17 00:00:00 2001 From: Christian Dywan Date: Sun, 9 Nov 2008 19:09:35 +0100 Subject: [PATCH] Move completion logic from LocationEntry to LocationAction This resolves various indirections, and since we are always using the action anyway, we finally move all logic to one place. There should be room for optimizations now. Incidentally this also keeps the completion intact if the entry needs to be recreated. --- midori/midori-locationaction.c | 755 ++++++++++++++++++++++++++++----- midori/midori-locationaction.h | 7 + midori/midori-locationentry.c | 703 +----------------------------- midori/midori-locationentry.h | 44 -- 4 files changed, 655 insertions(+), 854 deletions(-) diff --git a/midori/midori-locationaction.c b/midori/midori-locationaction.c index 90d1ae46..a0940758 100644 --- a/midori/midori-locationaction.c +++ b/midori/midori-locationaction.c @@ -1,5 +1,6 @@ /* Copyright (C) 2008 Christian Dywan + Copyright (C) 2008 Dale Whittaker This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -12,10 +13,14 @@ #include "midori-locationaction.h" #include "gtkiconentry.h" +#include "sokoke.h" +#include #include #include +#define MAX_ITEMS 25 + struct _MidoriLocationAction { GtkAction parent_instance; @@ -24,6 +29,9 @@ struct _MidoriLocationAction gdouble progress; GtkTreeModel* model; + GtkTreeModel* filter_model; + GtkTreeModel* sort_model; + GdkPixbuf* default_icon; }; struct _MidoriLocationActionClass @@ -53,6 +61,16 @@ enum static guint signals[LAST_SIGNAL]; +enum +{ + FAVICON_COL, + URI_COL, + TITLE_COL, + VISITS_COL, + VISIBLE_COL, + N_COLS +}; + static void midori_location_action_finalize (GObject* object); @@ -199,10 +217,27 @@ midori_location_action_class_init (MidoriLocationActionClass* class) static void midori_location_action_init (MidoriLocationAction* location_action) { + GtkTreeModel* liststore; + GtkTreeModel* sort_model; + GtkTreeModel* filter_model; + location_action->uri = NULL; location_action->progress = 0.0; - location_action->model = NULL; + liststore = (GtkTreeModel*)gtk_list_store_new (N_COLS, + GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING, + G_TYPE_INT, G_TYPE_BOOLEAN); + sort_model = (GtkTreeModel*)gtk_tree_model_sort_new_with_model (liststore); + gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sort_model), + VISITS_COL, GTK_SORT_DESCENDING); + filter_model = gtk_tree_model_filter_new (sort_model, NULL); + gtk_tree_model_filter_set_visible_column ( + GTK_TREE_MODEL_FILTER (filter_model), VISIBLE_COL); + + location_action->model = liststore; + location_action->filter_model = filter_model; + location_action->sort_model = sort_model; + location_action->default_icon = NULL; } static void @@ -210,9 +245,12 @@ midori_location_action_finalize (GObject* object) { MidoriLocationAction* location_action = MIDORI_LOCATION_ACTION (object); - g_free (location_action->uri); + katze_assign (location_action->uri, NULL); katze_object_assign (location_action->model, NULL); + katze_object_assign (location_action->sort_model, NULL); + katze_object_assign (location_action->filter_model, NULL); + katze_object_assign (location_action->default_icon, NULL); G_OBJECT_CLASS (midori_location_action_parent_class)->finalize (object); } @@ -228,17 +266,13 @@ midori_location_action_set_property (GObject* object, switch (prop_id) { case PROP_PROGRESS: - { midori_location_action_set_progress (location_action, g_value_get_double (value)); break; - } case PROP_SECONDARY_ICON: - { midori_location_action_set_secondary_icon (location_action, g_value_get_string (value)); break; - } default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -276,20 +310,16 @@ static GtkWidget* midori_location_action_create_tool_item (GtkAction* action) { GtkWidget* toolitem; - GtkWidget* entry; + GtkWidget* location_entry; GtkWidget* alignment; toolitem = GTK_WIDGET (gtk_tool_item_new ()); gtk_tool_item_set_expand (GTK_TOOL_ITEM (toolitem), TRUE); - entry = midori_location_entry_new (); - midori_location_entry_set_progress (MIDORI_LOCATION_ENTRY (entry), - MIDORI_LOCATION_ACTION (action)->progress); - gtk_icon_entry_set_icon_highlight (GTK_ICON_ENTRY ( - gtk_bin_get_child (GTK_BIN (entry))), - GTK_ICON_ENTRY_SECONDARY, TRUE); + location_entry = midori_location_entry_new (); + alignment = gtk_alignment_new (0, 0.5, 1, 0.1); - gtk_container_add (GTK_CONTAINER (alignment), entry); - gtk_widget_show (entry); + gtk_container_add (GTK_CONTAINER (alignment), location_entry); + gtk_widget_show (location_entry); gtk_container_add (GTK_CONTAINER (toolitem), alignment); gtk_widget_show (alignment); @@ -297,15 +327,17 @@ midori_location_action_create_tool_item (GtkAction* action) } static void -midori_location_action_active_changed_cb (GtkWidget* widget, +midori_location_action_active_changed_cb (GtkWidget* location_entry, gint active, GtkAction* action) { MidoriLocationAction* location_action; + GtkWidget* entry; const gchar* text; location_action = MIDORI_LOCATION_ACTION (action); - text = midori_location_entry_get_text (MIDORI_LOCATION_ENTRY (widget)); + entry = gtk_bin_get_child (GTK_BIN (location_entry)); + text = gtk_entry_get_text (GTK_ENTRY (entry)); katze_assign (location_action->uri, g_strdup (text)); g_signal_emit (action, signals[ACTIVE_CHANGED], 0, active); @@ -359,6 +391,397 @@ midori_location_action_icon_released_cb (GtkWidget* widget, g_signal_emit (action, signals[SECONDARY_ICON_RELEASED], 0, widget); } +static void +midori_location_entry_render_pixbuf_cb (GtkCellLayout* layout, + GtkCellRenderer* renderer, + GtkTreeModel* model, + GtkTreeIter* iter, + gpointer data) +{ + GdkPixbuf* pixbuf; + + gtk_tree_model_get (model, iter, FAVICON_COL, &pixbuf, -1); + if (pixbuf) + { + g_object_set (renderer, "pixbuf", pixbuf, "yalign", 0.25, NULL); + g_object_unref (pixbuf); + } +} + +static void +midori_location_entry_render_text_cb (GtkCellLayout* layout, + GtkCellRenderer* renderer, + GtkTreeModel* model, + GtkTreeIter* iter, + gpointer data) +{ + gchar* uri; + gchar* title; + gchar* desc; + gchar* desc_uri; + gchar* desc_title; + GtkWidget* entry; + gchar* key; + gchar* temp; + gchar** parts; + + gtk_tree_model_get (model, iter, URI_COL, &uri, TITLE_COL, &title, -1); + + desc_uri = desc_title = key = NULL; + if (data) + { + entry = gtk_entry_completion_get_entry (GTK_ENTRY_COMPLETION (data)); + key = g_utf8_strdown (gtk_entry_get_text (GTK_ENTRY (entry)), -1); + } + if (data && uri) + { + temp = g_utf8_strdown (uri, -1); + parts = g_strsplit (temp, key, 2); + g_free (temp); + if (parts && parts[0] && parts[1]) + desc_uri = g_markup_printf_escaped ("%s%s%s", + parts[0], key, parts[1]); + g_strfreev (parts); + } + if (uri && !desc_uri) + desc_uri = g_markup_escape_text (uri, -1); + if (data && title) + { + temp = g_utf8_strdown (title, -1); + parts = g_strsplit (temp, key, 2); + g_free (temp); + if (parts && parts[0] && parts[1]) + desc_title = g_markup_printf_escaped ("%s%s%s", + parts[0], key, parts[1]); + g_strfreev (parts); + } + if (title && !desc_title) + desc_title = g_markup_escape_text (title, -1); + + if (desc_title) + desc = g_strdup_printf ("%s\n%s", + desc_title, desc_uri); + else + desc = g_strdup_printf ("%s", desc_uri); + + g_object_set (renderer, "markup", desc, + "ellipsize-set", TRUE, "ellipsize", PANGO_ELLIPSIZE_END, NULL); + + g_free (uri); + g_free (title); + g_free (key); + g_free (desc); + g_free (desc_uri); + g_free (desc_title); +} + +static gboolean +midori_location_entry_completion_match_cb (GtkEntryCompletion* completion, + const gchar* key, + GtkTreeIter* iter, + gpointer data) +{ + GtkTreeModel* model; + gchar* uri; + gchar* title; + gboolean match; + gchar* temp; + + model = gtk_entry_completion_get_model (completion); + gtk_tree_model_get (model, iter, URI_COL, &uri, TITLE_COL, &title, -1); + + match = FALSE; + if (uri) + { + temp = g_utf8_casefold (uri, -1); + match = (strstr (temp, key) != NULL); + g_free (temp); + g_free (uri); + + if (!match && title) + { + temp = g_utf8_casefold (title, -1); + match = (strstr (temp, key) != NULL); + g_free (temp); + g_free (title); + } + } + + return match; +} + +static void +midori_location_action_set_item (MidoriLocationAction* location_action, + GtkTreeIter* iter, + MidoriLocationEntryItem* item) +{ + GtkTreeModel* model; + GdkPixbuf* icon; + GdkPixbuf* new_icon; + + model = location_action->model; + gtk_list_store_set (GTK_LIST_STORE (model), iter, + URI_COL, item->uri, TITLE_COL, item->title, -1); + + gtk_tree_model_get (model, iter, FAVICON_COL, &icon, -1); + if (item->favicon) + new_icon = item->favicon; + else if (!icon && !item->favicon) + new_icon = location_action->default_icon; + else + new_icon = NULL; + if (new_icon) + gtk_list_store_set (GTK_LIST_STORE (model), iter, + FAVICON_COL, new_icon, -1); +} + +static gboolean +midori_location_action_child_iter_to_iter (MidoriLocationAction* location_action, + GtkTreeIter* iter, + GtkTreeIter* child_iter) +{ + GtkTreeModel* filter_model; + GtkTreeModel* sort_model; + GtkTreeIter sort_iter; + GtkTreeIter* temp_iter; + + temp_iter = child_iter; + + filter_model = location_action->filter_model; + sort_model = location_action->sort_model; + gtk_tree_model_sort_convert_child_iter_to_iter + (GTK_TREE_MODEL_SORT (sort_model), &sort_iter, child_iter); + temp_iter = &sort_iter; + + return gtk_tree_model_filter_convert_child_iter_to_iter + (GTK_TREE_MODEL_FILTER (filter_model), iter, temp_iter); +} + +static void +midori_location_action_set_active_iter (MidoriLocationAction* location_action, + GtkTreeIter* iter) +{ + GdkPixbuf* pixbuf; + GtkTreeModel* model; + GSList* proxies; + GtkWidget* alignment; + GtkWidget* location_entry; + GtkWidget* entry; + GtkTreeIter parent_iter; + + model = location_action->filter_model; + + /* The filter iter must be set, not the child iter, + * but the row must first be set as visible to + * convert to a filter iter without error. + */ + gtk_list_store_set (GTK_LIST_STORE (model), iter, VISIBLE_COL, TRUE, -1); + + proxies = gtk_action_get_proxies (GTK_ACTION (location_action)); + if (!proxies) + return; + + do + if (GTK_IS_TOOL_ITEM (proxies->data)) + { + alignment = gtk_bin_get_child (GTK_BIN (proxies->data)); + location_entry = gtk_bin_get_child (GTK_BIN (alignment)); + entry = gtk_bin_get_child (GTK_BIN (location_entry)); + + if (midori_location_action_child_iter_to_iter ( + location_action, &parent_iter, iter)) + gtk_combo_box_set_active_iter (GTK_COMBO_BOX (location_entry), + &parent_iter); + + /* When setting the active iter (when adding or setting an item) + * the icon may have changed, so we must update the entry icon. + */ + gtk_tree_model_get (model, iter, FAVICON_COL, &pixbuf, -1); + + gtk_icon_entry_set_icon_from_pixbuf (GTK_ICON_ENTRY (entry), + GTK_ICON_ENTRY_PRIMARY, pixbuf); + g_object_unref (pixbuf); + } + while ((proxies = g_slist_next (proxies))); +} + +/** + * midori_location_action_item_iter: + * @location_action: a #MidoriLocationAction + * @uri: a string + * @iter: a GtkTreeIter + * + * Retrieves the iter of the item matching @uri. + * + * Return value: %TRUE if @uri was found, %FALSE otherwise + **/ +static gboolean +midori_location_action_item_iter (MidoriLocationAction* location_action, + const gchar* uri, + GtkTreeIter* iter) +{ + GtkTreeModel* model; + gchar* tmpuri; + gboolean found; + + g_return_val_if_fail (MIDORI_IS_LOCATION_ACTION (location_action), FALSE); + g_return_val_if_fail (uri != NULL, FALSE); + + found = FALSE; + model = location_action->model; // filter_model + if (gtk_tree_model_get_iter_first (model, iter)) + { + tmpuri = NULL; + do + { + gtk_tree_model_get (model, iter, URI_COL, &tmpuri, -1); + found = !g_ascii_strcasecmp (uri, tmpuri); + katze_assign (tmpuri, NULL); + + if (found) + break; + } + while (gtk_tree_model_iter_next (model, iter)); + } + return found; +} + +/** + * midori_location_action_reset: + * @location_action: a #MidoriLocationAction + * + * Clears the text in the entry and resets the icon. + **/ +static void +midori_location_action_reset (MidoriLocationAction* location_action) +{ + GSList* proxies; + GtkWidget* alignment; + GtkWidget* location_entry; + GtkWidget* entry; + + g_return_if_fail (MIDORI_IS_LOCATION_ACTION (location_action)); + + proxies = gtk_action_get_proxies (GTK_ACTION (location_action)); + if (!proxies) + return; + + do + if (GTK_IS_TOOL_ITEM (proxies->data)) + { + alignment = gtk_bin_get_child (GTK_BIN (proxies->data)); + location_entry = gtk_bin_get_child (GTK_BIN (alignment)); + entry = gtk_bin_get_child (GTK_BIN (location_entry)); + + gtk_entry_set_text (GTK_ENTRY (entry), ""); + gtk_icon_entry_set_icon_from_stock (GTK_ICON_ENTRY (entry), + GTK_ICON_ENTRY_PRIMARY, GTK_STOCK_FILE); + } + while ((proxies = g_slist_next (proxies))); +} + +/** + * midori_location_action_set_item_from_uri: + * @location_action: a #MidoriLocationAction + * @uri: a string + * + * Finds the item from the list matching @uri + * and sets it as the active item. + * If @uri is not found it clears the active item. + **/ +static void +midori_location_action_set_item_from_uri (MidoriLocationAction* location_action, + const gchar* uri) +{ + GtkTreeIter iter; + + g_return_if_fail (MIDORI_IS_LOCATION_ACTION (location_action)); + + if (midori_location_action_item_iter (location_action, uri, &iter)) + midori_location_action_set_active_iter (location_action, &iter); + else + midori_location_action_reset (location_action); + +} + +static gboolean +midori_location_entry_completion_selected (GtkEntryCompletion* completion, + GtkTreeModel* model, + GtkTreeIter* iter, + MidoriLocationAction* location_action) +{ + gchar* uri; + + gtk_tree_model_get (model, iter, URI_COL, &uri, -1); + midori_location_action_set_item_from_uri (location_action, uri); + g_free (uri); + + return FALSE; +} + +static void +midori_location_action_completion_init (MidoriLocationAction* location_action, + GtkWidget* location_entry) +{ + GtkWidget* entry; + GtkEntryCompletion* completion; + GtkCellRenderer* renderer; + + entry = gtk_bin_get_child (GTK_BIN (location_entry)); + completion = gtk_entry_completion_new (); + + gtk_entry_completion_set_model (completion, location_action->sort_model); + gtk_entry_completion_set_text_column (completion, URI_COL); + gtk_cell_layout_clear (GTK_CELL_LAYOUT (completion)); + + renderer = gtk_cell_renderer_pixbuf_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (completion), renderer, FALSE); + gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (completion), renderer, + midori_location_entry_render_pixbuf_cb, + NULL, NULL); + renderer = gtk_cell_renderer_text_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (completion), renderer, TRUE); + gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (completion), renderer, + midori_location_entry_render_text_cb, + completion, NULL); + gtk_entry_completion_set_match_func (completion, + midori_location_entry_completion_match_cb, NULL, NULL); + + gtk_entry_set_completion (GTK_ENTRY (entry), completion); + g_signal_connect (completion, "match-selected", + G_CALLBACK (midori_location_entry_completion_selected), location_entry); + + g_object_unref (completion); +} + +static void +midori_location_action_entry_changed_cb (GtkComboBox* combo_box, + MidoriLocationAction* location_action) +{ + GtkTreeIter iter; + GtkIconEntry* entry; + GtkTreeModel* model; + GdkPixbuf* pixbuf; + + if (gtk_combo_box_get_active_iter (combo_box, &iter)) + { + if ((entry = GTK_ICON_ENTRY (gtk_bin_get_child (GTK_BIN (combo_box))))) + { + pixbuf = NULL; + + model = location_action->filter_model; + gtk_tree_model_get (model, &iter, FAVICON_COL, &pixbuf, -1); + + gtk_icon_entry_set_icon_from_pixbuf (GTK_ICON_ENTRY (entry), + GTK_ICON_ENTRY_PRIMARY, pixbuf); + g_object_unref (pixbuf); + + g_signal_emit (MIDORI_LOCATION_ENTRY (combo_box), + signals[ACTIVE_CHANGED], 0, gtk_combo_box_get_active (combo_box)); + } + } +} + static void midori_location_action_connect_proxy (GtkAction* action, GtkWidget* proxy) @@ -366,6 +789,7 @@ midori_location_action_connect_proxy (GtkAction* action, GtkWidget* alignment; GtkWidget* entry; MidoriLocationAction* location_action; + GtkCellRenderer* renderer; GTK_ACTION_CLASS (midori_location_action_parent_class)->connect_proxy ( action, proxy); @@ -376,14 +800,30 @@ midori_location_action_connect_proxy (GtkAction* action, entry = gtk_bin_get_child (GTK_BIN (alignment)); location_action = MIDORI_LOCATION_ACTION (action); - if (location_action->model) - gtk_combo_box_set_model (GTK_COMBO_BOX (entry), - location_action->model); - else - location_action->model = g_object_ref (gtk_combo_box_get_model ( - GTK_COMBO_BOX (entry))); + midori_location_entry_set_progress (MIDORI_LOCATION_ENTRY (entry), + MIDORI_LOCATION_ACTION (action)->progress); + gtk_combo_box_set_model (GTK_COMBO_BOX (entry), + MIDORI_LOCATION_ACTION (action)->filter_model); + gtk_combo_box_entry_set_text_column ( + GTK_COMBO_BOX_ENTRY (entry), URI_COL); + gtk_cell_layout_clear (GTK_CELL_LAYOUT (entry)); - g_signal_connect (entry, "active-changed", + /* Setup the renderer for the favicon */ + renderer = gtk_cell_renderer_pixbuf_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (entry), renderer, FALSE); + gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (entry), + renderer, midori_location_entry_render_pixbuf_cb, NULL, NULL); + renderer = gtk_cell_renderer_text_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (entry), renderer, TRUE); + gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (entry), + renderer, midori_location_entry_render_text_cb, NULL, NULL); + + gtk_combo_box_set_active (GTK_COMBO_BOX (entry), -1); + midori_location_action_completion_init (location_action, entry); + g_signal_connect (entry, "changed", + G_CALLBACK (midori_location_action_entry_changed_cb), action); + + g_signal_connect (location_action, "active-changed", G_CALLBACK (midori_location_action_active_changed_cb), action); g_object_connect (gtk_bin_get_child (GTK_BIN (entry)), "signal::key-press-event", @@ -416,18 +856,26 @@ midori_location_action_get_uri (MidoriLocationAction* location_action) return location_action->uri; } -void -midori_location_action_set_uri (MidoriLocationAction* location_action, - const gchar* uri) +/** + * midori_location_action_set_text: + * @location_action: a #MidoriLocationAction + * @text: a string + * + * Sets the entry text to @text and, if applicable, updates the icon. + **/ +static void +midori_location_action_set_text (MidoriLocationAction* location_action, + const gchar* text) { GSList* proxies; GtkWidget* alignment; + GtkWidget* location_entry; GtkWidget* entry; + GtkTreeIter iter; + GtkTreeModel* model; + GdkPixbuf* icon; g_return_if_fail (MIDORI_IS_LOCATION_ACTION (location_action)); - g_return_if_fail (uri != NULL); - - katze_assign (location_action->uri, g_strdup (uri)); proxies = gtk_action_get_proxies (GTK_ACTION (location_action)); if (!proxies) @@ -437,20 +885,128 @@ midori_location_action_set_uri (MidoriLocationAction* location_action, if (GTK_IS_TOOL_ITEM (proxies->data)) { alignment = gtk_bin_get_child (GTK_BIN (proxies->data)); - entry = gtk_bin_get_child (GTK_BIN (alignment)); + location_entry = gtk_bin_get_child (GTK_BIN (alignment)); + entry = gtk_bin_get_child (GTK_BIN (location_entry)); - midori_location_entry_set_text (MIDORI_LOCATION_ENTRY (entry), uri); + gtk_entry_set_text (GTK_ENTRY (entry), text); + if (midori_location_action_item_iter (location_action, text, &iter)) + { + model = location_action->model; // filter_model + gtk_tree_model_get (model, &iter, FAVICON_COL, &icon, -1); + gtk_icon_entry_set_icon_from_pixbuf (GTK_ICON_ENTRY (entry), + GTK_ICON_ENTRY_PRIMARY, icon); + } + /* FIXME: Due to a bug in GtkIconEntry we can't reset the icon + else + gtk_icon_entry_set_icon_from_stock (GTK_ICON_ENTRY (entry), + GTK_ICON_ENTRY_PRIMARY, location_action->default_icon);*/ } while ((proxies = g_slist_next (proxies))); } +void +midori_location_action_set_uri (MidoriLocationAction* location_action, + const gchar* uri) +{ + g_return_if_fail (MIDORI_IS_LOCATION_ACTION (location_action)); + g_return_if_fail (uri != NULL); + + katze_assign (location_action->uri, g_strdup (uri)); + + midori_location_action_set_text (location_action, uri); +} + +/** + * midori_location_action_prepend_item: + * @location_action: a #MidoriLocationAction + * @item: a MidoriLocationItem + * + * Prepends @item if it is not already in the list. + * If the item already exists, it is moved before the first item. + * If the maximum is reached, the last item is removed. + **/ +static void +midori_location_action_prepend_item (MidoriLocationAction* location_action, + MidoriLocationEntryItem* item) +{ + GtkTreeModel* filter_model; + GtkTreeModel* model; + GtkTreeIter iter; + GtkTreeIter index; + gint n; + gint visits = 0; + + g_return_if_fail (MIDORI_IS_LOCATION_ACTION (location_action)); + g_return_if_fail (item->uri != NULL); + + filter_model = location_action->filter_model; + model = location_action->model; + + if (midori_location_action_item_iter (location_action, item->uri, &iter)) + { + gtk_tree_model_get_iter_first (model, &index); + gtk_tree_model_get (model, &iter, VISITS_COL, &visits, -1); + gtk_list_store_move_before (GTK_LIST_STORE (model), &iter, &index); + } + else + gtk_list_store_prepend (GTK_LIST_STORE (model), &iter); + + n = gtk_tree_model_iter_n_children (filter_model, NULL); + if (n > MAX_ITEMS) + { + gtk_tree_model_iter_nth_child (model, &index, NULL, n - 1); + gtk_list_store_set (GTK_LIST_STORE (model), + &index, VISIBLE_COL, FALSE, -1); + } + + /* Only increment the visits when we add the uri */ + if (!item->title && !item->favicon) + gtk_list_store_set (GTK_LIST_STORE (model), &iter, VISITS_COL, ++visits, + VISIBLE_COL, TRUE, -1); + midori_location_action_set_item (location_action, &iter, item); +} + +/** + * midori_location_entry_append_item: + * @location_entry: a #MidoriLocationEntry + * @item: a MidoriLocationItem + * + * Appends @item if it is not already in the list. + * @item is not added if the maximum is reached. + **/ +static void +midori_location_action_append_item (MidoriLocationAction* location_action, + MidoriLocationEntryItem* item) +{ + GtkTreeModel* model; + GtkTreeIter iter; + gint n; + gint visits = 0; + + g_return_if_fail (MIDORI_IS_LOCATION_ACTION (location_action)); + g_return_if_fail (item->uri != NULL); + + model = location_action->model; + + if (!midori_location_action_item_iter (location_action, item->uri, &iter)) + { + gtk_list_store_append (GTK_LIST_STORE (model), &iter); + + n = gtk_tree_model_iter_n_children (model, NULL); + gtk_list_store_set (GTK_LIST_STORE (model), &iter, VISIBLE_COL, + (n <= MAX_ITEMS), -1); + } + else + gtk_tree_model_get (model, &iter, VISITS_COL, &visits, -1); + + gtk_list_store_set (GTK_LIST_STORE (model), &iter, VISITS_COL, ++visits, -1); + midori_location_action_set_item (location_action, &iter, item); +} + void midori_location_action_add_uri (MidoriLocationAction* location_action, const gchar* uri) { - GSList* proxies; - GtkWidget* alignment; - GtkWidget* entry; MidoriLocationEntryItem item; g_return_if_fail (MIDORI_IS_LOCATION_ACTION (location_action)); @@ -458,23 +1014,10 @@ midori_location_action_add_uri (MidoriLocationAction* location_action, katze_assign (location_action->uri, g_strdup (uri)); - proxies = gtk_action_get_proxies (GTK_ACTION (location_action)); - if (!proxies) - return; - - do - if (GTK_IS_TOOL_ITEM (proxies->data)) - { - alignment = gtk_bin_get_child (GTK_BIN (proxies->data)); - entry = gtk_bin_get_child (GTK_BIN (alignment)); - - item.favicon = NULL; - item.uri = uri; - item.title = NULL; - midori_location_entry_prepend_item ( - MIDORI_LOCATION_ENTRY (entry), &item); - } - while ((proxies = g_slist_next (proxies))); + item.favicon = NULL; + item.uri = uri; + item.title = NULL; + midori_location_action_prepend_item (location_action, &item); } void @@ -485,8 +1028,8 @@ midori_location_action_add_item (MidoriLocationAction* location_action, { GSList* proxies; GtkWidget* alignment; + GtkWidget* location_entry; GtkWidget* entry; - GtkWidget* child; MidoriLocationEntryItem item; g_return_if_fail (MIDORI_IS_LOCATION_ACTION (location_action)); @@ -496,25 +1039,25 @@ midori_location_action_add_item (MidoriLocationAction* location_action, katze_assign (location_action->uri, g_strdup (uri)); + item.favicon = icon; + item.uri = uri; + item.title = title; + midori_location_action_append_item (location_action, &item); + proxies = gtk_action_get_proxies (GTK_ACTION (location_action)); if (!proxies) return; do - if (GTK_IS_TOOL_ITEM (proxies->data)) + if (GTK_IS_TOOL_ITEM (proxies->data) && + !g_strcmp0 (location_action->uri, uri)) { alignment = gtk_bin_get_child (GTK_BIN (proxies->data)); - entry = gtk_bin_get_child (GTK_BIN (alignment)); - child = gtk_bin_get_child (GTK_BIN (entry)); + location_entry = gtk_bin_get_child (GTK_BIN (alignment)); + entry = gtk_bin_get_child (GTK_BIN (location_entry)); - item.favicon = icon; - item.uri = uri; - item.title = title; - midori_location_entry_append_item ( - MIDORI_LOCATION_ENTRY (entry), &item); - if (!g_strcmp0 (location_action->uri, uri)) - gtk_icon_entry_set_icon_from_pixbuf (GTK_ICON_ENTRY (child), - GTK_ICON_ENTRY_PRIMARY, icon); + gtk_icon_entry_set_icon_from_pixbuf (GTK_ICON_ENTRY (entry), + GTK_ICON_ENTRY_PRIMARY, icon); } while ((proxies = g_slist_next (proxies))); } @@ -526,33 +1069,33 @@ midori_location_action_set_icon_for_uri (MidoriLocationAction* location_action, { GSList* proxies; GtkWidget* alignment; + GtkWidget* location_entry; GtkWidget* entry; - GtkWidget* child; MidoriLocationEntryItem item; g_return_if_fail (MIDORI_IS_LOCATION_ACTION (location_action)); g_return_if_fail (!icon || GDK_IS_PIXBUF (icon)); g_return_if_fail (uri != NULL); + item.favicon = icon; + item.uri = uri; + item.title = NULL; + midori_location_action_prepend_item (location_action, &item); + proxies = gtk_action_get_proxies (GTK_ACTION (location_action)); if (!proxies) return; do - if (GTK_IS_TOOL_ITEM (proxies->data)) + if (GTK_IS_TOOL_ITEM (proxies->data) && + !g_strcmp0 (location_action->uri, uri)) { alignment = gtk_bin_get_child (GTK_BIN (proxies->data)); - entry = gtk_bin_get_child (GTK_BIN (alignment)); - child = gtk_bin_get_child (GTK_BIN (entry)); + location_entry = gtk_bin_get_child (GTK_BIN (alignment)); + entry = gtk_bin_get_child (GTK_BIN (location_entry)); - item.favicon = icon; - item.uri = uri; - item.title = NULL; - midori_location_entry_prepend_item ( - MIDORI_LOCATION_ENTRY (entry), &item); - if (!g_strcmp0 (location_action->uri, uri)) - gtk_icon_entry_set_icon_from_pixbuf (GTK_ICON_ENTRY (child), - GTK_ICON_ENTRY_PRIMARY, icon); + gtk_icon_entry_set_icon_from_pixbuf (GTK_ICON_ENTRY (entry), + GTK_ICON_ENTRY_PRIMARY, icon); } while ((proxies = g_slist_next (proxies))); } @@ -562,32 +1105,16 @@ midori_location_action_set_title_for_uri (MidoriLocationAction* location_action, const gchar* title, const gchar* uri) { - GSList* proxies; - GtkWidget* alignment; - GtkWidget* entry; MidoriLocationEntryItem item; g_return_if_fail (MIDORI_IS_LOCATION_ACTION (location_action)); g_return_if_fail (title != NULL); g_return_if_fail (uri != NULL); - proxies = gtk_action_get_proxies (GTK_ACTION (location_action)); - if (!proxies) - return; - - do - if (GTK_IS_TOOL_ITEM (proxies->data)) - { - alignment = gtk_bin_get_child (GTK_BIN (proxies->data)); - entry = gtk_bin_get_child (GTK_BIN (alignment)); - - item.favicon = NULL; - item.uri = uri; - item.title = title; - midori_location_entry_prepend_item ( - MIDORI_LOCATION_ENTRY (entry), &item); - } - while ((proxies = g_slist_next (proxies))); + item.favicon = NULL; + item.uri = uri; + item.title = title; + midori_location_action_prepend_item (location_action, &item); } gdouble @@ -660,31 +1187,35 @@ midori_location_action_set_secondary_icon (MidoriLocationAction* location_action while ((proxies = g_slist_next (proxies))); } +/** + * midori_location_entry_set_item_from_uri: + * @location_entry: a #MidoriLocationEntry + * @uri: a string + * + * Finds the item from the list matching @uri + * and removes it if it is the last instance. + **/ void midori_location_action_delete_item_from_uri (MidoriLocationAction* location_action, const gchar* uri) { - GSList* proxies; - GtkWidget* alignment; - GtkWidget* entry; + GtkTreeModel* model; + GtkTreeIter iter; + gint visits; g_return_if_fail (MIDORI_IS_LOCATION_ACTION (location_action)); g_return_if_fail (uri != NULL); - proxies = gtk_action_get_proxies (GTK_ACTION (location_action)); - if (!proxies) - return; - - do - if (GTK_IS_TOOL_ITEM (proxies->data)) + model = location_action->model; + if (midori_location_action_item_iter (location_action, uri, &iter)) { - alignment = gtk_bin_get_child (GTK_BIN (proxies->data)); - entry = gtk_bin_get_child (GTK_BIN (alignment)); - - midori_location_entry_delete_item_from_uri - (MIDORI_LOCATION_ENTRY (entry), uri); + gtk_tree_model_get (model, &iter, VISITS_COL, &visits, -1); + if (visits > 1) + gtk_list_store_set (GTK_LIST_STORE (model), + &iter, VISITS_COL, --visits, -1); + else + gtk_list_store_remove (GTK_LIST_STORE (model), &iter); } - while ((proxies = g_slist_next (proxies))); } void @@ -706,7 +1237,7 @@ midori_location_action_clear (MidoriLocationAction* location_action) alignment = gtk_bin_get_child (GTK_BIN (proxies->data)); entry = gtk_bin_get_child (GTK_BIN (alignment)); - midori_location_entry_clear (MIDORI_LOCATION_ENTRY (entry)); + gtk_list_store_clear (GTK_LIST_STORE (location_action->filter_model)); } while ((proxies = g_slist_next (proxies))); } diff --git a/midori/midori-locationaction.h b/midori/midori-locationaction.h index 5a8f53de..a95301c9 100644 --- a/midori/midori-locationaction.h +++ b/midori/midori-locationaction.h @@ -34,6 +34,13 @@ G_BEGIN_DECLS typedef struct _MidoriLocationAction MidoriLocationAction; typedef struct _MidoriLocationActionClass MidoriLocationActionClass; +struct _MidoriLocationEntryItem +{ + GdkPixbuf* favicon; + const gchar* uri; + const gchar* title; +}; + GType midori_location_action_get_type (void); diff --git a/midori/midori-locationentry.c b/midori/midori-locationentry.c index 6170c8dd..1e9a4766 100644 --- a/midori/midori-locationentry.c +++ b/midori/midori-locationentry.c @@ -10,15 +10,10 @@ */ #include "midori-locationentry.h" + #include "gtkiconentry.h" #include "sokoke.h" - #include -#include - -#define DEFAULT_ICON GTK_STOCK_FILE -#define MAX_ITEMS 25 -/* #define ORDER_BY_VISITS 1 */ struct _MidoriLocationEntry { @@ -45,108 +40,15 @@ enum N_COLS }; -enum -{ - ACTIVE_CHANGED, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL]; - static gboolean entry_key_press_event (GtkWidget* widget, GdkEventKey* event, MidoriLocationEntry* location_entry); -static void -midori_location_entry_changed (GtkComboBox* combo_box, - gpointer user_data); - static void midori_location_entry_class_init (MidoriLocationEntryClass* class) { - signals[ACTIVE_CHANGED] = g_signal_new ("active-changed", - G_TYPE_FROM_CLASS (class), - (GSignalFlags) (G_SIGNAL_RUN_LAST), - 0, - 0, - NULL, - g_cclosure_marshal_VOID__INT, - G_TYPE_NONE, 1, - G_TYPE_INT); -} -static GtkTreeModel* -midori_location_entry_get_filter_model (MidoriLocationEntry* location_entry) -{ - return gtk_combo_box_get_model (GTK_COMBO_BOX (location_entry)); -} - -static GtkTreeModel* -midori_location_entry_get_sort_model (MidoriLocationEntry* location_entry) -{ - GtkTreeModel* model; - GtkTreeModelFilter* filter_model; - - model = midori_location_entry_get_filter_model (location_entry); - filter_model = GTK_TREE_MODEL_FILTER (model); - g_assert (filter_model); - - return gtk_tree_model_filter_get_model (filter_model); -} - -static GtkTreeModel* -midori_location_entry_get_model (MidoriLocationEntry* location_entry) -{ - - GtkTreeModel* model; -#ifdef ORDER_BY_VISITS - GtkTreeModelSort* sort_model; -#endif - - model = midori_location_entry_get_sort_model (location_entry); - -#ifdef ORDER_BY_VISITS - sort_model = GTK_TREE_MODEL_SORT (model); - g_assert (sort_model); - - return gtk_tree_model_sort_get_model (sort_model); -#else - return GTK_IS_TREE_MODEL (model) ? model : NULL; -#endif - -} - -static gboolean -midori_location_entry_child_iter_to_iter (MidoriLocationEntry* location_entry, - GtkTreeIter* iter, - GtkTreeIter* child_iter) -{ - GtkTreeModel* filter_model; -#ifdef ORDER_BY_VISITS - GtkTreeModel* sort_model; - GtkTreeIter sort_iter; -#endif - GtkTreeIter* temp_iter; - - temp_iter = child_iter; - - filter_model = midori_location_entry_get_filter_model (location_entry); - -#ifdef ORDER_BY_VISITS - sort_model = midori_location_entry_get_sort_model (location_entry); - - g_return_val_if_fail (GTK_IS_TREE_MODEL_FILTER (filter_model) && - GTK_IS_TREE_MODEL_SORT (sort_model), FALSE); - - gtk_tree_model_sort_convert_child_iter_to_iter - (GTK_TREE_MODEL_SORT (sort_model), &sort_iter, child_iter); - - temp_iter = &sort_iter; -#endif - - return gtk_tree_model_filter_convert_child_iter_to_iter - (GTK_TREE_MODEL_FILTER (filter_model), iter, temp_iter); } #define HAVE_ENTRY_PROGRESS 1 @@ -456,14 +358,6 @@ entry_expose_event (GtkWidget* entry, #endif -gdouble -midori_location_entry_get_progress (MidoriLocationEntry* location_entry) -{ - g_return_val_if_fail (MIDORI_IS_LOCATION_ENTRY (location_entry), 0.0); - - return location_entry->progress; -} - void midori_location_entry_set_progress (MidoriLocationEntry* location_entry, gdouble progress) @@ -483,188 +377,12 @@ midori_location_entry_set_progress (MidoriLocationEntry* location_entry, #endif } -static gboolean -midori_location_entry_completion_selected (GtkEntryCompletion* completion, - GtkTreeModel* model, - GtkTreeIter* iter, - MidoriLocationEntry* location_entry) -{ - gchar* uri; - - gtk_tree_model_get (model, iter, URI_COL, &uri, -1); - midori_location_entry_set_item_from_uri (location_entry, uri); - g_free (uri); - - return FALSE; -} - -static void -midori_location_entry_render_pixbuf_cb (GtkCellLayout* layout, - GtkCellRenderer* renderer, - GtkTreeModel* model, - GtkTreeIter* iter, - gpointer data) -{ - GdkPixbuf* pixbuf; - - gtk_tree_model_get (model, iter, FAVICON_COL, &pixbuf, -1); - if (pixbuf) - { - g_object_set (renderer, "pixbuf", pixbuf, "yalign", 0.25, NULL); - g_object_unref (pixbuf); - } -} - -static void -midori_location_entry_render_text_cb (GtkCellLayout* layout, - GtkCellRenderer* renderer, - GtkTreeModel* model, - GtkTreeIter* iter, - gpointer data) -{ - gchar* uri; - gchar* title; - gchar* desc; - gchar* desc_uri; - gchar* desc_title; - GtkWidget* entry; - gchar* key; - gchar* temp; - gchar** parts; - - gtk_tree_model_get (model, iter, URI_COL, &uri, TITLE_COL, &title, -1); - - desc_uri = desc_title = key = NULL; - if (data) - { - entry = gtk_entry_completion_get_entry (GTK_ENTRY_COMPLETION (data)); - key = g_utf8_strdown (gtk_entry_get_text (GTK_ENTRY (entry)), -1); - } - if (data && uri) - { - temp = g_utf8_strdown (uri, -1); - parts = g_strsplit (temp, key, 2); - g_free (temp); - if (parts && parts[0] && parts[1]) - desc_uri = g_markup_printf_escaped ("%s%s%s", - parts[0], key, parts[1]); - g_strfreev (parts); - } - if (uri && !desc_uri) - desc_uri = g_markup_escape_text (uri, -1); - if (data && title) - { - temp = g_utf8_strdown (title, -1); - parts = g_strsplit (temp, key, 2); - g_free (temp); - if (parts && parts[0] && parts[1]) - desc_title = g_markup_printf_escaped ("%s%s%s", - parts[0], key, parts[1]); - g_strfreev (parts); - } - if (title && !desc_title) - desc_title = g_markup_escape_text (title, -1); - - if (desc_title) - desc = g_strdup_printf ("%s\n%s", - desc_title, desc_uri); - else - desc = g_strdup_printf ("%s", desc_uri); - - g_object_set (renderer, "markup", desc, - "ellipsize-set", TRUE, "ellipsize", PANGO_ELLIPSIZE_END, NULL); - - g_free (uri); - g_free (title); - g_free (key); - g_free (desc); - g_free (desc_uri); - g_free (desc_title); -} - -static gboolean -midori_location_entry_completion_match_cb (GtkEntryCompletion* completion, - const gchar* key, - GtkTreeIter* iter, - gpointer data) -{ - GtkTreeModel* model; - gchar* uri; - gchar* title; - gboolean match; - gchar* temp; - - model = gtk_entry_completion_get_model (completion); - gtk_tree_model_get (model, iter, URI_COL, &uri, TITLE_COL, &title, -1); - - match = FALSE; - if (uri) - { - temp = g_utf8_casefold (uri, -1); - match = (strstr (temp, key) != NULL); - g_free (temp); - g_free (uri); - - if (!match && title) - { - temp = g_utf8_casefold (title, -1); - match = (strstr (temp, key) != NULL); - g_free (temp); - g_free (title); - } - } - - return match; -} - -static void -midori_location_entry_completion_init (MidoriLocationEntry* location_entry) -{ - GtkWidget* entry; - GtkEntryCompletion* completion; - GtkCellRenderer* renderer; - - entry = gtk_bin_get_child (GTK_BIN (location_entry)); - completion = gtk_entry_completion_new (); - - gtk_entry_completion_set_model (GTK_ENTRY_COMPLETION (completion), - midori_location_entry_get_sort_model (location_entry)); - gtk_entry_completion_set_text_column (GTK_ENTRY_COMPLETION (completion), - URI_COL); - gtk_cell_layout_clear (GTK_CELL_LAYOUT (completion)); - - renderer = gtk_cell_renderer_pixbuf_new (); - gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (completion), renderer, FALSE); - gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (completion), renderer, - midori_location_entry_render_pixbuf_cb, - NULL, NULL); - renderer = gtk_cell_renderer_text_new (); - gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (completion), renderer, TRUE); - gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (completion), renderer, - midori_location_entry_render_text_cb, - completion, NULL); - gtk_entry_completion_set_match_func (completion, - midori_location_entry_completion_match_cb, NULL, NULL); - - gtk_entry_set_completion (GTK_ENTRY (entry), completion); - g_signal_connect (completion, "match-selected", - G_CALLBACK (midori_location_entry_completion_selected), location_entry); - - g_object_unref (completion); -} - static void midori_location_entry_init (MidoriLocationEntry* location_entry) { GtkWidget* entry; - GtkListStore* store; - GtkCellRenderer* renderer; - GtkTreeModel* filter_model; -#ifdef ORDER_BY_VISITS - GtkTreeModel* sort_model; -#endif - /* we want the widget to have appears-as-list applied */ + /* We want the widget to have appears-as-list applied */ gtk_rc_parse_string ("style \"midori-location-entry-style\" {\n" " GtkComboBox::appears-as-list = 1\n }\n" "widget_class \"*MidoriLocationEntry\" " @@ -674,57 +392,17 @@ midori_location_entry_init (MidoriLocationEntry* location_entry) entry = gtk_icon_entry_new (); gtk_icon_entry_set_icon_from_stock (GTK_ICON_ENTRY (entry), - GTK_ICON_ENTRY_PRIMARY, DEFAULT_ICON); + GTK_ICON_ENTRY_PRIMARY, GTK_STOCK_FILE); + gtk_icon_entry_set_icon_highlight (GTK_ICON_ENTRY (entry), + GTK_ICON_ENTRY_SECONDARY, TRUE); g_signal_connect_after (entry, "key-press-event", G_CALLBACK (entry_key_press_event), location_entry); #ifdef HAVE_ENTRY_PROGRESS g_signal_connect_after (entry, "expose-event", G_CALLBACK (entry_expose_event), location_entry); #endif - gtk_widget_show (entry); gtk_container_add (GTK_CONTAINER (location_entry), entry); - - store = gtk_list_store_new (N_COLS, - GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING, - G_TYPE_INT, G_TYPE_BOOLEAN); - -#ifdef ORDER_BY_VISITS - sort_model = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (store)); - gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sort_model), - VISITS_COL, GTK_SORT_DESCENDING); - filter_model = gtk_tree_model_filter_new (GTK_TREE_MODEL (sort_model), NULL); -#else - filter_model = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL); -#endif - - gtk_tree_model_filter_set_visible_column ( - GTK_TREE_MODEL_FILTER (filter_model), VISIBLE_COL); - g_object_set (location_entry, "model", filter_model, NULL); - g_object_unref (store); - - gtk_combo_box_entry_set_text_column ( - GTK_COMBO_BOX_ENTRY (location_entry), URI_COL); - gtk_cell_layout_clear (GTK_CELL_LAYOUT (location_entry)); - - /* setup the renderer for the favicon */ - renderer = gtk_cell_renderer_pixbuf_new (); - gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (location_entry), - renderer, FALSE); - gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (location_entry), - renderer, midori_location_entry_render_pixbuf_cb, NULL, NULL); - renderer = gtk_cell_renderer_text_new (); - gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (location_entry), - renderer, TRUE); - gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (location_entry), - renderer, midori_location_entry_render_text_cb, NULL, NULL); - - gtk_combo_box_set_active (GTK_COMBO_BOX (location_entry), -1); - - midori_location_entry_completion_init (location_entry); - - g_signal_connect (location_entry, "changed", - G_CALLBACK (midori_location_entry_changed), NULL); } static gboolean @@ -746,101 +424,6 @@ entry_key_press_event (GtkWidget* widget, return FALSE; } -static void -midori_location_entry_changed (GtkComboBox* combo_box, - gpointer user_data) -{ - GtkTreeIter iter; - GtkIconEntry* entry; - GtkTreeModel* model; - GdkPixbuf* pixbuf; - - if (gtk_combo_box_get_active_iter (combo_box, &iter)) - { - entry = GTK_ICON_ENTRY (GTK_BIN (combo_box)->child); - - if (entry) - { - pixbuf = NULL; - - model = midori_location_entry_get_filter_model - (MIDORI_LOCATION_ENTRY (combo_box)); - gtk_tree_model_get (model, &iter, FAVICON_COL, &pixbuf, -1); - - gtk_icon_entry_set_icon_from_pixbuf (GTK_ICON_ENTRY (entry), - GTK_ICON_ENTRY_PRIMARY, pixbuf); - g_object_unref (pixbuf); - - g_signal_emit (MIDORI_LOCATION_ENTRY (combo_box), - signals[ACTIVE_CHANGED], 0, gtk_combo_box_get_active (combo_box)); - } - } -} - -static void -midori_location_entry_set_item (MidoriLocationEntry* entry, - GtkTreeIter* iter, - MidoriLocationEntryItem* item) -{ - GtkTreeModel* model; - GdkPixbuf* icon; - GdkPixbuf* new_icon; - - model = midori_location_entry_get_model (entry); - gtk_list_store_set (GTK_LIST_STORE (model), iter, - URI_COL, item->uri, TITLE_COL, item->title, -1); - - gtk_tree_model_get (model, iter, FAVICON_COL, &icon, -1); - if (item->favicon) - new_icon = g_object_ref (item->favicon); - else if (!icon && !item->favicon) - new_icon = gtk_widget_render_icon (GTK_WIDGET (entry), DEFAULT_ICON, - GTK_ICON_SIZE_MENU, NULL); - else - new_icon = NULL; - if (new_icon) - { - gtk_list_store_set (GTK_LIST_STORE (model), iter, - FAVICON_COL, new_icon, -1); - g_object_unref (new_icon); - } -} - -static void -midori_location_entry_set_active_iter (MidoriLocationEntry* location_entry, - GtkTreeIter* iter) -{ - GdkPixbuf* pixbuf; - GtkTreeModel* model; - GtkWidget* entry; - GtkTreeIter parent_iter; - - entry = gtk_bin_get_child (GTK_BIN (location_entry)); - model = midori_location_entry_get_model (location_entry); - - /* The filter iter must be set, not the child iter, - * but the row must first be set as visible to - * convert to a filter iter without error. - */ - gtk_list_store_set (GTK_LIST_STORE (model), iter, VISIBLE_COL, TRUE, -1); - if (midori_location_entry_child_iter_to_iter ( - location_entry, &parent_iter, iter)) - gtk_combo_box_set_active_iter (GTK_COMBO_BOX (location_entry), &parent_iter); - - /* When setting the active iter (when adding or setting an item) - * the favicon may have changed, so we must update the entry favicon. - */ - if (entry) - { - gtk_tree_model_get (model, iter, FAVICON_COL, &pixbuf, -1); - - gtk_icon_entry_set_icon_from_pixbuf (GTK_ICON_ENTRY (entry), - GTK_ICON_ENTRY_PRIMARY, pixbuf); - - g_object_unref (pixbuf); - } -} - /** * midori_location_entry_new: * @@ -853,279 +436,3 @@ midori_location_entry_new (void) { return g_object_new (MIDORI_TYPE_LOCATION_ENTRY, NULL); } - -/** - * midori_location_entry_item_iter: - * @location_entry: a #MidoriLocationEntry - * @uri: a string - * @iter: a GtkTreeIter - * - * Retrieves the iter of the item matching @uri. - * - * Return value: %TRUE if @uri was found, %FALSE otherwise - **/ -gboolean -midori_location_entry_item_iter (MidoriLocationEntry* location_entry, - const gchar* uri, - GtkTreeIter* iter) -{ - GtkTreeModel* model; - gchar* tmpuri; - gboolean found; - - g_return_val_if_fail (MIDORI_IS_LOCATION_ENTRY (location_entry), FALSE); - g_return_val_if_fail (uri != NULL, FALSE); - - found = FALSE; - model = midori_location_entry_get_model (location_entry); - if (gtk_tree_model_get_iter_first (model, iter)) - { - tmpuri = NULL; - do - { - gtk_tree_model_get (model, iter, URI_COL, &tmpuri, -1); - found = !g_ascii_strcasecmp (uri, tmpuri); - katze_assign (tmpuri, NULL); - - if (found) - break; - } - while (gtk_tree_model_iter_next (model, iter)); - } - return found; -} - -/** - * midori_location_entry_get_text: - * @location_entry: a #MidoriLocationEntry - * - * Retrieves the text of the embedded entry. - * - * Return value: a string - **/ -const gchar* -midori_location_entry_get_text (MidoriLocationEntry* location_entry) -{ - GtkWidget* entry; - - g_return_val_if_fail (MIDORI_IS_LOCATION_ENTRY (location_entry), NULL); - - entry = gtk_bin_get_child (GTK_BIN (location_entry)); - g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL); - - return gtk_entry_get_text (GTK_ENTRY (entry)); -} - -/** - * midori_location_entry_set_text: - * @location_entry: a #MidoriLocationEntry - * @text: a string - * - * Sets the entry text to @text and, if applicable, updates the icon. - **/ -void -midori_location_entry_set_text (MidoriLocationEntry* location_entry, - const gchar* text) -{ - GtkWidget* entry; - GtkTreeIter iter; - GtkTreeModel* model; - GdkPixbuf* icon; - - g_return_if_fail (MIDORI_IS_LOCATION_ENTRY (location_entry)); - - entry = gtk_bin_get_child (GTK_BIN (location_entry)); - g_return_if_fail (GTK_IS_ENTRY (entry)); - - gtk_entry_set_text (GTK_ENTRY (entry), text); - if (midori_location_entry_item_iter (location_entry, text, &iter)) - { - model = midori_location_entry_get_model (location_entry); - gtk_tree_model_get (model, &iter, FAVICON_COL, &icon, -1); - gtk_icon_entry_set_icon_from_pixbuf (GTK_ICON_ENTRY (entry), - GTK_ICON_ENTRY_PRIMARY, icon); - } - /* FIXME: Due to a bug in GtkIconEntry we can't reset the icon - else - gtk_icon_entry_set_icon_from_stock (GTK_ICON_ENTRY (entry), - GTK_ICON_ENTRY_PRIMARY, DEFAULT_ICON);*/ -} - -/** - * midori_location_entry_reset: - * @location_entry: a #MidoriLocationEntry - * - * Clears the entry text and resets the entry favicon. - **/ -void -midori_location_entry_reset (MidoriLocationEntry* location_entry) -{ - GtkWidget* entry; - - g_return_if_fail (MIDORI_IS_LOCATION_ENTRY (location_entry)); - - entry = gtk_bin_get_child (GTK_BIN (location_entry)); - g_return_if_fail (GTK_IS_ICON_ENTRY (entry)); - - gtk_entry_set_text (GTK_ENTRY (entry), ""); - gtk_icon_entry_set_icon_from_stock (GTK_ICON_ENTRY (entry), - GTK_ICON_ENTRY_PRIMARY, DEFAULT_ICON); -} - -/** - * midori_location_entry_clear: - * @location_entry: a #MidoriLocationEntry - * - * Removes all items from @location_entry - **/ -void -midori_location_entry_clear (MidoriLocationEntry* location_entry) -{ - GtkTreeModel* model; - - g_return_if_fail (MIDORI_IS_LOCATION_ENTRY (location_entry)); - - model = midori_location_entry_get_model (location_entry); - gtk_list_store_clear (GTK_LIST_STORE (model)); -} - -/** - * midori_location_entry_set_item_from_uri: - * @location_entry: a #MidoriLocationEntry - * @uri: a string - * - * Finds the item from the list matching @uri and sets it as the active item. - * If @uri is not found it clears the active item. - **/ -void -midori_location_entry_set_item_from_uri (MidoriLocationEntry* location_entry, - const gchar* uri) -{ - GtkTreeIter iter; - - g_return_if_fail (MIDORI_IS_LOCATION_ENTRY (location_entry)); - - if (midori_location_entry_item_iter (location_entry, uri, &iter)) - midori_location_entry_set_active_iter (location_entry, &iter); - else - midori_location_entry_reset (location_entry); - -} - -/** - * midori_location_entry_prepend_item: - * @location_entry: a #MidoriLocationEntry - * @item: a MidoriLocationItem - * - * Prepends @item if it is not already in the list. - * If the item already exists, it is moved before the first item. - * If the maximum is reached, the last item is removed. - **/ -void -midori_location_entry_prepend_item (MidoriLocationEntry* location_entry, - MidoriLocationEntryItem* item) -{ - GtkTreeModel* filter_model; - GtkTreeModel* model; - GtkTreeIter iter; - GtkTreeIter index; - gint n; - gint visits = 0; - - g_return_if_fail (MIDORI_IS_LOCATION_ENTRY (location_entry)); - g_return_if_fail (item->uri != NULL); - - filter_model = midori_location_entry_get_filter_model (location_entry); - model = midori_location_entry_get_model (location_entry); - - if (midori_location_entry_item_iter (location_entry, item->uri, &iter)) - { - gtk_tree_model_get_iter_first (model, &index); - gtk_tree_model_get (model, &iter, VISITS_COL, &visits, -1); - gtk_list_store_move_before (GTK_LIST_STORE (model), &iter, &index); - } - else - gtk_list_store_prepend (GTK_LIST_STORE (model), &iter); - - n = gtk_tree_model_iter_n_children (filter_model, NULL); - if (n > MAX_ITEMS) - { - gtk_tree_model_iter_nth_child (model, &index, NULL, n - 1); - gtk_list_store_set (GTK_LIST_STORE (model), - &index, VISIBLE_COL, FALSE, -1); - } - - /* Only increment the visits when we add the uri */ - if (!item->title && !item->favicon) - gtk_list_store_set (GTK_LIST_STORE (model), &iter, VISITS_COL, ++visits, - VISIBLE_COL, TRUE, -1); - midori_location_entry_set_item (location_entry, &iter, item); -} - -/** - * midori_location_entry_append_item: - * @location_entry: a #MidoriLocationEntry - * @item: a MidoriLocationItem - * - * Appends @item if it is not already in the list. - * @item is not added if the maximum is reached. - **/ -void -midori_location_entry_append_item (MidoriLocationEntry* location_entry, - MidoriLocationEntryItem* item) -{ - GtkTreeModel* model; - GtkTreeIter iter; - gint n; - gint visits = 0; - - g_return_if_fail (MIDORI_IS_LOCATION_ENTRY (location_entry)); - g_return_if_fail (item->uri != NULL); - - model = midori_location_entry_get_model (location_entry); - - if (!midori_location_entry_item_iter (location_entry, item->uri, &iter)) - { - gtk_list_store_append (GTK_LIST_STORE (model), &iter); - - n = gtk_tree_model_iter_n_children (model, NULL); - gtk_list_store_set (GTK_LIST_STORE (model), &iter, VISIBLE_COL, - (n <= MAX_ITEMS), -1); - } - else - gtk_tree_model_get (model, &iter, VISITS_COL, &visits, -1); - - gtk_list_store_set (GTK_LIST_STORE (model), &iter, VISITS_COL, ++visits, -1); - midori_location_entry_set_item (location_entry, &iter, item); -} - -/** - * midori_location_entry_set_item_from_uri: - * @location_entry: a #MidoriLocationEntry - * @uri: a string - * - * Finds the item from the list matching @uri - * and removes it if it is the last instance. - **/ -void -midori_location_entry_delete_item_from_uri (MidoriLocationEntry* location_entry, - const gchar* uri) -{ - GtkTreeModel* model; - GtkTreeIter iter; - gint visits = 0; - - g_return_if_fail (MIDORI_IS_LOCATION_ENTRY (location_entry)); - - model = midori_location_entry_get_model (location_entry); - if (midori_location_entry_item_iter (location_entry, uri, &iter)) - { - gtk_tree_model_get (model, &iter, VISITS_COL, &visits, -1); - if (visits > 1) - gtk_list_store_set (GTK_LIST_STORE (model), - &iter, VISITS_COL, --visits, -1); - else - gtk_list_store_remove (GTK_LIST_STORE (model), &iter); - } -} - diff --git a/midori/midori-locationentry.h b/midori/midori-locationentry.h index 6be5ed69..f84d0b29 100644 --- a/midori/midori-locationentry.h +++ b/midori/midori-locationentry.h @@ -27,56 +27,12 @@ typedef struct _MidoriLocationEntry MidoriLocationEntry; typedef struct _MidoriLocationEntryClass MidoriLocationEntryClass; typedef struct _MidoriLocationEntryItem MidoriLocationEntryItem; -struct _MidoriLocationEntryItem -{ - GdkPixbuf* favicon; - const gchar* uri; - const gchar* title; -}; - GType midori_location_entry_get_type (void); GtkWidget* midori_location_entry_new (void); -gboolean -midori_location_entry_item_iter (MidoriLocationEntry* location_entry, - const gchar* uri, - GtkTreeIter* iter); - -const gchar* -midori_location_entry_get_text (MidoriLocationEntry* location_entry); - -void -midori_location_entry_set_text (MidoriLocationEntry* location_entry, - const gchar* text); - -void -midori_location_entry_reset (MidoriLocationEntry* location_entry); - -void -midori_location_entry_clear (MidoriLocationEntry* location_entry); - -void -midori_location_entry_set_item_from_uri (MidoriLocationEntry* location_entry, - const gchar* uri); - -void -midori_location_entry_prepend_item (MidoriLocationEntry* location_entry, - MidoriLocationEntryItem* item); - -void -midori_location_entry_append_item (MidoriLocationEntry* location_entry, - MidoriLocationEntryItem* item); - -void -midori_location_entry_delete_item_from_uri (MidoriLocationEntry* location_entry, - const gchar* uri); - -gdouble -midori_location_entry_get_progress (MidoriLocationEntry* location_entry); - void midori_location_entry_set_progress (MidoriLocationEntry* location_entry, gdouble progress);