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.
This commit is contained in:
Christian Dywan 2008-11-09 19:09:35 +01:00
parent 57ec9a7bb8
commit 87092babef
4 changed files with 655 additions and 854 deletions

View file

@ -1,5 +1,6 @@
/* /*
Copyright (C) 2008 Christian Dywan <christian@twotoasts.de> Copyright (C) 2008 Christian Dywan <christian@twotoasts.de>
Copyright (C) 2008 Dale Whittaker <dayul@users.sf.net>
This library is free software; you can redistribute it and/or This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public modify it under the terms of the GNU Lesser General Public
@ -12,10 +13,14 @@
#include "midori-locationaction.h" #include "midori-locationaction.h"
#include "gtkiconentry.h" #include "gtkiconentry.h"
#include "sokoke.h"
#include <string.h>
#include <glib/gi18n.h> #include <glib/gi18n.h>
#include <gdk/gdkkeysyms.h> #include <gdk/gdkkeysyms.h>
#define MAX_ITEMS 25
struct _MidoriLocationAction struct _MidoriLocationAction
{ {
GtkAction parent_instance; GtkAction parent_instance;
@ -24,6 +29,9 @@ struct _MidoriLocationAction
gdouble progress; gdouble progress;
GtkTreeModel* model; GtkTreeModel* model;
GtkTreeModel* filter_model;
GtkTreeModel* sort_model;
GdkPixbuf* default_icon;
}; };
struct _MidoriLocationActionClass struct _MidoriLocationActionClass
@ -53,6 +61,16 @@ enum
static guint signals[LAST_SIGNAL]; static guint signals[LAST_SIGNAL];
enum
{
FAVICON_COL,
URI_COL,
TITLE_COL,
VISITS_COL,
VISIBLE_COL,
N_COLS
};
static void static void
midori_location_action_finalize (GObject* object); midori_location_action_finalize (GObject* object);
@ -199,10 +217,27 @@ midori_location_action_class_init (MidoriLocationActionClass* class)
static void static void
midori_location_action_init (MidoriLocationAction* location_action) midori_location_action_init (MidoriLocationAction* location_action)
{ {
GtkTreeModel* liststore;
GtkTreeModel* sort_model;
GtkTreeModel* filter_model;
location_action->uri = NULL; location_action->uri = NULL;
location_action->progress = 0.0; 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 static void
@ -210,9 +245,12 @@ midori_location_action_finalize (GObject* object)
{ {
MidoriLocationAction* location_action = MIDORI_LOCATION_ACTION (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->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); G_OBJECT_CLASS (midori_location_action_parent_class)->finalize (object);
} }
@ -228,17 +266,13 @@ midori_location_action_set_property (GObject* object,
switch (prop_id) switch (prop_id)
{ {
case PROP_PROGRESS: case PROP_PROGRESS:
{
midori_location_action_set_progress (location_action, midori_location_action_set_progress (location_action,
g_value_get_double (value)); g_value_get_double (value));
break; break;
}
case PROP_SECONDARY_ICON: case PROP_SECONDARY_ICON:
{
midori_location_action_set_secondary_icon (location_action, midori_location_action_set_secondary_icon (location_action,
g_value_get_string (value)); g_value_get_string (value));
break; break;
}
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -276,20 +310,16 @@ static GtkWidget*
midori_location_action_create_tool_item (GtkAction* action) midori_location_action_create_tool_item (GtkAction* action)
{ {
GtkWidget* toolitem; GtkWidget* toolitem;
GtkWidget* entry; GtkWidget* location_entry;
GtkWidget* alignment; GtkWidget* alignment;
toolitem = GTK_WIDGET (gtk_tool_item_new ()); toolitem = GTK_WIDGET (gtk_tool_item_new ());
gtk_tool_item_set_expand (GTK_TOOL_ITEM (toolitem), TRUE); gtk_tool_item_set_expand (GTK_TOOL_ITEM (toolitem), TRUE);
entry = midori_location_entry_new (); location_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);
alignment = gtk_alignment_new (0, 0.5, 1, 0.1); alignment = gtk_alignment_new (0, 0.5, 1, 0.1);
gtk_container_add (GTK_CONTAINER (alignment), entry); gtk_container_add (GTK_CONTAINER (alignment), location_entry);
gtk_widget_show (entry); gtk_widget_show (location_entry);
gtk_container_add (GTK_CONTAINER (toolitem), alignment); gtk_container_add (GTK_CONTAINER (toolitem), alignment);
gtk_widget_show (alignment); gtk_widget_show (alignment);
@ -297,15 +327,17 @@ midori_location_action_create_tool_item (GtkAction* action)
} }
static void static void
midori_location_action_active_changed_cb (GtkWidget* widget, midori_location_action_active_changed_cb (GtkWidget* location_entry,
gint active, gint active,
GtkAction* action) GtkAction* action)
{ {
MidoriLocationAction* location_action; MidoriLocationAction* location_action;
GtkWidget* entry;
const gchar* text; const gchar* text;
location_action = MIDORI_LOCATION_ACTION (action); 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)); katze_assign (location_action->uri, g_strdup (text));
g_signal_emit (action, signals[ACTIVE_CHANGED], 0, active); 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); 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<b>%s</b>%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<b>%s</b>%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<span color='gray45'>%s</span>",
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 static void
midori_location_action_connect_proxy (GtkAction* action, midori_location_action_connect_proxy (GtkAction* action,
GtkWidget* proxy) GtkWidget* proxy)
@ -366,6 +789,7 @@ midori_location_action_connect_proxy (GtkAction* action,
GtkWidget* alignment; GtkWidget* alignment;
GtkWidget* entry; GtkWidget* entry;
MidoriLocationAction* location_action; MidoriLocationAction* location_action;
GtkCellRenderer* renderer;
GTK_ACTION_CLASS (midori_location_action_parent_class)->connect_proxy ( GTK_ACTION_CLASS (midori_location_action_parent_class)->connect_proxy (
action, proxy); action, proxy);
@ -376,14 +800,30 @@ midori_location_action_connect_proxy (GtkAction* action,
entry = gtk_bin_get_child (GTK_BIN (alignment)); entry = gtk_bin_get_child (GTK_BIN (alignment));
location_action = MIDORI_LOCATION_ACTION (action); location_action = MIDORI_LOCATION_ACTION (action);
if (location_action->model) midori_location_entry_set_progress (MIDORI_LOCATION_ENTRY (entry),
MIDORI_LOCATION_ACTION (action)->progress);
gtk_combo_box_set_model (GTK_COMBO_BOX (entry), gtk_combo_box_set_model (GTK_COMBO_BOX (entry),
location_action->model); MIDORI_LOCATION_ACTION (action)->filter_model);
else gtk_combo_box_entry_set_text_column (
location_action->model = g_object_ref (gtk_combo_box_get_model ( GTK_COMBO_BOX_ENTRY (entry), URI_COL);
GTK_COMBO_BOX (entry))); 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_CALLBACK (midori_location_action_active_changed_cb), action);
g_object_connect (gtk_bin_get_child (GTK_BIN (entry)), g_object_connect (gtk_bin_get_child (GTK_BIN (entry)),
"signal::key-press-event", "signal::key-press-event",
@ -416,18 +856,26 @@ midori_location_action_get_uri (MidoriLocationAction* location_action)
return location_action->uri; return location_action->uri;
} }
void /**
midori_location_action_set_uri (MidoriLocationAction* location_action, * midori_location_action_set_text:
const gchar* uri) * @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; GSList* proxies;
GtkWidget* alignment; GtkWidget* alignment;
GtkWidget* location_entry;
GtkWidget* entry; GtkWidget* entry;
GtkTreeIter iter;
GtkTreeModel* model;
GdkPixbuf* icon;
g_return_if_fail (MIDORI_IS_LOCATION_ACTION (location_action)); 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)); proxies = gtk_action_get_proxies (GTK_ACTION (location_action));
if (!proxies) if (!proxies)
@ -437,20 +885,128 @@ midori_location_action_set_uri (MidoriLocationAction* location_action,
if (GTK_IS_TOOL_ITEM (proxies->data)) if (GTK_IS_TOOL_ITEM (proxies->data))
{ {
alignment = gtk_bin_get_child (GTK_BIN (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))); 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 void
midori_location_action_add_uri (MidoriLocationAction* location_action, midori_location_action_add_uri (MidoriLocationAction* location_action,
const gchar* uri) const gchar* uri)
{ {
GSList* proxies;
GtkWidget* alignment;
GtkWidget* entry;
MidoriLocationEntryItem item; MidoriLocationEntryItem item;
g_return_if_fail (MIDORI_IS_LOCATION_ACTION (location_action)); 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)); 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.favicon = NULL;
item.uri = uri; item.uri = uri;
item.title = NULL; item.title = NULL;
midori_location_entry_prepend_item ( midori_location_action_prepend_item (location_action, &item);
MIDORI_LOCATION_ENTRY (entry), &item);
}
while ((proxies = g_slist_next (proxies)));
} }
void void
@ -485,8 +1028,8 @@ midori_location_action_add_item (MidoriLocationAction* location_action,
{ {
GSList* proxies; GSList* proxies;
GtkWidget* alignment; GtkWidget* alignment;
GtkWidget* location_entry;
GtkWidget* entry; GtkWidget* entry;
GtkWidget* child;
MidoriLocationEntryItem item; MidoriLocationEntryItem item;
g_return_if_fail (MIDORI_IS_LOCATION_ACTION (location_action)); g_return_if_fail (MIDORI_IS_LOCATION_ACTION (location_action));
@ -496,24 +1039,24 @@ midori_location_action_add_item (MidoriLocationAction* location_action,
katze_assign (location_action->uri, g_strdup (uri)); 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)); proxies = gtk_action_get_proxies (GTK_ACTION (location_action));
if (!proxies) if (!proxies)
return; return;
do 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)); 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));
child = gtk_bin_get_child (GTK_BIN (entry)); entry = gtk_bin_get_child (GTK_BIN (location_entry));
item.favicon = icon; gtk_icon_entry_set_icon_from_pixbuf (GTK_ICON_ENTRY (entry),
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_PRIMARY, icon);
} }
while ((proxies = g_slist_next (proxies))); while ((proxies = g_slist_next (proxies)));
@ -526,32 +1069,32 @@ midori_location_action_set_icon_for_uri (MidoriLocationAction* location_action,
{ {
GSList* proxies; GSList* proxies;
GtkWidget* alignment; GtkWidget* alignment;
GtkWidget* location_entry;
GtkWidget* entry; GtkWidget* entry;
GtkWidget* child;
MidoriLocationEntryItem item; MidoriLocationEntryItem item;
g_return_if_fail (MIDORI_IS_LOCATION_ACTION (location_action)); g_return_if_fail (MIDORI_IS_LOCATION_ACTION (location_action));
g_return_if_fail (!icon || GDK_IS_PIXBUF (icon)); g_return_if_fail (!icon || GDK_IS_PIXBUF (icon));
g_return_if_fail (uri != NULL); 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)); proxies = gtk_action_get_proxies (GTK_ACTION (location_action));
if (!proxies) if (!proxies)
return; return;
do 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)); 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));
child = gtk_bin_get_child (GTK_BIN (entry)); entry = gtk_bin_get_child (GTK_BIN (location_entry));
item.favicon = icon; gtk_icon_entry_set_icon_from_pixbuf (GTK_ICON_ENTRY (entry),
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_PRIMARY, icon);
} }
while ((proxies = g_slist_next (proxies))); 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* title,
const gchar* uri) const gchar* uri)
{ {
GSList* proxies;
GtkWidget* alignment;
GtkWidget* entry;
MidoriLocationEntryItem item; MidoriLocationEntryItem item;
g_return_if_fail (MIDORI_IS_LOCATION_ACTION (location_action)); g_return_if_fail (MIDORI_IS_LOCATION_ACTION (location_action));
g_return_if_fail (title != NULL); g_return_if_fail (title != NULL);
g_return_if_fail (uri != 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.favicon = NULL;
item.uri = uri; item.uri = uri;
item.title = title; item.title = title;
midori_location_entry_prepend_item ( midori_location_action_prepend_item (location_action, &item);
MIDORI_LOCATION_ENTRY (entry), &item);
}
while ((proxies = g_slist_next (proxies)));
} }
gdouble gdouble
@ -660,31 +1187,35 @@ midori_location_action_set_secondary_icon (MidoriLocationAction* location_action
while ((proxies = g_slist_next (proxies))); 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 void
midori_location_action_delete_item_from_uri (MidoriLocationAction* location_action, midori_location_action_delete_item_from_uri (MidoriLocationAction* location_action,
const gchar* uri) const gchar* uri)
{ {
GSList* proxies; GtkTreeModel* model;
GtkWidget* alignment; GtkTreeIter iter;
GtkWidget* entry; gint visits;
g_return_if_fail (MIDORI_IS_LOCATION_ACTION (location_action)); g_return_if_fail (MIDORI_IS_LOCATION_ACTION (location_action));
g_return_if_fail (uri != NULL); g_return_if_fail (uri != NULL);
proxies = gtk_action_get_proxies (GTK_ACTION (location_action)); model = location_action->model;
if (!proxies) if (midori_location_action_item_iter (location_action, uri, &iter))
return;
do
if (GTK_IS_TOOL_ITEM (proxies->data))
{ {
alignment = gtk_bin_get_child (GTK_BIN (proxies->data)); gtk_tree_model_get (model, &iter, VISITS_COL, &visits, -1);
entry = gtk_bin_get_child (GTK_BIN (alignment)); if (visits > 1)
gtk_list_store_set (GTK_LIST_STORE (model),
midori_location_entry_delete_item_from_uri &iter, VISITS_COL, --visits, -1);
(MIDORI_LOCATION_ENTRY (entry), uri); else
gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
} }
while ((proxies = g_slist_next (proxies)));
} }
void void
@ -706,7 +1237,7 @@ midori_location_action_clear (MidoriLocationAction* location_action)
alignment = gtk_bin_get_child (GTK_BIN (proxies->data)); alignment = gtk_bin_get_child (GTK_BIN (proxies->data));
entry = gtk_bin_get_child (GTK_BIN (alignment)); 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))); while ((proxies = g_slist_next (proxies)));
} }

View file

@ -34,6 +34,13 @@ G_BEGIN_DECLS
typedef struct _MidoriLocationAction MidoriLocationAction; typedef struct _MidoriLocationAction MidoriLocationAction;
typedef struct _MidoriLocationActionClass MidoriLocationActionClass; typedef struct _MidoriLocationActionClass MidoriLocationActionClass;
struct _MidoriLocationEntryItem
{
GdkPixbuf* favicon;
const gchar* uri;
const gchar* title;
};
GType GType
midori_location_action_get_type (void); midori_location_action_get_type (void);

View file

@ -10,15 +10,10 @@
*/ */
#include "midori-locationentry.h" #include "midori-locationentry.h"
#include "gtkiconentry.h" #include "gtkiconentry.h"
#include "sokoke.h" #include "sokoke.h"
#include <gdk/gdkkeysyms.h> #include <gdk/gdkkeysyms.h>
#include <string.h>
#define DEFAULT_ICON GTK_STOCK_FILE
#define MAX_ITEMS 25
/* #define ORDER_BY_VISITS 1 */
struct _MidoriLocationEntry struct _MidoriLocationEntry
{ {
@ -45,108 +40,15 @@ enum
N_COLS N_COLS
}; };
enum
{
ACTIVE_CHANGED,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL];
static gboolean static gboolean
entry_key_press_event (GtkWidget* widget, entry_key_press_event (GtkWidget* widget,
GdkEventKey* event, GdkEventKey* event,
MidoriLocationEntry* location_entry); MidoriLocationEntry* location_entry);
static void
midori_location_entry_changed (GtkComboBox* combo_box,
gpointer user_data);
static void static void
midori_location_entry_class_init (MidoriLocationEntryClass* class) 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 #define HAVE_ENTRY_PROGRESS 1
@ -456,14 +358,6 @@ entry_expose_event (GtkWidget* entry,
#endif #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 void
midori_location_entry_set_progress (MidoriLocationEntry* location_entry, midori_location_entry_set_progress (MidoriLocationEntry* location_entry,
gdouble progress) gdouble progress)
@ -483,188 +377,12 @@ midori_location_entry_set_progress (MidoriLocationEntry* location_entry,
#endif #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<b>%s</b>%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<b>%s</b>%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<span color='gray45'>%s</span>",
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 static void
midori_location_entry_init (MidoriLocationEntry* location_entry) midori_location_entry_init (MidoriLocationEntry* location_entry)
{ {
GtkWidget* 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" gtk_rc_parse_string ("style \"midori-location-entry-style\" {\n"
" GtkComboBox::appears-as-list = 1\n }\n" " GtkComboBox::appears-as-list = 1\n }\n"
"widget_class \"*MidoriLocationEntry\" " "widget_class \"*MidoriLocationEntry\" "
@ -674,57 +392,17 @@ midori_location_entry_init (MidoriLocationEntry* location_entry)
entry = gtk_icon_entry_new (); entry = gtk_icon_entry_new ();
gtk_icon_entry_set_icon_from_stock (GTK_ICON_ENTRY (entry), 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_signal_connect_after (entry, "key-press-event",
G_CALLBACK (entry_key_press_event), location_entry); G_CALLBACK (entry_key_press_event), location_entry);
#ifdef HAVE_ENTRY_PROGRESS #ifdef HAVE_ENTRY_PROGRESS
g_signal_connect_after (entry, "expose-event", g_signal_connect_after (entry, "expose-event",
G_CALLBACK (entry_expose_event), location_entry); G_CALLBACK (entry_expose_event), location_entry);
#endif #endif
gtk_widget_show (entry); gtk_widget_show (entry);
gtk_container_add (GTK_CONTAINER (location_entry), 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 static gboolean
@ -746,101 +424,6 @@ entry_key_press_event (GtkWidget* widget,
return FALSE; 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: * midori_location_entry_new:
* *
@ -853,279 +436,3 @@ midori_location_entry_new (void)
{ {
return g_object_new (MIDORI_TYPE_LOCATION_ENTRY, NULL); 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);
}
}

View file

@ -27,56 +27,12 @@ typedef struct _MidoriLocationEntry MidoriLocationEntry;
typedef struct _MidoriLocationEntryClass MidoriLocationEntryClass; typedef struct _MidoriLocationEntryClass MidoriLocationEntryClass;
typedef struct _MidoriLocationEntryItem MidoriLocationEntryItem; typedef struct _MidoriLocationEntryItem MidoriLocationEntryItem;
struct _MidoriLocationEntryItem
{
GdkPixbuf* favicon;
const gchar* uri;
const gchar* title;
};
GType GType
midori_location_entry_get_type (void); midori_location_entry_get_type (void);
GtkWidget* GtkWidget*
midori_location_entry_new (void); 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 void
midori_location_entry_set_progress (MidoriLocationEntry* location_entry, midori_location_entry_set_progress (MidoriLocationEntry* location_entry,
gdouble progress); gdouble progress);