2 * Copyright © 2003, 2004 Marco Pesenti Gritti
3 * Copyright © 2003, 2004 Christian Persch
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24 #include "ephy-location-action.h"
25 #include "ephy-location-entry.h"
26 #include "ephy-shell.h"
27 #include "ephy-completion-model.h"
28 #include "ephy-link.h"
29 #include "ephy-debug.h"
31 #include <gdk/gdkkeysyms.h>
32 #include <gtk/gtkentry.h>
33 #include <gtk/gtkstock.h>
34 #include <gtk/gtkimage.h>
35 #include <gtk/gtkentrycompletion.h>
36 #include <gtk/gtkmain.h>
38 #define EPHY_LOCATION_ACTION_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), EPHY_TYPE_LOCATION_ACTION, EphyLocationActionPrivate))
40 struct _EphyLocationActionPrivate
47 EphyBookmarks *bookmarks;
56 static void ephy_location_action_init (EphyLocationAction *action);
57 static void ephy_location_action_class_init (EphyLocationActionClass *class);
58 static void ephy_location_action_finalize (GObject *object);
59 static void user_changed_cb (GtkWidget *proxy,
60 EphyLocationAction *action);
61 static void sync_address (GtkAction *action,
83 static guint signals[LAST_SIGNAL] = { 0 };
85 static GObjectClass *parent_class = NULL;
88 ephy_location_action_get_type (void)
90 static GType type = 0;
92 if (G_UNLIKELY (type == 0))
94 const GTypeInfo type_info =
96 sizeof (EphyLocationActionClass),
98 (GBaseFinalizeFunc) NULL,
99 (GClassInitFunc) ephy_location_action_class_init,
100 (GClassFinalizeFunc) NULL,
102 sizeof (EphyLocationAction),
104 (GInstanceInitFunc) ephy_location_action_init,
107 type = g_type_register_static (EPHY_TYPE_LINK_ACTION,
108 "EphyLocationAction",
116 action_activated_cb (GtkEntryCompletion *completion,
118 EphyLocationAction *action)
123 entry = gtk_entry_completion_get_entry (completion);
124 content = gtk_editable_get_chars (GTK_EDITABLE (entry), 0, -1);
128 const char *smart_url;
131 node = (EphyNode *)g_list_nth_data (action->priv->actions, index);
132 smart_url = ephy_node_get_property_string
133 (node, EPHY_NODE_BMK_PROP_LOCATION);
134 g_return_if_fail (smart_url != NULL);
136 url = ephy_bookmarks_resolve_address
137 (action->priv->bookmarks, smart_url, content);
139 if (url == NULL) return;
141 ephy_link_open (EPHY_LINK (action), url, NULL,
142 ephy_link_flags_from_current_event () | EPHY_LINK_ALLOW_FIXUP);
149 entry_activate_cb (GtkEntry *entry,
150 EphyLocationAction *action)
152 EphyBookmarks *bookmarks;
156 content = gtk_entry_get_text (entry);
157 if (content == NULL || content[0] == '\0') return;
159 bookmarks = ephy_shell_get_bookmarks (ephy_shell_get_default ());
161 address = ephy_bookmarks_resolve_address (bookmarks, content, NULL);
162 g_return_if_fail (address != NULL);
164 ephy_link_open (EPHY_LINK (action), address, NULL,
165 ephy_link_flags_from_current_event () | EPHY_LINK_ALLOW_FIXUP);
171 user_changed_cb (GtkWidget *proxy, EphyLocationAction *action)
175 address = ephy_location_entry_get_location (EPHY_LOCATION_ENTRY (proxy));
177 LOG ("user_changed_cb, new address %s", address);
179 g_signal_handlers_block_by_func (action, G_CALLBACK (sync_address), proxy);
180 ephy_location_action_set_address (action, address, NULL);
181 g_signal_handlers_unblock_by_func (action, G_CALLBACK (sync_address), proxy);
185 lock_clicked_cb (GtkWidget *proxy,
186 EphyLocationAction *action)
188 g_signal_emit (action, signals[LOCK_CLICKED], 0);
192 sync_address (GtkAction *gaction,
196 EphyLocationAction *action = EPHY_LOCATION_ACTION (gaction);
197 EphyLocationActionPrivate *priv = action->priv;
198 EphyLocationEntry *lentry = EPHY_LOCATION_ENTRY (proxy);
200 LOG ("sync_address %s", action->priv->address);
202 g_signal_handlers_block_by_func (proxy, G_CALLBACK (user_changed_cb), action);
203 ephy_location_entry_set_location (lentry, priv->address,
204 priv->typed_address);
205 g_signal_handlers_unblock_by_func (proxy, G_CALLBACK (user_changed_cb), action);
209 sync_editable (GtkAction *gaction,
213 EphyLocationAction *action = EPHY_LOCATION_ACTION (gaction);
214 EphyLocationEntry *lentry = EPHY_LOCATION_ENTRY (proxy);
217 entry = ephy_location_entry_get_entry (lentry);
218 gtk_editable_set_editable (GTK_EDITABLE (entry), action->priv->editable);
222 sync_icon (GtkAction *gaction,
226 EphyLocationAction *action = EPHY_LOCATION_ACTION (gaction);
227 EphyLocationActionPrivate *priv = action->priv;
228 EphyLocationEntry *entry = EPHY_LOCATION_ENTRY (proxy);
230 ephy_location_entry_set_favicon (entry, priv->icon);
234 sync_lock_stock_id (GtkAction *gaction,
238 EphyLocationAction *action = EPHY_LOCATION_ACTION (gaction);
239 EphyLocationActionPrivate *priv = action->priv;
240 EphyLocationEntry *entry = EPHY_LOCATION_ENTRY (proxy);
242 ephy_location_entry_set_lock_stock (entry, priv->lock_stock_id);
246 sync_lock_tooltip (GtkAction *gaction,
250 EphyLocationAction *action = EPHY_LOCATION_ACTION (gaction);
251 EphyLocationActionPrivate *priv = action->priv;
252 EphyLocationEntry *entry = EPHY_LOCATION_ENTRY (proxy);
254 ephy_location_entry_set_lock_tooltip (entry, priv->lock_tooltip);
258 sync_secure (GtkAction *gaction,
262 EphyLocationAction *action = EPHY_LOCATION_ACTION (gaction);
263 EphyLocationActionPrivate *priv = action->priv;
264 EphyLocationEntry *entry = EPHY_LOCATION_ENTRY (proxy);
266 ephy_location_entry_set_secure (entry, priv->secure);
270 sync_show_lock (GtkAction *gaction,
274 EphyLocationAction *action = EPHY_LOCATION_ACTION (gaction);
275 EphyLocationActionPrivate *priv = action->priv;
276 EphyLocationEntry *entry = EPHY_LOCATION_ENTRY (proxy);
278 ephy_location_entry_set_show_lock (entry, priv->show_lock);
282 get_location_cb (EphyLocationEntry *entry,
283 EphyLocationAction *action)
285 EphyLocationActionPrivate *priv = action->priv;
288 tab = ephy_window_get_active_tab (priv->window);
289 g_return_val_if_fail (tab != NULL, NULL);
291 return g_strdup (ephy_tab_get_address (tab));
295 get_title_cb (EphyLocationEntry *entry,
296 EphyLocationAction *action)
300 tab = ephy_window_get_active_tab (action->priv->window);
302 return g_strdup (ephy_tab_get_title (tab));
306 remove_completion_actions (GtkAction *gaction,
309 EphyLocationAction *action = EPHY_LOCATION_ACTION (gaction);
310 EphyLocationEntry *lentry = EPHY_LOCATION_ENTRY (proxy);
312 GtkEntryCompletion *completion;
315 entry = ephy_location_entry_get_entry (lentry);
316 completion = gtk_entry_get_completion (GTK_ENTRY (entry));
318 for (l = action->priv->actions; l != NULL; l = l->next)
320 gtk_entry_completion_delete_action (completion, 0);
323 g_signal_handlers_disconnect_by_func
324 (completion, G_CALLBACK (action_activated_cb), action);
328 add_completion_actions (GtkAction *gaction,
331 EphyLocationAction *action = EPHY_LOCATION_ACTION (gaction);
332 EphyLocationEntry *lentry = EPHY_LOCATION_ENTRY (proxy);
334 GtkEntryCompletion *completion;
337 entry = ephy_location_entry_get_entry (lentry);
338 completion = gtk_entry_get_completion (GTK_ENTRY (entry));
340 for (l = action->priv->actions; l != NULL; l = l->next)
342 EphyNode *bmk = l->data;
346 index = g_list_position (action->priv->actions, l);
347 title = ephy_node_get_property_string
348 (bmk, EPHY_NODE_BMK_PROP_TITLE);
349 gtk_entry_completion_insert_action_text (completion, index, (char*)title);
352 g_signal_connect (completion, "action_activated",
353 G_CALLBACK (action_activated_cb), action);
357 connect_proxy (GtkAction *action, GtkWidget *proxy)
359 if (EPHY_IS_LOCATION_ENTRY (proxy))
361 EphyLocationEntry *lentry = EPHY_LOCATION_ENTRY (proxy);
362 EphyCompletionModel *model;
365 model = ephy_completion_model_new ();
366 ephy_location_entry_set_completion (EPHY_LOCATION_ENTRY (proxy),
367 GTK_TREE_MODEL (model),
368 EPHY_COMPLETION_TEXT_COL,
369 EPHY_COMPLETION_ACTION_COL,
370 EPHY_COMPLETION_KEYWORDS_COL,
371 EPHY_COMPLETION_RELEVANCE_COL,
372 EPHY_COMPLETION_EXTRA_COL,
373 EPHY_COMPLETION_FAVICON_COL,
374 EPHY_COMPLETION_URL_COL);
376 add_completion_actions (action, proxy);
378 sync_address (action, NULL, proxy);
379 g_signal_connect_object (action, "notify::address",
380 G_CALLBACK (sync_address), proxy, 0);
381 sync_editable (action, NULL, proxy);
382 g_signal_connect_object (action, "notify::editable",
383 G_CALLBACK (sync_editable), proxy, 0);
384 sync_icon (action, NULL, proxy);
385 g_signal_connect_object (action, "notify::icon",
386 G_CALLBACK (sync_icon), proxy, 0);
387 sync_lock_stock_id (action, NULL, proxy);
388 g_signal_connect_object (action, "notify::lock-stock-id",
389 G_CALLBACK (sync_lock_stock_id), proxy, 0);
390 sync_lock_tooltip (action, NULL, proxy);
391 g_signal_connect_object (action, "notify::lock-tooltip",
392 G_CALLBACK (sync_lock_tooltip), proxy, 0);
393 sync_secure (action, NULL, proxy);
394 g_signal_connect_object (action, "notify::secure",
395 G_CALLBACK (sync_secure), proxy, 0);
396 sync_show_lock (action, NULL, proxy);
397 g_signal_connect_object (action, "notify::show-lock",
398 G_CALLBACK (sync_show_lock), proxy, 0);
400 entry = ephy_location_entry_get_entry (lentry);
401 g_signal_connect_object (entry, "activate",
402 G_CALLBACK (entry_activate_cb),
404 g_signal_connect_object (proxy, "user-changed",
405 G_CALLBACK (user_changed_cb), action, 0);
406 g_signal_connect_object (proxy, "lock-clicked",
407 G_CALLBACK (lock_clicked_cb), action, 0);
408 g_signal_connect_object (proxy, "get-location",
409 G_CALLBACK (get_location_cb), action, 0);
410 g_signal_connect_object (proxy, "get-title",
411 G_CALLBACK (get_title_cb), action, 0);
414 GTK_ACTION_CLASS (parent_class)->connect_proxy (action, proxy);
418 disconnect_proxy (GtkAction *action, GtkWidget *proxy)
420 GTK_ACTION_CLASS (parent_class)->disconnect_proxy (action, proxy);
422 if (EPHY_IS_LOCATION_ENTRY (proxy))
424 EphyLocationEntry *lentry = EPHY_LOCATION_ENTRY (proxy);
427 entry = ephy_location_entry_get_entry (lentry);
429 g_signal_handlers_disconnect_matched (action, G_SIGNAL_MATCH_DATA,
430 0, 0, NULL, NULL, proxy);
431 g_signal_handlers_disconnect_matched (proxy, G_SIGNAL_MATCH_DATA,
432 0, 0, NULL, NULL, action);
433 g_signal_handlers_disconnect_matched (entry, G_SIGNAL_MATCH_DATA,
434 0, 0, NULL, NULL, action);
439 ephy_location_action_set_property (GObject *object,
444 EphyLocationAction *action = EPHY_LOCATION_ACTION (object);
445 EphyLocationActionPrivate *priv = action->priv;
450 ephy_location_action_set_address (action, g_value_get_string (value), NULL);
453 priv->editable = g_value_get_boolean (value);
456 if (priv->icon != NULL)
458 g_object_unref (priv->icon);
460 priv->icon = GDK_PIXBUF (g_value_dup_object (value));
462 case PROP_LOCK_STOCK:
463 g_free (priv->lock_stock_id);
464 priv->lock_stock_id = g_value_dup_string (value);
466 case PROP_LOCK_TOOLTIP:
467 g_free (priv->lock_tooltip);
468 priv->lock_tooltip = g_value_dup_string (value);
471 priv->secure = g_value_get_boolean (value);
474 priv->show_lock = g_value_get_boolean (value);
477 priv->window = EPHY_WINDOW (g_value_get_object (value));
483 ephy_location_action_get_property (GObject *object,
488 EphyLocationAction *action = EPHY_LOCATION_ACTION (object);
489 EphyLocationActionPrivate *priv = action->priv;
494 g_value_set_string (value, ephy_location_action_get_address (action));
497 g_value_set_boolean (value, priv->editable);
500 g_value_set_object (value, priv->icon);
502 case PROP_LOCK_STOCK:
503 g_value_set_string (value, priv->lock_stock_id);
505 case PROP_LOCK_TOOLTIP:
506 g_value_set_string (value, priv->lock_tooltip);
509 g_value_set_boolean (value, priv->secure);
512 g_value_set_boolean (value, priv->show_lock);
521 ephy_location_action_class_init (EphyLocationActionClass *class)
523 GObjectClass *object_class = G_OBJECT_CLASS (class);
524 GtkActionClass *action_class = GTK_ACTION_CLASS (class);
526 parent_class = g_type_class_peek_parent (class);
528 object_class->finalize = ephy_location_action_finalize;
529 object_class->get_property = ephy_location_action_get_property;
530 object_class->set_property = ephy_location_action_set_property;
532 action_class->toolbar_item_type = EPHY_TYPE_LOCATION_ENTRY;
533 action_class->connect_proxy = connect_proxy;
534 action_class->disconnect_proxy = disconnect_proxy;
536 signals[LOCK_CLICKED] = g_signal_new (
538 EPHY_TYPE_LOCATION_ACTION,
539 G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST,
540 G_STRUCT_OFFSET (EphyLocationActionClass, lock_clicked),
542 g_cclosure_marshal_VOID__VOID,
546 g_object_class_install_property (object_class,
548 g_param_spec_string ("address",
552 G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
553 g_object_class_install_property (object_class,
555 g_param_spec_boolean ("editable",
559 G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
561 g_object_class_install_property (object_class,
563 g_param_spec_object ("icon",
567 G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
569 g_object_class_install_property (object_class,
571 g_param_spec_string ("lock-stock-id",
575 G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
577 g_object_class_install_property (object_class,
579 g_param_spec_string ("lock-tooltip",
583 G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
585 g_object_class_install_property (object_class,
587 g_param_spec_boolean ("secure",
591 G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
593 g_object_class_install_property (object_class,
595 g_param_spec_boolean ("show-lock",
599 G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
601 g_object_class_install_property (object_class,
603 g_param_spec_object ("window",
605 "The navigation window",
607 G_PARAM_WRITABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB |
608 G_PARAM_CONSTRUCT_ONLY));
610 g_type_class_add_private (object_class, sizeof (EphyLocationActionPrivate));
614 compare_actions (gconstpointer a,
617 EphyNode *node_a = (EphyNode *)a;
618 EphyNode *node_b = (EphyNode *)b;
619 const char *title1, *title2;
622 title1 = ephy_node_get_property_string (node_a, EPHY_NODE_BMK_PROP_TITLE);
623 title2 = ephy_node_get_property_string (node_b, EPHY_NODE_BMK_PROP_TITLE);
629 else if (title2 == NULL)
637 str_a = g_utf8_casefold (title1, -1);
638 str_b = g_utf8_casefold (title2, -1);
639 retval = g_utf8_collate (str_a, str_b);
648 init_actions_list (EphyLocationAction *action)
653 children = ephy_node_get_children (action->priv->smart_bmks);
654 for (i = 0; i < children->len; i++)
658 kid = g_ptr_array_index (children, i);
660 action->priv->actions = g_list_prepend
661 (action->priv->actions, kid);
664 action->priv->actions =
665 g_list_sort (action->priv->actions, (GCompareFunc) compare_actions);
669 update_actions_list (EphyLocationAction *la)
672 GtkAction *action = GTK_ACTION (la);
674 l = gtk_action_get_proxies (action);
675 for (; l != NULL; l = l->next)
677 remove_completion_actions (action, GTK_WIDGET (l->data));
680 g_list_free (la->priv->actions);
681 la->priv->actions = NULL;
682 init_actions_list (la);
684 l = gtk_action_get_proxies (action);
685 for (; l != NULL; l = l->next)
687 add_completion_actions (action, l->data);
692 actions_child_removed_cb (EphyNode *node,
695 EphyLocationAction *action)
697 update_actions_list (action);
701 actions_child_added_cb (EphyNode *node,
703 EphyLocationAction *action)
705 update_actions_list (action);
709 actions_child_changed_cb (EphyNode *node,
712 EphyLocationAction *action)
714 update_actions_list (action);
718 ephy_location_action_init (EphyLocationAction *action)
720 EphyLocationActionPrivate *priv;
722 priv = action->priv = EPHY_LOCATION_ACTION_GET_PRIVATE (action);
724 priv->address = g_strdup ("");
725 priv->editable = TRUE;
726 priv->bookmarks = ephy_shell_get_bookmarks (ephy_shell);
727 priv->smart_bmks = ephy_bookmarks_get_smart_bookmarks
728 (action->priv->bookmarks);
730 init_actions_list (action);
732 ephy_node_signal_connect_object (priv->smart_bmks,
733 EPHY_NODE_CHILD_ADDED,
734 (EphyNodeCallback)actions_child_added_cb,
736 ephy_node_signal_connect_object (priv->smart_bmks,
737 EPHY_NODE_CHILD_REMOVED,
738 (EphyNodeCallback)actions_child_removed_cb,
740 ephy_node_signal_connect_object (priv->smart_bmks,
741 EPHY_NODE_CHILD_CHANGED,
742 (EphyNodeCallback)actions_child_changed_cb,
747 ephy_location_action_finalize (GObject *object)
749 EphyLocationAction *action = EPHY_LOCATION_ACTION (object);
750 EphyLocationActionPrivate *priv = action->priv;
752 if (priv->icon != NULL)
754 g_object_unref (priv->icon);
757 g_list_free (priv->actions);
758 g_free (priv->address);
759 g_free (priv->typed_address);
760 g_free (priv->lock_stock_id);
761 g_free (priv->lock_tooltip);
763 G_OBJECT_CLASS (parent_class)->finalize (object);
767 ephy_location_action_get_address (EphyLocationAction *action)
769 g_return_val_if_fail (EPHY_IS_LOCATION_ACTION (action), "");
771 return action->priv->address;
775 ephy_location_action_set_address (EphyLocationAction *action,
777 const char *typed_address)
779 EphyLocationActionPrivate *priv;
781 g_return_if_fail (EPHY_IS_LOCATION_ACTION (action));
785 LOG ("set_address %s", address);
787 g_free (priv->address);
788 priv->address = g_strdup (address);
790 g_free (priv->typed_address);
791 priv->typed_address = typed_address ? g_strdup (typed_address) : NULL;
793 g_object_notify (G_OBJECT (action), "address");