diff options
author | Cosimo Cecchi <cosimoc@gnome.org> | 2012-01-19 03:08:09 +0800 |
---|---|---|
committer | Cosimo Cecchi <cosimoc@gnome.org> | 2012-01-20 02:07:23 +0800 |
commit | e62275191c520024b3b48dd2bdecbfb407e105e1 (patch) | |
tree | 4d2edd491ef3c4290802e5e60b4f0a633616f0bd /src/ephy-location-controller.c | |
parent | 2082e3a96b3aed97adc615e7739cec6afea5d76e (diff) | |
download | gsoc2013-epiphany-e62275191c520024b3b48dd2bdecbfb407e105e1.tar.gz gsoc2013-epiphany-e62275191c520024b3b48dd2bdecbfb407e105e1.tar.zst gsoc2013-epiphany-e62275191c520024b3b48dd2bdecbfb407e105e1.zip |
Rename EphyLocationAction -> EphyLocationController
Since it's not a GtkAction anymore.
https://bugzilla.gnome.org/show_bug.cgi?id=668206
Diffstat (limited to 'src/ephy-location-controller.c')
-rw-r--r-- | src/ephy-location-controller.c | 914 |
1 files changed, 914 insertions, 0 deletions
diff --git a/src/ephy-location-controller.c b/src/ephy-location-controller.c new file mode 100644 index 000000000..4c447ec56 --- /dev/null +++ b/src/ephy-location-controller.c @@ -0,0 +1,914 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright © 2003, 2004 Marco Pesenti Gritti + * Copyright © 2003, 2004 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "ephy-location-controller.h" + +#include "ephy-completion-model.h" +#include "ephy-debug.h" +#include "ephy-embed-container.h" +#include "ephy-embed-utils.h" +#include "ephy-link.h" +#include "ephy-location-entry.h" +#include "ephy-shell.h" + +#include <gdk/gdkkeysyms.h> +#include <gtk/gtk.h> +#include <string.h> + +/** + * SECTION:ephy-location-controller + * @short_description: An #EphyLink implementation + * + * #EphyLocationController handles navigation together with #EphyLocationEntry + */ + +#define EPHY_LOCATION_CONTROLLER_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), EPHY_TYPE_LOCATION_CONTROLLER, EphyLocationControllerPrivate)) + +struct _EphyLocationControllerPrivate +{ + EphyWindow *window; + EphyLocationEntry *location_entry; + GtkWidget *proxy; + GList *actions; + char *address; + EphyNode *smart_bmks; + EphyBookmarks *bookmarks; + GdkPixbuf *icon; + char *lock_stock_id; + char *lock_tooltip; + guint editable : 1; + guint show_lock : 1; + gboolean sync_address_is_blocked; +}; + +static void ephy_location_controller_init (EphyLocationController *controller); +static void ephy_location_controller_class_init (EphyLocationControllerClass *class); +static void ephy_location_controller_finalize (GObject *object); +static void user_changed_cb (GtkWidget *proxy, + EphyLocationController *controller); +static void sync_address (EphyLocationController *controller, + GParamSpec *pspec, + GtkWidget *proxy); + +enum +{ + PROP_0, + PROP_ADDRESS, + PROP_EDITABLE, + PROP_ICON, + PROP_LOCK_STOCK, + PROP_LOCK_TOOLTIP, + PROP_SHOW_LOCK, + PROP_WINDOW, + PROP_LOCATION_ENTRY +}; + +enum +{ + LOCK_CLICKED, + LAST_SIGNAL +}; +static guint signals[LAST_SIGNAL]; + +G_DEFINE_TYPE_WITH_CODE (EphyLocationController, ephy_location_controller, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (EPHY_TYPE_LINK, + NULL)) + +static gboolean +match_func (GtkEntryCompletion *completion, + const char *key, + GtkTreeIter *iter, + gpointer data) +{ + char *item = NULL; + char *url = NULL; + char *keywords = NULL; + + gboolean ret = FALSE; + GtkTreeModel *model; + GSList *search_terms; + + model = gtk_entry_completion_get_model (completion); + + gtk_tree_model_get (model, iter, + EPHY_COMPLETION_TEXT_COL, &item, + EPHY_COMPLETION_URL_COL, &url, + EPHY_COMPLETION_KEYWORDS_COL, &keywords, + -1); + + if (!key) + return FALSE; + + search_terms = ephy_location_entry_get_search_terms (data); + + if (search_terms) + { + GSList *iter; + GRegex *current = NULL; + + ret = TRUE; + for (iter = search_terms; iter != NULL; iter = iter->next) + { + current = (GRegex*) iter->data; + if ((!g_regex_match (current, item, G_REGEX_MATCH_NOTEMPTY, NULL)) && + (!g_regex_match (current, url, G_REGEX_MATCH_NOTEMPTY, NULL)) && + (!g_regex_match (current, keywords, G_REGEX_MATCH_NOTEMPTY, NULL))) + { + ret = FALSE; + break; + } + } + } + + g_free (item); + g_free (url); + g_free (keywords); + + return ret; +} + +static void +action_activated_cb (GtkEntryCompletion *completion, + gint index, + EphyLocationController *controller) +{ + GtkWidget *entry; + char *content; + + entry = gtk_entry_completion_get_entry (completion); + content = gtk_editable_get_chars (GTK_EDITABLE (entry), 0, -1); + if (content) + { + EphyNode *node; + const char *smart_url; + char *url; + + node = (EphyNode *)g_list_nth_data (controller->priv->actions, index); + smart_url = ephy_node_get_property_string + (node, EPHY_NODE_BMK_PROP_LOCATION); + g_return_if_fail (smart_url != NULL); + + url = ephy_bookmarks_resolve_address + (controller->priv->bookmarks, smart_url, content); + g_free (content); + if (url == NULL) return; + + ephy_link_open (EPHY_LINK (controller), url, NULL, + ephy_link_flags_from_current_event ()); + + g_free (url); + } +} + +static void +entry_activate_cb (GtkEntry *entry, + EphyLocationController *controller) +{ + EphyBookmarks *bookmarks; + const char *content; + char *address; + EphyLocationControllerPrivate *priv; + + priv = controller->priv; + + if (priv->sync_address_is_blocked) + { + priv->sync_address_is_blocked = FALSE; + g_signal_handlers_unblock_by_func (controller, G_CALLBACK (sync_address), entry); + } + + content = gtk_entry_get_text (entry); + if (content == NULL || content[0] == '\0') return; + + bookmarks = ephy_shell_get_bookmarks (ephy_shell_get_default ()); + + address = ephy_bookmarks_resolve_address (bookmarks, content, NULL); + g_return_if_fail (address != NULL); + + ephy_link_open (EPHY_LINK (controller), g_strstrip (address), NULL, + ephy_link_flags_from_current_event ()); + + g_free (address); +} + +static void +user_changed_cb (GtkWidget *proxy, EphyLocationController *controller) +{ + const char *address; + + address = ephy_location_entry_get_location (EPHY_LOCATION_ENTRY (proxy)); + + LOG ("user_changed_cb, new address %s", address); + + g_signal_handlers_block_by_func (controller, G_CALLBACK (sync_address), proxy); + ephy_location_controller_set_address (controller, address); + g_signal_handlers_unblock_by_func (controller, G_CALLBACK (sync_address), proxy); +} + +static void +lock_clicked_cb (GtkWidget *proxy, + EphyLocationController *controller) +{ + g_signal_emit (controller, signals[LOCK_CLICKED], 0); +} + +static void +sync_address (EphyLocationController *controller, + GParamSpec *pspec, + GtkWidget *widget) +{ + EphyLocationControllerPrivate *priv = controller->priv; + EphyLocationEntry *lentry = EPHY_LOCATION_ENTRY (widget); + + LOG ("sync_address %s", controller->priv->address); + + g_signal_handlers_block_by_func (widget, G_CALLBACK (user_changed_cb), controller); + ephy_location_entry_set_location (lentry, priv->address); + g_signal_handlers_unblock_by_func (widget, G_CALLBACK (user_changed_cb), controller); +} + +static void +sync_editable (EphyLocationController *controller, + GParamSpec *pspec, + GtkWidget *widget) +{ + EphyLocationEntry *lentry = EPHY_LOCATION_ENTRY (widget); + + gtk_editable_set_editable (GTK_EDITABLE (lentry), controller->priv->editable); +} + +static void +sync_icon (EphyLocationController *controller, + GParamSpec *pspec, + GtkWidget *widget) +{ + EphyLocationControllerPrivate *priv = controller->priv; + EphyLocationEntry *entry = EPHY_LOCATION_ENTRY (widget); + + ephy_location_entry_set_favicon (entry, priv->icon); +} + +static void +sync_lock_stock_id (EphyLocationController *controller, + GParamSpec *pspec, + GtkWidget *widget) +{ + EphyLocationControllerPrivate *priv = controller->priv; + EphyLocationEntry *entry = EPHY_LOCATION_ENTRY (widget); + + ephy_location_entry_set_lock_stock (entry, priv->lock_stock_id); +} + +static void +sync_lock_tooltip (EphyLocationController *controller, + GParamSpec *pspec, + GtkWidget *widget) +{ + EphyLocationControllerPrivate *priv = controller->priv; + EphyLocationEntry *entry = EPHY_LOCATION_ENTRY (widget); + + ephy_location_entry_set_lock_tooltip (entry, priv->lock_tooltip); +} + +static void +sync_show_lock (EphyLocationController *controller, + GParamSpec *pspec, + GtkWidget *widget) +{ + EphyLocationControllerPrivate *priv = controller->priv; + EphyLocationEntry *entry = EPHY_LOCATION_ENTRY (widget); + + ephy_location_entry_set_show_lock (entry, priv->show_lock); +} + +static char * +get_location_cb (EphyLocationEntry *entry, + EphyLocationController *controller) +{ + EphyLocationControllerPrivate *priv = controller->priv; + EphyEmbed *embed; + + embed = ephy_embed_container_get_active_child + (EPHY_EMBED_CONTAINER (priv->window)); + + return g_strdup (ephy_web_view_get_address (ephy_embed_get_web_view (embed))); +} + +static char * +get_title_cb (EphyLocationEntry *entry, + EphyLocationController *controller) +{ + EphyEmbed *embed; + + embed = ephy_embed_container_get_active_child + (EPHY_EMBED_CONTAINER (controller->priv->window)); + + return g_strdup (ephy_web_view_get_title (ephy_embed_get_web_view (embed))); +} + +static void +remove_completion_actions (EphyLocationController *controller, + EphyLocationEntry *lentry) +{ + GtkEntryCompletion *completion; + GList *l; + + completion = gtk_entry_get_completion (GTK_ENTRY (lentry)); + + for (l = controller->priv->actions; l != NULL; l = l->next) + { + gtk_entry_completion_delete_action (completion, 0); + } + + g_signal_handlers_disconnect_by_func + (completion, G_CALLBACK (action_activated_cb), controller); +} + +static void +add_completion_actions (EphyLocationController *controller, + EphyLocationEntry *lentry) +{ + GtkEntryCompletion *completion; + GList *l; + + completion = gtk_entry_get_completion (GTK_ENTRY (lentry)); + + for (l = controller->priv->actions; l != NULL; l = l->next) + { + EphyNode *bmk = l->data; + const char *title; + int index; + + index = g_list_position (controller->priv->actions, l); + title = ephy_node_get_property_string + (bmk, EPHY_NODE_BMK_PROP_TITLE); + gtk_entry_completion_insert_action_text (completion, index, (char*)title); + } + + g_signal_connect (completion, "action_activated", + G_CALLBACK (action_activated_cb), controller); +} + +static gboolean +focus_in_event_cb (GtkWidget *entry, + GdkEventFocus *event, + EphyLocationController *controller) +{ + EphyLocationControllerPrivate *priv = controller->priv; + + if (!priv->sync_address_is_blocked) + { + priv->sync_address_is_blocked = TRUE; + g_signal_handlers_block_by_func (controller, G_CALLBACK (sync_address), entry); + } + + return FALSE; +} + +static gboolean +focus_out_event_cb (GtkWidget *entry, + GdkEventFocus *event, + EphyLocationController *controller) +{ + EphyLocationControllerPrivate *priv = controller->priv; + + if (priv->sync_address_is_blocked) + { + priv->sync_address_is_blocked = FALSE; + g_signal_handlers_unblock_by_func (controller, G_CALLBACK (sync_address), entry); + } + + return FALSE; +} + +static void +switch_page_cb (GtkNotebook *notebook, + GtkWidget *page, + guint page_num, + EphyLocationController *controller) +{ + EphyLocationControllerPrivate *priv = controller->priv; + + if (priv->sync_address_is_blocked == TRUE) + { + priv->sync_address_is_blocked = FALSE; + g_signal_handlers_unblock_by_func (controller, G_CALLBACK (sync_address), priv->proxy); + } +} + +static void +ephy_location_controller_constructed (GObject *object) +{ + EphyLocationController *controller = EPHY_LOCATION_CONTROLLER (object); + EphyLocationControllerPrivate *priv = controller->priv; + EphyCompletionModel *model; + GtkWidget *notebook, *widget; + + G_OBJECT_CLASS (ephy_location_controller_parent_class)->constructed (object); + + notebook = ephy_window_get_notebook (priv->window); + widget = GTK_WIDGET (priv->location_entry); + + g_signal_connect (notebook, "switch-page", + G_CALLBACK (switch_page_cb), controller); + + model = ephy_completion_model_new (); + ephy_location_entry_set_completion (priv->location_entry, + GTK_TREE_MODEL (model), + EPHY_COMPLETION_TEXT_COL, + EPHY_COMPLETION_ACTION_COL, + EPHY_COMPLETION_KEYWORDS_COL, + EPHY_COMPLETION_RELEVANCE_COL, + EPHY_COMPLETION_URL_COL, + EPHY_COMPLETION_EXTRA_COL, + EPHY_COMPLETION_FAVICON_COL); + g_object_unref (model); + + ephy_location_entry_set_match_func (priv->location_entry, + match_func, + priv->location_entry, + NULL); + + add_completion_actions (controller, priv->location_entry); + + sync_address (controller, NULL, widget); + g_signal_connect_object (controller, "notify::address", + G_CALLBACK (sync_address), widget, 0); + sync_editable (controller, NULL, widget); + g_signal_connect_object (controller, "notify::editable", + G_CALLBACK (sync_editable), widget, 0); + sync_icon (controller, NULL, widget); + g_signal_connect_object (controller, "notify::icon", + G_CALLBACK (sync_icon), widget, 0); + sync_lock_stock_id (controller, NULL, widget); + g_signal_connect_object (controller, "notify::lock-stock-id", + G_CALLBACK (sync_lock_stock_id), widget, 0); + sync_lock_tooltip (controller, NULL, widget); + g_signal_connect_object (controller, "notify::lock-tooltip", + G_CALLBACK (sync_lock_tooltip), widget, 0); + sync_show_lock (controller, NULL, widget); + g_signal_connect_object (controller, "notify::show-lock", + G_CALLBACK (sync_show_lock), widget, 0); + + g_signal_connect_object (widget, "activate", + G_CALLBACK (entry_activate_cb), + controller, 0); + g_signal_connect_object (widget, "user-changed", + G_CALLBACK (user_changed_cb), controller, 0); + g_signal_connect_object (widget, "lock-clicked", + G_CALLBACK (lock_clicked_cb), controller, 0); + g_signal_connect_object (widget, "get-location", + G_CALLBACK (get_location_cb), controller, 0); + g_signal_connect_object (widget, "get-title", + G_CALLBACK (get_title_cb), controller, 0); + g_signal_connect_object (widget, "focus-in-event", + G_CALLBACK (focus_in_event_cb), controller, 0); + g_signal_connect_object (widget, "focus-out-event", + G_CALLBACK (focus_out_event_cb), controller, 0); +} + +static void +ephy_location_controller_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + EphyLocationController *controller = EPHY_LOCATION_CONTROLLER (object); + EphyLocationControllerPrivate *priv = controller->priv; + + switch (prop_id) + { + case PROP_ADDRESS: + ephy_location_controller_set_address (controller, g_value_get_string (value)); + break; + case PROP_EDITABLE: + priv->editable = g_value_get_boolean (value); + break; + case PROP_ICON: + if (priv->icon != NULL) + { + g_object_unref (priv->icon); + } + priv->icon = GDK_PIXBUF (g_value_dup_object (value)); + break; + case PROP_LOCK_STOCK: + g_free (priv->lock_stock_id); + priv->lock_stock_id = g_value_dup_string (value); + break; + case PROP_LOCK_TOOLTIP: + g_free (priv->lock_tooltip); + priv->lock_tooltip = g_value_dup_string (value); + break; + case PROP_SHOW_LOCK: + priv->show_lock = g_value_get_boolean (value); + break; + case PROP_WINDOW: + priv->window = EPHY_WINDOW (g_value_get_object (value)); + break; + case PROP_LOCATION_ENTRY: + priv->location_entry = EPHY_LOCATION_ENTRY (g_value_get_object (value)); + break; + } +} + +static void +ephy_location_controller_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + EphyLocationController *controller = EPHY_LOCATION_CONTROLLER (object); + EphyLocationControllerPrivate *priv = controller->priv; + + switch (prop_id) + { + case PROP_ADDRESS: + g_value_set_string (value, ephy_location_controller_get_address (controller)); + break; + case PROP_EDITABLE: + g_value_set_boolean (value, priv->editable); + break; + case PROP_ICON: + g_value_set_object (value, priv->icon); + break; + case PROP_LOCK_STOCK: + g_value_set_string (value, priv->lock_stock_id); + break; + case PROP_LOCK_TOOLTIP: + g_value_set_string (value, priv->lock_tooltip); + break; + case PROP_SHOW_LOCK: + g_value_set_boolean (value, priv->show_lock); + break; + case PROP_WINDOW: + case PROP_LOCATION_ENTRY: + /* not readable */ + break; + } +} + +static void +ephy_location_controller_dispose (GObject *object) +{ + EphyLocationController *controller = EPHY_LOCATION_CONTROLLER (object); + EphyLocationControllerPrivate *priv = controller->priv; + GtkWidget *notebook; + + notebook = ephy_window_get_notebook (priv->window); + + if (notebook == NULL || + priv->location_entry == NULL) { + return; + } + + g_signal_handlers_disconnect_matched (controller, G_SIGNAL_MATCH_DATA, + 0, 0, NULL, NULL, priv->location_entry); + g_signal_handlers_disconnect_matched (priv->location_entry, G_SIGNAL_MATCH_DATA, + 0, 0, NULL, NULL, controller); + g_signal_handlers_disconnect_matched (notebook, G_SIGNAL_MATCH_DATA, + 0, 0, NULL, NULL, controller); + priv->location_entry = NULL; + + G_OBJECT_CLASS (ephy_location_controller_parent_class)->dispose (object); +} + +static void +ephy_location_controller_class_init (EphyLocationControllerClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + + object_class->finalize = ephy_location_controller_finalize; + object_class->dispose = ephy_location_controller_dispose; + object_class->constructed = ephy_location_controller_constructed; + object_class->get_property = ephy_location_controller_get_property; + object_class->set_property = ephy_location_controller_set_property; + + /** + * EphyLocationController::lock-clicked: + * @controller: the object which received the signal. + * + * Emitted when the user clicks on the security icon of the internal + * #EphyLocationEntry. + */ + signals[LOCK_CLICKED] = g_signal_new ( + "lock-clicked", + EPHY_TYPE_LOCATION_CONTROLLER, + G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EphyLocationControllerClass, lock_clicked), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + + /** + * EphyLocationController:address: + * + * The address of the current location. + */ + g_object_class_install_property (object_class, + PROP_ADDRESS, + g_param_spec_string ("address", + "Address", + "The address of the current location", + "", + G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB)); + + /** + * EphyLocationController:editable: + * + * Whether the location bar entry can be edited. + */ + g_object_class_install_property (object_class, + PROP_EDITABLE, + g_param_spec_boolean ("editable", + "Editable", + "Whether the location bar entry can be edited", + TRUE, + G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB)); + + /** + * EphyLocationController:icon: + * + * The icon corresponding to the current location. + */ + g_object_class_install_property (object_class, + PROP_ICON, + g_param_spec_object ("icon", + "Icon", + "The icon corresponding to the current location", + GDK_TYPE_PIXBUF, + G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB)); + + /** + * EphyLocationController:lock-stock-id: + * + * Stock id of the security icon. + */ + g_object_class_install_property (object_class, + PROP_LOCK_STOCK, + g_param_spec_string ("lock-stock-id", + "Lock Stock ID", + "Stock id of the security icon", + NULL, + G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB)); + + /** + * EphyLocationController:lock-tooltip: + * + * Tooltip for the security icon. + */ + g_object_class_install_property (object_class, + PROP_LOCK_TOOLTIP, + g_param_spec_string ("lock-tooltip", + "Lock Tooltip", + "Tooltip for the security icon", + NULL, + G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB)); + + /** + * EphyLocationController:show-lock: + * + * If we should show the security icon. + */ + g_object_class_install_property (object_class, + PROP_SHOW_LOCK, + g_param_spec_boolean ("show-lock", + "Show Lock", + "If we should show the security icon", + FALSE, + G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB)); + + /** + * EphyLocationController:window: + * + * The parent window. + */ + g_object_class_install_property (object_class, + PROP_WINDOW, + g_param_spec_object ("window", + "Window", + "The parent window", + G_TYPE_OBJECT, + G_PARAM_WRITABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | + G_PARAM_CONSTRUCT_ONLY)); + + /** + * EphyLocationController:location-entry: + * + * The controlled location entry. + */ + g_object_class_install_property (object_class, + PROP_LOCATION_ENTRY, + g_param_spec_object ("location-entry", + "Location entry", + "The controlled location entry", + G_TYPE_OBJECT, + G_PARAM_WRITABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | + G_PARAM_CONSTRUCT_ONLY)); + + g_type_class_add_private (object_class, sizeof (EphyLocationControllerPrivate)); +} + +static int +compare_actions (gconstpointer a, + gconstpointer b) +{ + EphyNode *node_a = (EphyNode *)a; + EphyNode *node_b = (EphyNode *)b; + const char *title1, *title2; + int retval; + + title1 = ephy_node_get_property_string (node_a, EPHY_NODE_BMK_PROP_TITLE); + title2 = ephy_node_get_property_string (node_b, EPHY_NODE_BMK_PROP_TITLE); + + if (title1 == NULL) + { + retval = -1; + } + else if (title2 == NULL) + { + retval = 1; + } + else + { + char *str_a, *str_b; + + str_a = g_utf8_casefold (title1, -1); + str_b = g_utf8_casefold (title2, -1); + retval = g_utf8_collate (str_a, str_b); + g_free (str_a); + g_free (str_b); + } + + return retval; +} + +static void +init_actions_list (EphyLocationController *controller) +{ + GPtrArray *children; + int i; + + children = ephy_node_get_children (controller->priv->smart_bmks); + for (i = 0; i < children->len; i++) + { + EphyNode *kid; + + kid = g_ptr_array_index (children, i); + + controller->priv->actions = g_list_prepend + (controller->priv->actions, kid); + } + + controller->priv->actions = + g_list_sort (controller->priv->actions, (GCompareFunc) compare_actions); +} + +static void +update_actions_list (EphyLocationController *la) +{ + EphyLocationControllerPrivate *priv = la->priv; + + remove_completion_actions (la, priv->location_entry); + + g_list_free (la->priv->actions); + la->priv->actions = NULL; + init_actions_list (la); + + add_completion_actions (la, priv->location_entry); +} + +static void +actions_child_removed_cb (EphyNode *node, + EphyNode *child, + guint old_index, + EphyLocationController *controller) +{ + update_actions_list (controller); +} + +static void +actions_child_added_cb (EphyNode *node, + EphyNode *child, + EphyLocationController *controller) +{ + update_actions_list (controller); +} + +static void +actions_child_changed_cb (EphyNode *node, + EphyNode *child, + guint property_id, + EphyLocationController *controller) +{ + update_actions_list (controller); +} + +static void +ephy_location_controller_init (EphyLocationController *controller) +{ + EphyLocationControllerPrivate *priv; + + priv = controller->priv = EPHY_LOCATION_CONTROLLER_GET_PRIVATE (controller); + + priv->address = g_strdup (""); + priv->editable = TRUE; + priv->bookmarks = ephy_shell_get_bookmarks (ephy_shell); + priv->smart_bmks = ephy_bookmarks_get_smart_bookmarks + (controller->priv->bookmarks); + priv->sync_address_is_blocked = FALSE; + + init_actions_list (controller); + + ephy_node_signal_connect_object (priv->smart_bmks, + EPHY_NODE_CHILD_ADDED, + (EphyNodeCallback)actions_child_added_cb, + G_OBJECT (controller)); + ephy_node_signal_connect_object (priv->smart_bmks, + EPHY_NODE_CHILD_REMOVED, + (EphyNodeCallback)actions_child_removed_cb, + G_OBJECT (controller)); + ephy_node_signal_connect_object (priv->smart_bmks, + EPHY_NODE_CHILD_CHANGED, + (EphyNodeCallback)actions_child_changed_cb, + G_OBJECT (controller)); +} + +static void +ephy_location_controller_finalize (GObject *object) +{ + EphyLocationController *controller = EPHY_LOCATION_CONTROLLER (object); + EphyLocationControllerPrivate *priv = controller->priv; + + if (priv->icon != NULL) + { + g_object_unref (priv->icon); + } + + g_list_free (priv->actions); + g_free (priv->address); + g_free (priv->lock_stock_id); + g_free (priv->lock_tooltip); + + G_OBJECT_CLASS (ephy_location_controller_parent_class)->finalize (object); +} + +/** + * ephy_location_controller_get_address: + * @controller: an #EphyLocationController + * + * Retrieves the currently loaded address. + * + * Returns: the current address + **/ +const char * +ephy_location_controller_get_address (EphyLocationController *controller) +{ + g_return_val_if_fail (EPHY_IS_LOCATION_CONTROLLER (controller), ""); + + return controller->priv->address; +} + +/** + * ephy_location_controller_set_address: + * @controller: an #EphyLocationController + * @address: new address + * + * Sets @address as the address of @controller. + **/ +void +ephy_location_controller_set_address (EphyLocationController *controller, + const char *address) +{ + EphyLocationControllerPrivate *priv; + + g_return_if_fail (EPHY_IS_LOCATION_CONTROLLER (controller)); + + priv = controller->priv; + + LOG ("set_address %s", address); + + g_free (priv->address); + priv->address = g_strdup (address); + + g_object_notify (G_OBJECT (controller), "address"); +} |