diff --git a/midori/Makefile.am b/midori/Makefile.am index 3c327a3f..627c49a5 100644 --- a/midori/Makefile.am +++ b/midori/Makefile.am @@ -32,7 +32,7 @@ midori_SOURCES = \ midori-source.c midori-source.h \ midori-websettings.c midori-websettings.h \ midori-preferences.c midori-preferences.h \ - midori-searchentry.c midori-searchentry.h \ + midori-searchaction.c midori-searchaction.h \ midori-locationentry.c midori-locationentry.h \ midori-locationaction.c midori-locationaction.h \ gjs.c gjs.h \ diff --git a/midori/midori-browser.c b/midori/midori-browser.c index 163ae484..24426dbc 100644 --- a/midori/midori-browser.c +++ b/midori/midori-browser.c @@ -21,8 +21,8 @@ #include "midori-panel.h" #include "midori-addons.h" #include "midori-console.h" -#include "midori-searchentry.h" #include "midori-locationaction.h" +#include "midori-searchaction.h" #include "midori-stock.h" #include "gtkiconentry.h" @@ -1758,30 +1758,75 @@ static void _action_search_activate (GtkAction* action, MidoriBrowser* browser) { - if (!GTK_WIDGET_VISIBLE (browser->search)) - gtk_widget_show (browser->search); if (!GTK_WIDGET_VISIBLE (browser->navigationbar)) gtk_widget_show (browser->navigationbar); - gtk_widget_grab_focus (browser->search); } -static gboolean -midori_browser_search_focus_out_event_cb (GtkWidget* widget, - GdkEventFocus* event, - MidoriBrowser* browser) +static void +_action_search_submit (GtkAction* action, + const gchar* keywords, + gboolean new_tab, + MidoriBrowser* browser) { - gboolean show_navigationbar; - gboolean show_web_search; + guint last_web_search; + KatzeItem* item; + const gchar* url; + gchar* location_entry_search; + gchar* search; - g_object_get (browser->settings, - "show-navigationbar", &show_navigationbar, - "show-web-search", &show_web_search, - NULL); - if (!show_navigationbar) + g_object_get (browser->settings, "last-web-search", &last_web_search, NULL); + item = katze_array_get_nth_item (browser->search_engines, last_web_search); + if (item) + { + location_entry_search = NULL; + url = katze_item_get_uri (item); + } + else /* The location entry search is our fallback */ + { + g_object_get (browser->settings, "location-entry-search", + &location_entry_search, NULL); + url = location_entry_search; + } + if (strstr (url, "%s")) + search = g_strdup_printf (url, keywords); + else + search = g_strconcat (url, " ", keywords, NULL); + + if (new_tab) + midori_browser_add_uri (browser, search); + else + _midori_browser_open_uri (browser, search); + + g_free (search); + g_free (location_entry_search); +} + +static void +_action_search_notify_current_item (GtkAction* action, + GParamSpec* pspec, + MidoriBrowser* browser) +{ + MidoriSearchAction* search_action; + KatzeItem* item; + guint index; + + search_action = MIDORI_SEARCH_ACTION (action); + item = midori_search_action_get_current_item (search_action); + if (item) + index = katze_array_get_item_index (browser->search_engines, item); + else + index = 0; + + g_object_set (browser->settings, "last-web-search", index, NULL); +} + +static void +_action_search_focus_out (GtkAction* action, + MidoriBrowser* browser) +{ + if (GTK_WIDGET_VISIBLE (browser->statusbar) && + !sokoke_object_get_boolean (browser->settings, "show-navigationbar")) gtk_widget_hide (browser->navigationbar); - if (!show_web_search) - gtk_widget_hide (browser->search); - return FALSE; } static void @@ -2092,8 +2137,8 @@ _action_manage_search_engines_activate (GtkAction* action, { GtkWidget* dialog; - dialog = midori_search_entry_get_dialog ( - MIDORI_SEARCH_ENTRY (browser->search)); + dialog = midori_search_action_get_dialog ( + MIDORI_SEARCH_ACTION (_action_by_name (browser, "Search"))); if (GTK_WIDGET_VISIBLE (dialog)) gtk_window_present (GTK_WINDOW (dialog)); else @@ -2523,9 +2568,6 @@ static const GtkActionEntry entries[] = { { "Homepage", STOCK_HOMEPAGE, NULL, "Home", N_("Go to your homepage"), G_CALLBACK (_action_homepage_activate) }, - { "Search", GTK_STOCK_FIND, - N_("_Web Search..."), "k", - N_("Run a web search"), G_CALLBACK (_action_search_activate) }, { "OpenInPageholder", GTK_STOCK_JUMP_TO, N_("Open in Page_holder..."), "", N_("Open the current page in the pageholder"), G_CALLBACK (_action_open_in_panel_activate) }, @@ -2764,7 +2806,7 @@ static const gchar* ui_markup = "" "" "" - "" + "" "" "" "" @@ -2800,43 +2842,6 @@ midori_browser_realize_cb (GtkStyle* style, } } -static void -midori_browser_search_activate_cb (GtkWidget* widget, - MidoriBrowser* browser) -{ - KatzeArray* search_engines; - const gchar* keywords; - guint last_web_search; - KatzeItem* item; - const gchar* url; - gchar* location_entry_search; - gchar* search; - - search_engines = browser->search_engines; - keywords = gtk_entry_get_text (GTK_ENTRY (widget)); - g_object_get (browser->settings, "last-web-search", &last_web_search, NULL); - item = katze_array_get_nth_item (search_engines, last_web_search); - if (item) - { - location_entry_search = NULL; - url = katze_item_get_uri (item); - } - else /* The location entry search is our fallback */ - { - g_object_get (browser->settings, "location-entry-search", - &location_entry_search, NULL); - url = location_entry_search; - } - if (strstr (url, "%s")) - search = g_strdup_printf (url, keywords); - else - search = g_strconcat (url, " ", keywords, NULL); - sokoke_entry_append_completion (GTK_ENTRY (widget), keywords); - _midori_browser_open_uri (browser, search); - g_free (search); - g_free (location_entry_search); -} - static void midori_browser_entry_clear_icon_released_cb (GtkIconEntry* entry, gint icon_pos, @@ -2847,25 +2852,6 @@ midori_browser_entry_clear_icon_released_cb (GtkIconEntry* entry, gtk_entry_set_text (GTK_ENTRY (entry), ""); } -static void -midori_browser_search_notify_current_item_cb (GObject* gobject, - GParamSpec* arg1, - MidoriBrowser* browser) -{ - MidoriSearchEntry* search_entry; - KatzeItem* item; - guint index; - - search_entry = MIDORI_SEARCH_ENTRY (browser->search); - item = midori_search_entry_get_current_item (search_entry); - if (item) - index = katze_array_get_item_index (browser->search_engines, item); - else - index = 0; - - g_object_set (browser->settings, "last-web-search", index, NULL); -} - static void midori_browser_init (MidoriBrowser* browser) { @@ -2958,6 +2944,26 @@ midori_browser_init (MidoriBrowser* browser) action, "L"); g_object_unref (action); + action = g_object_new (MIDORI_TYPE_SEARCH_ACTION, + "name", "Search", + "label", _("_Web Search..."), + "stock-id", GTK_STOCK_FIND, + "tooltip", _("Run a web search"), + NULL); + g_object_connect (action, + "signal::activate", + _action_search_activate, browser, + "signal::submit", + _action_search_submit, browser, + "signal::focus-out", + _action_search_focus_out, browser, + "signal::notify::current-item", + _action_search_notify_current_item, browser, + NULL); + gtk_action_group_add_action_with_accel (browser->action_group, + action, "K"); + g_object_unref (action); + /* Create the menubar */ browser->menubar = gtk_ui_manager_get_widget (ui_manager, "/menubar"); GtkWidget* menuitem = gtk_menu_item_new (); @@ -3009,24 +3015,9 @@ midori_browser_init (MidoriBrowser* browser) g_object_set (_action_by_name (browser, "Back"), "is-important", TRUE, NULL); browser->button_homepage = gtk_ui_manager_get_widget ( ui_manager, "/toolbar_navigation/Homepage"); + browser->search = gtk_ui_manager_get_widget ( + ui_manager, "/toolbar_navigation/Search"); - /* Search */ - browser->search = midori_search_entry_new (); - /* TODO: Make this actively resizable or enlarge to fit contents? - The interface is somewhat awkward and ought to be rethought - Display "show in context menu" search engines as "completion actions" */ - sokoke_entry_setup_completion (GTK_ENTRY (browser->search)); - g_object_connect (browser->search, - "signal::activate", - midori_browser_search_activate_cb, browser, - "signal::focus-out-event", - midori_browser_search_focus_out_event_cb, browser, - "signal::notify::current-item", - midori_browser_search_notify_current_item_cb, browser, - NULL); - toolitem = gtk_tool_item_new (); - gtk_container_add (GTK_CONTAINER (toolitem), browser->search); - gtk_toolbar_insert (GTK_TOOLBAR (browser->navigationbar), toolitem, -1); action = gtk_action_group_get_action (browser->action_group, "Trash"); browser->button_trash = gtk_action_create_tool_item (action); g_signal_connect (browser->button_trash, "clicked", @@ -3398,8 +3389,8 @@ _midori_browser_update_settings (MidoriBrowser* browser) item = katze_array_get_nth_item (browser->search_engines, last_web_search); if (item) - midori_search_entry_set_current_item ( - MIDORI_SEARCH_ENTRY (browser->search), item); + midori_search_action_set_current_item (MIDORI_SEARCH_ACTION ( + _action_by_name (browser, "Search")), item); } gtk_paned_set_position (GTK_PANED (gtk_widget_get_parent (browser->panel)), @@ -3574,8 +3565,8 @@ midori_browser_set_property (GObject* object, ; /* FIXME: Disconnect handlers */ katze_object_assign (browser->search_engines, g_value_get_object (value)); g_object_ref (browser->search_engines); - g_object_set (browser->search, "search-engines", - browser->search_engines, NULL); + midori_search_action_set_search_engines (MIDORI_SEARCH_ACTION ( + _action_by_name (browser, "Search")), browser->search_engines); /* FIXME: Connect to updates */ if (browser->settings) { @@ -3583,7 +3574,8 @@ midori_browser_set_property (GObject* object, &last_web_search, NULL); item = katze_array_get_nth_item (browser->search_engines, last_web_search); - g_object_set (browser->search, "current-item", item, NULL); + midori_search_action_set_current_item (MIDORI_SEARCH_ACTION ( + _action_by_name (browser, "Search")), item); } break; default: diff --git a/midori/midori-searchaction.c b/midori/midori-searchaction.c new file mode 100644 index 00000000..549c60f2 --- /dev/null +++ b/midori/midori-searchaction.c @@ -0,0 +1,1140 @@ +/* + Copyright (C) 2008 Christian Dywan + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + See the file COPYING for the full license text. +*/ + +#include "midori-searchaction.h" + +#include "gtkiconentry.h" +#include "sokoke.h" + +#include +#include +#include +#include + +struct _MidoriSearchAction +{ + GtkAction parent_instance; + + KatzeArray* search_engines; + KatzeItem* current_item; + gchar* text; + + GtkWidget* last_proxy; + + GtkWidget* dialog; + GtkWidget* treeview; + GtkWidget* edit_button; + GtkWidget* remove_button; +}; + +struct _MidoriSearchActionClass +{ + GtkActionClass parent_class; +}; + +G_DEFINE_TYPE (MidoriSearchAction, midori_search_action, GTK_TYPE_ACTION) + +enum +{ + PROP_0, + + PROP_SEARCH_ENGINES, + PROP_CURRENT_ITEM, + PROP_TEXT, + PROP_DIALOG +}; + +enum +{ + SUBMIT, + FOCUS_OUT, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL]; + +static void +midori_search_action_finalize (GObject* object); + +static void +midori_search_action_set_property (GObject* object, + guint prop_id, + const GValue* value, + GParamSpec* pspec); + +static void +midori_search_action_get_property (GObject* object, + guint prop_id, + GValue* value, + GParamSpec* pspec); + +static void +midori_search_action_activate (GtkAction* object); + +static GtkWidget* +midori_search_action_create_tool_item (GtkAction* action); + +static void +midori_search_action_connect_proxy (GtkAction* action, + GtkWidget* proxy); + +static void +midori_search_action_disconnect_proxy (GtkAction* action, + GtkWidget* proxy); + +static void +midori_cclosure_marshal_VOID__STRING_BOOLEAN (GClosure* closure, + GValue* return_value, + guint n_param_values, + const GValue* param_values, + gpointer invocation_hint, + gpointer marshal_data) +{ + typedef void(*GMarshalFunc_VOID__STRING_BOOLEAN) (gpointer data1, + const gchar* arg_1, + gboolean arg_2, + gpointer data2); + register GMarshalFunc_VOID__STRING_BOOLEAN callback; + register GCClosure* cc = (GCClosure*) closure; + register gpointer data1, data2; + + g_return_if_fail (n_param_values == 3); + + if (G_CCLOSURE_SWAP_DATA (closure)) + { + data1 = closure->data; + data2 = g_value_peek_pointer (param_values + 0); + } + else + { + data1 = g_value_peek_pointer (param_values + 0); + data2 = closure->data; + } + callback = (GMarshalFunc_VOID__STRING_BOOLEAN) (marshal_data + ? marshal_data : cc->callback); + callback (data1, + g_value_get_string (param_values + 1), + g_value_get_boolean (param_values + 2), + data2); +} + +static void +midori_search_action_class_init (MidoriSearchActionClass* class) +{ + GObjectClass* gobject_class; + GtkActionClass* action_class; + + signals[SUBMIT] = g_signal_new ("submit", + G_TYPE_FROM_CLASS (class), + (GSignalFlags) (G_SIGNAL_RUN_LAST), + 0, + 0, + NULL, + midori_cclosure_marshal_VOID__STRING_BOOLEAN, + G_TYPE_NONE, 2, + G_TYPE_STRING, + G_TYPE_BOOLEAN); + + signals[FOCUS_OUT] = g_signal_new ("focus-out", + G_TYPE_FROM_CLASS (class), + (GSignalFlags) (G_SIGNAL_RUN_LAST), + 0, + 0, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + gobject_class = G_OBJECT_CLASS (class); + gobject_class->finalize = midori_search_action_finalize; + gobject_class->set_property = midori_search_action_set_property; + gobject_class->get_property = midori_search_action_get_property; + + action_class = GTK_ACTION_CLASS (class); + action_class->activate = midori_search_action_activate; + action_class->create_tool_item = midori_search_action_create_tool_item; + action_class->connect_proxy = midori_search_action_connect_proxy; + action_class->disconnect_proxy = midori_search_action_disconnect_proxy; + + g_object_class_install_property (gobject_class, + PROP_SEARCH_ENGINES, + g_param_spec_object ( + "search-engines", + _("Search Engines"), + _("The list of search engines"), + KATZE_TYPE_ARRAY, + G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, + PROP_CURRENT_ITEM, + g_param_spec_object ( + "current-item", + _("Current Item"), + _("The currently selected item"), + KATZE_TYPE_ITEM, + G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, + PROP_TEXT, + g_param_spec_string ( + "text", + _("Text"), + _("The current text typed in the entry"), + NULL, + G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, + PROP_DIALOG, + g_param_spec_object ( + "dialog", + _("Dialog"), + _("A dialog to manage search engines"), + GTK_TYPE_DIALOG, + G_PARAM_READABLE)); +} + +static void +midori_search_action_init (MidoriSearchAction* search_action) +{ + search_action->search_engines = NULL; + search_action->current_item = NULL; + search_action->text = NULL; + + search_action->last_proxy = NULL; + + search_action->dialog = NULL; + search_action->treeview = NULL; + search_action->edit_button = NULL; + search_action->remove_button = NULL; +} + +static void +midori_search_action_finalize (GObject* object) +{ + MidoriSearchAction* search_action = MIDORI_SEARCH_ACTION (object); + + g_free (search_action->text); + + G_OBJECT_CLASS (midori_search_action_parent_class)->finalize (object); +} + +static void +midori_search_action_set_property (GObject* object, + guint prop_id, + const GValue* value, + GParamSpec* pspec) +{ + MidoriSearchAction* search_action = MIDORI_SEARCH_ACTION (object); + + switch (prop_id) + { + case PROP_SEARCH_ENGINES: + midori_search_action_set_search_engines (search_action, + g_value_get_object (value)); + break; + case PROP_CURRENT_ITEM: + midori_search_action_set_current_item (search_action, + g_value_get_object (value)); + break; + case PROP_TEXT: + midori_search_action_set_text (search_action, + g_value_get_string (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +midori_search_action_get_property (GObject* object, + guint prop_id, + GValue* value, + GParamSpec* pspec) +{ + MidoriSearchAction* search_action = MIDORI_SEARCH_ACTION (object); + + switch (prop_id) + { + case PROP_SEARCH_ENGINES: + g_value_set_object (value, search_action->search_engines); + break; + case PROP_CURRENT_ITEM: + g_value_set_object (value, search_action->current_item); + break; + case PROP_TEXT: + g_value_set_string (value, search_action->text); + break; + case PROP_DIALOG: + g_value_set_object (value, + midori_search_action_get_dialog (search_action)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +midori_search_action_activate (GtkAction* action) +{ + GSList* proxies; + GtkWidget* alignment; + GtkWidget* entry; + + proxies = gtk_action_get_proxies (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)); + + /* Obviously only one widget can end up with the focus. + Yet we can't predict which one that is, can we? */ + gtk_widget_grab_focus (entry); + MIDORI_SEARCH_ACTION (action)->last_proxy = proxies->data; + } + while ((proxies = g_slist_next (proxies))); + + if (GTK_ACTION_CLASS (midori_search_action_parent_class)->activate) + GTK_ACTION_CLASS (midori_search_action_parent_class)->activate (action); +} + +static GtkWidget* +midori_search_action_create_tool_item (GtkAction* action) +{ + GtkWidget* toolitem; + GtkWidget* entry; + GtkWidget* alignment; + + toolitem = GTK_WIDGET (gtk_tool_item_new ()); + entry = gtk_icon_entry_new (); + gtk_icon_entry_set_icon_highlight (GTK_ICON_ENTRY (entry), + GTK_ICON_ENTRY_PRIMARY, TRUE); + alignment = gtk_alignment_new (0, 0.5, 1, 0.1); + gtk_container_add (GTK_CONTAINER (alignment), entry); + gtk_widget_show (entry); + gtk_container_add (GTK_CONTAINER (toolitem), alignment); + gtk_widget_show (alignment); + + MIDORI_SEARCH_ACTION (action)->last_proxy = GTK_WIDGET (toolitem); + return GTK_WIDGET (toolitem); +} + +static void +_midori_search_action_move_index (MidoriSearchAction* search_action, + guint n) +{ + gint i; + KatzeItem* item; + + i = katze_array_get_item_index (search_action->search_engines, + search_action->current_item); + item = katze_array_get_nth_item (search_action->search_engines, i + n); + if (item) + midori_search_action_set_current_item (search_action, item); +} + +static gboolean +midori_search_action_key_press_event_cb (GtkWidget* entry, + GdkEventKey* event, + MidoriSearchAction* search_action) +{ + const gchar* text; + + switch (event->keyval) + { + case GDK_ISO_Enter: + case GDK_KP_Enter: + case GDK_Return: + text = gtk_entry_get_text (GTK_ENTRY (entry)); + g_signal_emit (search_action, signals[SUBMIT], 0, text, + (event->state & GDK_MOD1_MASK) ? TRUE : FALSE); + search_action->last_proxy = entry; + return TRUE; + case GDK_Up: + if (event->state & GDK_CONTROL_MASK) + _midori_search_action_move_index (search_action, - 1); + return TRUE; + case GDK_Down: + if (event->state & GDK_CONTROL_MASK) + _midori_search_action_move_index (search_action, + 1); + return TRUE; + } + + return FALSE; +} + +static gboolean +midori_search_action_focus_out_event_cb (GtkWidget* widget, + GdkEventKey* event, + GtkAction* action) +{ + g_signal_emit (action, signals[FOCUS_OUT], 0); + return FALSE; +} + +static void +midori_search_action_engine_activate_cb (GtkWidget* menuitem, + MidoriSearchAction* search_action) +{ + KatzeItem* item; + + item = (KatzeItem*)g_object_get_data (G_OBJECT (menuitem), "engine"); + midori_search_action_set_current_item (search_action, item); +} + +static void +midori_search_action_manage_activate_cb (GtkWidget* menuitem, + MidoriSearchAction* search_action) +{ + GtkWidget* dialog; + + dialog = midori_search_action_get_dialog (search_action); + if (GTK_WIDGET_VISIBLE (dialog)) + gtk_window_present (GTK_WINDOW (dialog)); + else + gtk_widget_show (dialog); +} + +static void +midori_search_action_icon_released_cb (GtkWidget* entry, + GtkIconEntryPosition icon_pos, + gint button, + GtkAction* action) +{ + if (icon_pos == GTK_ICON_ENTRY_SECONDARY) + return; + + KatzeArray* search_engines; + GtkWidget* menu; + guint n, i; + GtkWidget* menuitem; + KatzeItem* item; + GdkPixbuf* pixbuf; + GtkWidget* icon; + + search_engines = MIDORI_SEARCH_ACTION (action)->search_engines; + menu = gtk_menu_new (); + n = katze_array_get_length (search_engines); + if (n) + { + for (i = 0; i < n; i++) + { + item = katze_array_get_nth_item (search_engines, i); + menuitem = gtk_image_menu_item_new_with_label ( + katze_item_get_name (item)); + pixbuf = sokoke_web_icon (katze_item_get_icon (item), + GTK_ICON_SIZE_MENU, menuitem); + icon = gtk_image_new_from_pixbuf (pixbuf); + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), icon); + g_object_unref (pixbuf); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); + g_object_set_data (G_OBJECT (menuitem), "engine", item); + g_signal_connect (menuitem, "activate", + G_CALLBACK (midori_search_action_engine_activate_cb), action); + gtk_widget_show (menuitem); + } + } + else + { + menuitem = gtk_image_menu_item_new_with_label (_("Empty")); + gtk_widget_set_sensitive (menuitem, FALSE); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); + gtk_widget_show (menuitem); + } + + menuitem = gtk_separator_menu_item_new (); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); + gtk_widget_show (menuitem); + menuitem = gtk_image_menu_item_new_with_mnemonic (_("_Manage Search Engines")); + icon = gtk_image_new_from_stock (GTK_STOCK_PREFERENCES, GTK_ICON_SIZE_MENU); + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), icon); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); + g_signal_connect (menuitem, "activate", + G_CALLBACK (midori_search_action_manage_activate_cb), action); + gtk_widget_show (menuitem); + sokoke_widget_popup (entry, GTK_MENU (menu), + NULL, SOKOKE_MENU_POSITION_LEFT); +} + +static gboolean +midori_search_action_scroll_event_cb (GtkWidget* entry, + GdkEventScroll* event, + MidoriSearchAction* search_action) +{ + if (event->direction == GDK_SCROLL_DOWN) + _midori_search_action_move_index (search_action, + 1); + else if (event->direction == GDK_SCROLL_UP) + _midori_search_action_move_index (search_action, - 1); + return FALSE; +} + +static void +midori_search_action_connect_proxy (GtkAction* action, + GtkWidget* proxy) +{ + GtkWidget* alignment; + GtkWidget* entry; + + GTK_ACTION_CLASS (midori_search_action_parent_class)->connect_proxy ( + action, proxy); + + if (GTK_IS_TOOL_ITEM (proxy)) + { + alignment = gtk_bin_get_child (GTK_BIN (proxy)); + entry = gtk_bin_get_child (GTK_BIN (alignment)); + + g_object_connect (entry, + "signal::key-press-event", + midori_search_action_key_press_event_cb, action, + "signal::focus-out-event", + midori_search_action_focus_out_event_cb, action, + "signal::icon-released", + midori_search_action_icon_released_cb, action, + "signal::scroll-event", + midori_search_action_scroll_event_cb, action, + NULL); + } + + MIDORI_SEARCH_ACTION (action)->last_proxy = proxy; +} + +static void +midori_search_action_disconnect_proxy (GtkAction* action, + GtkWidget* proxy) +{ + GSList* proxies; + + /* FIXME: This is wrong */ + g_signal_handlers_disconnect_by_func (proxy, + G_CALLBACK (gtk_action_activate), action); + + GTK_ACTION_CLASS (midori_search_action_parent_class)->disconnect_proxy + (action, proxy); + + if (MIDORI_SEARCH_ACTION (action)->last_proxy == proxy) + { + proxies = gtk_action_get_proxies (action); + if (proxies) + MIDORI_SEARCH_ACTION (action)->last_proxy = proxies->data; + } +} + +const gchar* +midori_search_action_get_text (MidoriSearchAction* search_action) +{ + g_return_val_if_fail (MIDORI_IS_SEARCH_ACTION (search_action), NULL); + + return search_action->text; +} + +void +midori_search_action_set_text (MidoriSearchAction* search_action, + const gchar* text) +{ + GSList* proxies; + GtkWidget* alignment; + GtkWidget* entry; + + g_return_if_fail (MIDORI_IS_SEARCH_ACTION (search_action)); + g_return_if_fail (text != NULL); + + katze_assign (search_action->text, g_strdup (text)); + g_object_notify (G_OBJECT (search_action), "text"); + + proxies = gtk_action_get_proxies (GTK_ACTION (search_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)); + + gtk_entry_set_text (GTK_ENTRY (entry), text); + search_action->last_proxy = proxies->data; + } + while ((proxies = g_slist_next (proxies))); +} + +KatzeArray* +midori_search_action_get_search_engines (MidoriSearchAction* search_action) +{ + g_return_val_if_fail (MIDORI_IS_SEARCH_ACTION (search_action), NULL); + + return search_action->search_engines; +} + +static void +midori_search_action_engines_add_item_cb (KatzeArray* list, + KatzeItem* item, + MidoriSearchAction* search_action) +{ + if (!search_action->current_item) + midori_search_action_set_current_item (search_action, item); +} + +static void +midori_search_action_engines_remove_item_cb (KatzeArray* list, + KatzeItem* item, + MidoriSearchAction* search_action) +{ + KatzeItem* found_item; + + if (search_action->current_item == item) + { + found_item = katze_array_get_nth_item (list, 0); + midori_search_action_set_current_item (search_action, found_item); + } +} + +void +midori_search_action_set_search_engines (MidoriSearchAction* search_action, + KatzeArray* search_engines) +{ + GSList* proxies; + GtkWidget* alignment; + GtkWidget* entry; + + g_return_if_fail (MIDORI_IS_SEARCH_ACTION (search_action)); + g_return_if_fail (!search_engines || + katze_array_is_a (search_engines, KATZE_TYPE_ITEM)); + + /* FIXME: Disconnect old search engines */ + /* FIXME: Disconnect and reconnect dialog signals */ + + if (search_engines) + g_object_ref (search_engines); + katze_object_assign (search_action->search_engines, search_engines); + + g_object_connect (search_engines, + "signal-after::add-item", + midori_search_action_engines_add_item_cb, search_action, + "signal-after::remove-item", + midori_search_action_engines_remove_item_cb, search_action, + NULL); + + g_object_notify (G_OBJECT (search_action), "search-engines"); + + proxies = gtk_action_get_proxies (GTK_ACTION (search_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)); + + /* FIXME: Unset the current item if it isn't in the list */ + } + while ((proxies = g_slist_next (proxies))); +} + +KatzeItem* +midori_search_action_get_current_item (MidoriSearchAction* search_action) +{ + g_return_val_if_fail (MIDORI_IS_SEARCH_ACTION (search_action), NULL); + + return search_action->current_item; +} + +void +midori_search_action_set_current_item (MidoriSearchAction* search_action, + KatzeItem* item) +{ + GSList* proxies; + GtkWidget* alignment; + GtkWidget* entry; + GdkPixbuf* pixbuf; + + g_return_if_fail (MIDORI_IS_SEARCH_ACTION (search_action)); + g_return_if_fail (!item || KATZE_IS_ITEM (item)); + + if (item) + g_object_ref (item); + katze_object_assign (search_action->current_item, item); + + proxies = gtk_action_get_proxies (GTK_ACTION (search_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)); + + pixbuf = sokoke_web_icon (item ? katze_item_get_icon (item) : NULL, + GTK_ICON_SIZE_MENU, entry); + gtk_icon_entry_set_icon_from_pixbuf (GTK_ICON_ENTRY (entry), + GTK_ICON_ENTRY_PRIMARY, pixbuf); + g_object_unref (pixbuf); + if (item) + sokoke_entry_set_default_text (GTK_ENTRY (entry), + katze_item_get_name (item)); + else + sokoke_entry_set_default_text (GTK_ENTRY (entry), ""); + } + while ((proxies = g_slist_next (proxies))); +} + +static void +midori_search_action_dialog_render_icon_cb (GtkTreeViewColumn* column, + GtkCellRenderer* renderer, + GtkTreeModel* model, + GtkTreeIter* iter, + GtkWidget* treeview) +{ + KatzeItem* item; + const gchar* icon; + GdkPixbuf* pixbuf; + + gtk_tree_model_get (model, iter, 0, &item, -1); + + icon = katze_item_get_icon (item); + if (icon) + { + pixbuf = sokoke_web_icon (icon, GTK_ICON_SIZE_DND, treeview); + g_object_set (renderer, "pixbuf", pixbuf, NULL); + if (pixbuf) + g_object_unref (pixbuf); + } + else + g_object_set (renderer, "pixbuf", NULL, NULL); +} + +static void +midori_search_action_dialog_render_text (GtkTreeViewColumn* column, + GtkCellRenderer* renderer, + GtkTreeModel* model, + GtkTreeIter* iter, + GtkWidget* treeview) +{ + KatzeItem* item; + const gchar* name; + const gchar* text; + gchar* markup; + + gtk_tree_model_get (model, iter, 0, &item, -1); + name = katze_item_get_name (item); + text = katze_item_get_text (item); + markup = g_markup_printf_escaped ("%s\n%s", name, text ? text : ""); + g_object_set (renderer, "markup", markup, NULL); + g_free (markup); +} + +static void +midori_search_action_editor_name_changed_cb (GtkWidget* entry, + GtkWidget* dialog) +{ + const gchar* text = gtk_entry_get_text (GTK_ENTRY (entry)); + gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), + GTK_RESPONSE_ACCEPT, text && *text); +} + +static inline const gchar* +STR_NON_NULL (const gchar* string) +{ + return string ? string : ""; +} + +static void +midori_search_action_get_editor (MidoriSearchAction* search_action, + gboolean new_engine) +{ + GtkWidget* toplevel; + GtkWidget* dialog; + GtkSizeGroup* sizegroup; + KatzeItem* item; + GtkWidget* hbox; + GtkWidget* label; + GtkTreeModel* liststore; + GtkTreeIter iter; + GtkTreeSelection* selection; + GtkWidget* entry_name; + GtkWidget* entry_description; + GtkWidget* entry_uri; + GtkWidget* entry_icon; + GtkWidget* entry_token; + + toplevel = gtk_widget_get_toplevel (search_action->treeview); + dialog = gtk_dialog_new_with_buttons ( + new_engine ? _("Add search engine") : _("Edit search engine"), + toplevel ? GTK_WINDOW (toplevel) : NULL, + GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + new_engine ? GTK_STOCK_ADD : GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, + NULL); + gtk_window_set_icon_name (GTK_WINDOW (dialog), + new_engine ? GTK_STOCK_ADD : GTK_STOCK_REMOVE); + gtk_container_set_border_width (GTK_CONTAINER (dialog), 5); + gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), 5); + sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); + + if (new_engine) + { + item = katze_item_new (); + gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), + GTK_RESPONSE_ACCEPT, FALSE); + } + else + { + selection = gtk_tree_view_get_selection ( + GTK_TREE_VIEW (search_action->treeview)); + gtk_tree_selection_get_selected (selection, &liststore, &iter); + gtk_tree_model_get (liststore, &iter, 0, &item, -1); + } + + hbox = gtk_hbox_new (FALSE, 8); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); + label = gtk_label_new_with_mnemonic (_("_Name:")); + gtk_size_group_add_widget (sizegroup, label); + gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); + entry_name = gtk_entry_new (); + g_signal_connect (entry_name, "changed", + G_CALLBACK (midori_search_action_editor_name_changed_cb), dialog); + gtk_entry_set_activates_default (GTK_ENTRY (entry_name), TRUE); + if (!new_engine) + gtk_entry_set_text (GTK_ENTRY (entry_name), + STR_NON_NULL (katze_item_get_name (item))); + gtk_box_pack_start (GTK_BOX (hbox), entry_name, TRUE, TRUE, 0); + gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), hbox); + gtk_widget_show_all (hbox); + + hbox = gtk_hbox_new (FALSE, 8); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); + label = gtk_label_new_with_mnemonic (_("_Description:")); + gtk_size_group_add_widget (sizegroup, label); + gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); + entry_description = gtk_entry_new (); + gtk_entry_set_activates_default (GTK_ENTRY (entry_description), TRUE); + if (!new_engine) + gtk_entry_set_text (GTK_ENTRY (entry_description) + , STR_NON_NULL (katze_item_get_text (item))); + gtk_box_pack_start (GTK_BOX (hbox), entry_description, TRUE, TRUE, 0); + gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), hbox); + gtk_widget_show_all (hbox); + + hbox = gtk_hbox_new (FALSE, 8); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); + label = gtk_label_new_with_mnemonic (_("_URL:")); + gtk_size_group_add_widget (sizegroup, label); + gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); + entry_uri = gtk_entry_new (); + gtk_entry_set_activates_default (GTK_ENTRY (entry_uri), TRUE); + if (!new_engine) + gtk_entry_set_text (GTK_ENTRY (entry_uri) + , STR_NON_NULL (katze_item_get_uri (item))); + gtk_box_pack_start (GTK_BOX (hbox), entry_uri, TRUE, TRUE, 0); + gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), hbox); + gtk_widget_show_all (hbox); + + hbox = gtk_hbox_new (FALSE, 8); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); + label = gtk_label_new_with_mnemonic (_("_Icon (name or file):")); + gtk_size_group_add_widget (sizegroup, label); + gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); + entry_icon = gtk_entry_new (); + gtk_entry_set_activates_default (GTK_ENTRY (entry_icon), TRUE); + if (!new_engine) + gtk_entry_set_text (GTK_ENTRY (entry_icon) + , STR_NON_NULL (katze_item_get_icon (item))); + gtk_box_pack_start (GTK_BOX (hbox), entry_icon, TRUE, TRUE, 0); + gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), hbox); + gtk_widget_show_all (hbox); + + hbox = gtk_hbox_new (FALSE, 8); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); + label = gtk_label_new_with_mnemonic (_("_Token:")); + gtk_size_group_add_widget (sizegroup, label); + gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); + entry_token = gtk_entry_new (); + gtk_entry_set_activates_default (GTK_ENTRY (entry_token), TRUE); + if (!new_engine) + gtk_entry_set_text (GTK_ENTRY (entry_token) + , STR_NON_NULL (katze_item_get_token (item))); + gtk_box_pack_start (GTK_BOX (hbox), entry_token, TRUE, TRUE, 0); + gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), hbox); + gtk_widget_show_all (hbox); + + gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT); + if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) + { + g_object_set (item, + "name", gtk_entry_get_text (GTK_ENTRY (entry_name)), + "text", gtk_entry_get_text (GTK_ENTRY (entry_description)), + "uri", gtk_entry_get_text (GTK_ENTRY (entry_uri)), + "icon", gtk_entry_get_text (GTK_ENTRY (entry_icon)), + "token", gtk_entry_get_text (GTK_ENTRY (entry_token)), + NULL); + + if (new_engine) + katze_array_add_item (search_action->search_engines, item); + } + gtk_widget_destroy (dialog); +} + +static void +midori_search_action_dialog_add_cb (GtkWidget* widget, + MidoriSearchAction* search_action) +{ + midori_search_action_get_editor (search_action, TRUE); +} + +static void +midori_search_action_dialog_edit_cb (GtkWidget* widget, + MidoriSearchAction* search_action) +{ + GtkWidget* treeview; + GtkTreeSelection* selection; + + treeview = search_action->treeview; + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)); + if (gtk_tree_selection_get_selected (selection, NULL, NULL)) + midori_search_action_get_editor (search_action, FALSE); +} + +static void +midori_search_action_dialog_remove_cb (GtkWidget* widget, + MidoriSearchAction* search_action) +{ + KatzeArray* search_engines; + GtkWidget* treeview; + GtkTreeSelection* selection; + GtkTreeModel* liststore; + GtkTreeIter iter; + KatzeItem* item; + + search_engines = search_action->search_engines; + treeview = search_action->treeview; + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)); + if (gtk_tree_selection_get_selected (selection, &liststore, &iter)) + { + gtk_tree_model_get (liststore, &iter, 0, &item, -1); + katze_array_remove_item (search_engines, item); + g_object_unref (item); + /* FIXME: we want to allow undo of some kind */ + } +} + +static void +midori_search_action_treeview_selection_cb (GtkTreeSelection* selection, + MidoriSearchAction* search_action) +{ + gboolean selected; + + selected = gtk_tree_selection_get_selected (selection, NULL, NULL); + + gtk_widget_set_sensitive (search_action->edit_button, selected); + gtk_widget_set_sensitive (search_action->remove_button, selected); +} + +static void +midori_search_action_dialog_engines_add_item_cb (KatzeArray* list, + KatzeItem* item, + GtkAction* action) +{ + MidoriSearchAction* search_action; + GtkTreeModel* liststore; + GtkTreeIter iter; + + search_action = MIDORI_SEARCH_ACTION (action); + liststore = gtk_tree_view_get_model (GTK_TREE_VIEW (search_action->treeview)); + gtk_list_store_append (GTK_LIST_STORE (liststore), &iter); + gtk_list_store_set (GTK_LIST_STORE (liststore), &iter, 0, item, -1); +} + +static void +midori_search_action_dialog_engines_remove_item_cb (KatzeArray* list, + KatzeItem* item, + GtkAction* action) +{ + MidoriSearchAction* search_action; + GtkTreeModel* liststore; + GtkTreeIter iter; + gboolean valid; + KatzeItem* found_item; + + search_action = MIDORI_SEARCH_ACTION (action); + liststore = gtk_tree_view_get_model (GTK_TREE_VIEW (search_action->treeview)); + valid = gtk_tree_model_get_iter_first (liststore, &iter); + while (valid) + { + gtk_tree_model_get (liststore, &iter, 0, &found_item, -1); + if (found_item == item) + { + gtk_list_store_remove (GTK_LIST_STORE (liststore), &iter); + valid = FALSE; + } + else + valid = gtk_tree_model_iter_next (liststore, &iter); + } +} + +static void +midori_search_action_treeview_destroy_cb (GtkWidget* treeview, + MidoriSearchAction* search_action) +{ + g_signal_handlers_disconnect_by_func ( + search_action->search_engines, + midori_search_action_dialog_engines_add_item_cb, search_action); + g_signal_handlers_disconnect_by_func ( + search_action->search_engines, + midori_search_action_dialog_engines_remove_item_cb, search_action); +} + +/** + * midori_search_action_get_dialog: + * @search_action: a #MidoriSearchAction + * + * Obtains a dialog that provides an interface for managing + * the list of search engines. + * + * The dialog is created once and this function will return + * the very same dialog until it is destroyed, in which case + * a new dialog is created. + * + * Return value: a #GtkDialog + **/ +GtkWidget* +midori_search_action_get_dialog (MidoriSearchAction* search_action) +{ + const gchar* dialog_title; + GtkWidget* toplevel; + GtkWidget* dialog; + gint width, height; + GtkWidget* xfce_heading; + GtkWidget* hbox; + GtkTreeViewColumn* column; + GtkCellRenderer* renderer_text; + GtkCellRenderer* renderer_pixbuf; + GtkListStore* liststore; + GtkWidget* treeview; + GtkWidget* scrolled; + guint n, i; + KatzeItem* item; + GtkWidget* vbox; + GtkWidget* button; + + g_return_val_if_fail (MIDORI_IS_SEARCH_ACTION (search_action), NULL); + + /* If there is a dialog, use that. We want only one. */ + if (search_action->dialog) + return search_action->dialog; + + dialog_title = _("Manage search engines"); + toplevel = gtk_widget_get_toplevel (search_action->last_proxy); + dialog = gtk_dialog_new_with_buttons (dialog_title, + toplevel ? GTK_WINDOW (toplevel) : NULL, + GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR, + GTK_STOCK_HELP, GTK_RESPONSE_HELP, + GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, + NULL); + g_signal_connect (dialog, "destroy", + G_CALLBACK (gtk_widget_destroyed), &dialog); + gtk_window_set_icon_name (GTK_WINDOW (dialog), GTK_STOCK_PROPERTIES); + /* TODO: Implement some kind of help function */ + gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), + GTK_RESPONSE_HELP, FALSE); + sokoke_widget_get_text_size (dialog, "M", &width, &height); + gtk_window_set_default_size (GTK_WINDOW (dialog), width * 42, -1); + g_signal_connect (dialog, "response", + G_CALLBACK (gtk_widget_destroy), dialog); + /* TODO: Do we want tooltips for explainations or can we omit that? + We need mnemonics */ + if ((xfce_heading = sokoke_xfce_header_new ( + gtk_window_get_icon_name (GTK_WINDOW (dialog)), dialog_title))) + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), + xfce_heading, FALSE, FALSE, 0); + hbox = gtk_hbox_new (FALSE, 0); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), hbox, + TRUE, TRUE, 12); + liststore = gtk_list_store_new (1, KATZE_TYPE_ITEM); + treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (liststore)); + search_action->treeview = treeview; + g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)), + "changed", G_CALLBACK (midori_search_action_treeview_selection_cb), + search_action); + gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE); + column = gtk_tree_view_column_new (); + renderer_pixbuf = gtk_cell_renderer_pixbuf_new (); + gtk_tree_view_column_pack_start (column, renderer_pixbuf, FALSE); + gtk_tree_view_column_set_cell_data_func (column, renderer_pixbuf, + (GtkTreeCellDataFunc)midori_search_action_dialog_render_icon_cb, + treeview, NULL); + renderer_text = gtk_cell_renderer_text_new (); + gtk_tree_view_column_pack_start (column, renderer_text, TRUE); + gtk_tree_view_column_set_cell_data_func (column, renderer_text, + (GtkTreeCellDataFunc)midori_search_action_dialog_render_text, + treeview, NULL); + gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column); + scrolled = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_container_add (GTK_CONTAINER (scrolled), treeview); + gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled), + GTK_SHADOW_IN); + gtk_box_pack_start (GTK_BOX (hbox), scrolled, TRUE, TRUE, 5); + n = katze_array_get_length (search_action->search_engines); + for (i = 0; i < n; i++) + { + item = katze_array_get_nth_item (search_action->search_engines, i); + gtk_list_store_insert_with_values (GTK_LIST_STORE (liststore), + NULL, i, 0, item, -1); + } + g_object_unref (liststore); + g_signal_connect (treeview, "destroy", + G_CALLBACK (midori_search_action_treeview_destroy_cb), search_action); + vbox = gtk_vbox_new (FALSE, 4); + gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 4); + button = gtk_button_new_from_stock (GTK_STOCK_ADD); + g_signal_connect (button, "clicked", + G_CALLBACK (midori_search_action_dialog_add_cb), search_action); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + button = gtk_button_new_from_stock (GTK_STOCK_EDIT); + search_action->edit_button = button; + g_signal_connect (button, "clicked", + G_CALLBACK (midori_search_action_dialog_edit_cb), search_action); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + if (!n) + gtk_widget_set_sensitive (button, FALSE); + button = gtk_button_new_from_stock (GTK_STOCK_REMOVE); + search_action->remove_button = button; + g_signal_connect (button, "clicked", + G_CALLBACK (midori_search_action_dialog_remove_cb), search_action); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + if (!n) + gtk_widget_set_sensitive (button, FALSE); + button = gtk_label_new (""); /* This is an invisible separator */ + gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 12); + button = gtk_button_new_from_stock (GTK_STOCK_GO_DOWN); + gtk_widget_set_sensitive (button, FALSE); + gtk_box_pack_end (GTK_BOX (vbox), button, FALSE, FALSE, 0); + button = gtk_button_new_from_stock (GTK_STOCK_GO_UP); + gtk_widget_set_sensitive (button, FALSE); + gtk_box_pack_end (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_widget_show_all (GTK_DIALOG (dialog)->vbox); + + g_object_connect (search_action->search_engines, + "signal-after::add-item", + midori_search_action_dialog_engines_add_item_cb, search_action, + "signal-after::remove-item", + midori_search_action_dialog_engines_remove_item_cb, search_action, + NULL); + + search_action->dialog = dialog; + return dialog; +} diff --git a/midori/midori-searchaction.h b/midori/midori-searchaction.h new file mode 100644 index 00000000..a2cecaf2 --- /dev/null +++ b/midori/midori-searchaction.h @@ -0,0 +1,64 @@ +/* + Copyright (C) 2008 Christian Dywan + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + See the file COPYING for the full license text. +*/ + +#ifndef __MIDORI_SEARCH_ACTION_H__ +#define __MIDORI_SEARCH_ACTION_H__ + +#include + +G_BEGIN_DECLS + +#define MIDORI_TYPE_SEARCH_ACTION \ + (midori_search_action_get_type ()) +#define MIDORI_SEARCH_ACTION(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), MIDORI_TYPE_SEARCH_ACTION, MidoriSearchAction)) +#define MIDORI_SEARCH_ACTION_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), MIDORI_TYPE_SEARCH_ACTION, MidoriSearchActionClass)) +#define MIDORI_IS_SEARCH_ACTION(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MIDORI_TYPE_SEARCH_ACTION)) +#define MIDORI_IS_SEARCH_ACTION_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), MIDORI_TYPE_SEARCH_ACTION)) +#define MIDORI_SEARCH_ACTION_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), MIDORI_TYPE_SEARCH_ACTION, MidoriSearchActionClass)) + +typedef struct _MidoriSearchAction MidoriSearchAction; +typedef struct _MidoriSearchActionClass MidoriSearchActionClass; + +GType +midori_search_action_get_type (void); + +const gchar* +midori_search_action_get_text (MidoriSearchAction* action); + +void +midori_search_action_set_text (MidoriSearchAction* search_action, + const gchar* text); + +KatzeArray* +midori_search_action_get_search_engines (MidoriSearchAction* search_action); + +void +midori_search_action_set_search_engines (MidoriSearchAction* search_action, + KatzeArray* search_engines); + +KatzeItem* +midori_search_action_get_current_item (MidoriSearchAction* search_action); + +void +midori_search_action_set_current_item (MidoriSearchAction* search_action, + KatzeItem* item); + +GtkWidget* +midori_search_action_get_dialog (MidoriSearchAction* search_action); + +G_END_DECLS + +#endif /* __MIDORI_SEARCH_ACTION_H__ */ diff --git a/midori/midori-searchentry.c b/midori/midori-searchentry.c deleted file mode 100644 index 2cac9ec7..00000000 --- a/midori/midori-searchentry.c +++ /dev/null @@ -1,891 +0,0 @@ -/* - Copyright (C) 2007-2008 Christian Dywan - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - See the file COPYING for the full license text. -*/ - -#include "midori-searchentry.h" - -#include "sokoke.h" - -#include -#include - -struct _MidoriSearchEntry -{ - GtkIconEntry parent_instance; - - KatzeArray* search_engines; - KatzeItem* current_item; -}; - -G_DEFINE_TYPE (MidoriSearchEntry, midori_search_entry, GTK_TYPE_ICON_ENTRY) - -enum -{ - PROP_0, - - PROP_SEARCH_ENGINES, - PROP_CURRENT_ITEM, - PROP_DIALOG -}; - -static void -midori_search_entry_finalize (GObject* object); - -static void -midori_search_entry_set_property (GObject* object, - guint prop_id, - const GValue* value, - GParamSpec* pspec); - -static void -midori_search_entry_get_property (GObject* object, - guint prop_id, - GValue* value, - GParamSpec* pspec); - -static void -midori_search_entry_class_init (MidoriSearchEntryClass* class) -{ - GObjectClass* gobject_class = G_OBJECT_CLASS (class); - gobject_class->finalize = midori_search_entry_finalize; - gobject_class->set_property = midori_search_entry_set_property; - gobject_class->get_property = midori_search_entry_get_property; - - g_object_class_install_property (gobject_class, - PROP_SEARCH_ENGINES, - g_param_spec_object ( - "search-engines", - _("Search Engines"), - _("The list of search engines"), - KATZE_TYPE_ARRAY, - G_PARAM_READWRITE)); - - g_object_class_install_property (gobject_class, - PROP_CURRENT_ITEM, - g_param_spec_object ( - "current-item", - _("Current Item"), - _("The currently selected item"), - KATZE_TYPE_ITEM, - G_PARAM_READWRITE)); - - g_object_class_install_property (gobject_class, - PROP_DIALOG, - g_param_spec_object ( - "dialog", - _("Dialog"), - _("A dialog to manage search engines"), - GTK_TYPE_DIALOG, - G_PARAM_READABLE)); -} - -static void -midori_search_entry_engine_activate_cb (GtkWidget* widget, - MidoriSearchEntry* search_entry) -{ - KatzeItem* item; - - item = (KatzeItem*)g_object_get_data (G_OBJECT (widget), "engine"); - midori_search_entry_set_current_item (search_entry, item); -} - -static void -midori_search_entry_manage_activate_cb (GtkWidget* menuitem, - MidoriSearchEntry* search_entry) -{ - GtkWidget* dialog; - - dialog = midori_search_entry_get_dialog (search_entry); - if (GTK_WIDGET_VISIBLE (dialog)) - gtk_window_present (GTK_WINDOW (dialog)); - else - gtk_widget_show (dialog); -} - -static void -midori_search_entry_icon_released_cb (GtkWidget* widget, - GtkIconEntryPosition* pos, - gint button) -{ - MidoriSearchEntry* search_entry; - KatzeArray* search_engines; - GtkWidget* menu; - guint n, i; - GtkWidget* menuitem; - KatzeItem* item; - GdkPixbuf* pixbuf; - GtkWidget* icon; - - search_entry = MIDORI_SEARCH_ENTRY (widget); - search_engines = search_entry->search_engines; - menu = gtk_menu_new (); - n = katze_array_get_length (search_engines); - if (n) - { - for (i = 0; i < n; i++) - { - item = katze_array_get_nth_item (search_engines, i); - menuitem = gtk_image_menu_item_new_with_label ( - katze_item_get_name (item)); - pixbuf = sokoke_web_icon (katze_item_get_icon (item), - GTK_ICON_SIZE_MENU, menuitem); - icon = gtk_image_new_from_pixbuf (pixbuf); - gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), icon); - g_object_unref (pixbuf); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); - g_object_set_data (G_OBJECT (menuitem), "engine", item); - g_signal_connect (menuitem, "activate", - G_CALLBACK (midori_search_entry_engine_activate_cb), widget); - gtk_widget_show (menuitem); - } - } - else - { - menuitem = gtk_image_menu_item_new_with_label (_("Empty")); - gtk_widget_set_sensitive (menuitem, FALSE); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); - gtk_widget_show (menuitem); - } - - menuitem = gtk_separator_menu_item_new (); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); - gtk_widget_show (menuitem); - menuitem = gtk_image_menu_item_new_with_mnemonic (_("_Manage Search Engines")); - icon = gtk_image_new_from_stock (GTK_STOCK_PREFERENCES, GTK_ICON_SIZE_MENU); - gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem), icon); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); - g_signal_connect (menuitem, "activate", - G_CALLBACK (midori_search_entry_manage_activate_cb), widget); - gtk_widget_show (menuitem); - sokoke_widget_popup (widget, GTK_MENU (menu), - NULL, SOKOKE_MENU_POSITION_LEFT); -} - -static void -_midori_search_entry_move_index (MidoriSearchEntry* search_entry, - guint n) -{ - gint i; - KatzeItem* item; - - i = katze_array_get_item_index (search_entry->search_engines, - search_entry->current_item); - item = katze_array_get_nth_item (search_entry->search_engines, i + n); - if (item) - midori_search_entry_set_current_item (search_entry, item); -} - -static gboolean -midori_search_entry_key_press_event_cb (MidoriSearchEntry* search_entry, - GdkEventKey* event) -{ - GdkModifierType state; - gint x, y; - - gdk_window_get_pointer (NULL, &x, &y, &state); - if (!(state & GDK_CONTROL_MASK)) - return FALSE; - switch (event->keyval) - { - case GDK_Up: - _midori_search_entry_move_index (search_entry, - 1); - return TRUE; - case GDK_Down: - _midori_search_entry_move_index (search_entry, + 1); - return TRUE; - } - return FALSE; -} - -static gboolean -midori_search_entry_scroll_event_cb (MidoriSearchEntry* search_entry, - GdkEventScroll* event) -{ - if (event->direction == GDK_SCROLL_DOWN) - _midori_search_entry_move_index (search_entry, + 1); - else if (event->direction == GDK_SCROLL_UP) - _midori_search_entry_move_index (search_entry, - 1); - return TRUE; -} - -static void -midori_search_entry_engines_add_item_cb (KatzeArray* list, - KatzeItem* item, - MidoriSearchEntry* search_entry) -{ - if (!search_entry->current_item) - midori_search_entry_set_current_item (search_entry, item); -} - -static void -midori_search_entry_engines_remove_item_cb (KatzeArray* list, - KatzeItem* item, - MidoriSearchEntry* search_entry) -{ - KatzeItem* found_item; - - if (search_entry->current_item == item) - { - found_item = katze_array_get_nth_item (list, 0); - midori_search_entry_set_current_item (search_entry, found_item); - } -} - -static void -midori_search_entry_init (MidoriSearchEntry* search_entry) -{ - search_entry->search_engines = katze_array_new (KATZE_TYPE_ITEM); - search_entry->current_item = NULL; - - gtk_icon_entry_set_icon_highlight (GTK_ICON_ENTRY (search_entry), - GTK_ICON_ENTRY_PRIMARY, TRUE); - g_object_connect (search_entry, - "signal::icon-released", - midori_search_entry_icon_released_cb, NULL, - "signal::key-press-event", - midori_search_entry_key_press_event_cb, NULL, - "signal::scroll-event", - midori_search_entry_scroll_event_cb, NULL, - NULL); - - g_object_connect (search_entry->search_engines, - "signal-after::add-item", - midori_search_entry_engines_add_item_cb, search_entry, - "signal-after::remove-item", - midori_search_entry_engines_remove_item_cb, search_entry, - NULL); -} - -static void -midori_search_entry_finalize (GObject* object) -{ - MidoriSearchEntry* search_entry = MIDORI_SEARCH_ENTRY (object); - - g_object_unref (search_entry->search_engines); - if (search_entry->current_item) - g_object_unref (search_entry->current_item); - - G_OBJECT_CLASS (midori_search_entry_parent_class)->finalize (object); -} - -static void -midori_search_entry_set_property (GObject* object, - guint prop_id, - const GValue* value, - GParamSpec* pspec) -{ - MidoriSearchEntry* search_entry = MIDORI_SEARCH_ENTRY (object); - - switch (prop_id) - { - case PROP_SEARCH_ENGINES: - midori_search_entry_set_search_engines (search_entry, - g_value_get_object (value)); - break; - case PROP_CURRENT_ITEM: - midori_search_entry_set_current_item (search_entry, - g_value_get_object (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -midori_search_entry_get_property (GObject* object, - guint prop_id, - GValue* value, - GParamSpec* pspec) -{ - MidoriSearchEntry* search_entry = MIDORI_SEARCH_ENTRY (object); - - switch (prop_id) - { - case PROP_SEARCH_ENGINES: - g_value_set_object (value, search_entry->search_engines); - break; - case PROP_CURRENT_ITEM: - g_value_set_object (value, search_entry->current_item); - break; - case PROP_DIALOG: - g_value_set_object (value, midori_search_entry_get_dialog (search_entry)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -/** - * midori_search_entry_new: - * - * Creates a new #MidoriSearchEntry. - * - * Return value: a new #MidoriSearchEntry - **/ -GtkWidget* -midori_search_entry_new (void) -{ - GtkWidget* search_entry = g_object_new (MIDORI_TYPE_SEARCH_ENTRY, NULL); - - return search_entry; -} - -/** - * midori_search_entry_get_search_engines: - * @search_entry: a #MidoriSearchEntry - * - * Retrieves the list of search engines. - * - * Return value: the list of search engines - **/ -KatzeArray* -midori_search_entry_get_search_engines (MidoriSearchEntry* search_entry) -{ - g_return_val_if_fail (MIDORI_IS_SEARCH_ENTRY (search_entry), NULL); - - return search_entry->search_engines; -} - -/** - * midori_search_entry_set_search_engines: - * @search_entry: a #MidoriSearchEntry - * @search_engines: a list of search engines - * - * Sets the list of search engines. - **/ -void -midori_search_entry_set_search_engines (MidoriSearchEntry* search_entry, - KatzeArray* search_engines) -{ - g_return_if_fail (MIDORI_IS_SEARCH_ENTRY (search_entry)); - g_return_if_fail (katze_array_is_a (search_engines, KATZE_TYPE_ITEM)); - - g_object_ref (search_engines); - katze_object_assign (search_entry->search_engines, search_engines); - g_object_notify (G_OBJECT (search_entry), "search-engines"); - - g_object_connect (search_engines, - "signal-after::add-item", - midori_search_entry_engines_add_item_cb, search_entry, - "signal-after::remove-item", - midori_search_entry_engines_remove_item_cb, search_entry, - NULL); -} - -/** - * midori_search_entry_set_current_item: - * @search_entry: a #MidoriSearchEntry - * @item: a #KatzeItem, or %NULL - * - * Looks up the specified item in the list of search engines and makes - * it the currently selected item. - * - * Pass %NULL for @item in order to unset the item. - * - * This function fails if @item is not in the current list. - **/ -void -midori_search_entry_set_current_item (MidoriSearchEntry* search_entry, - KatzeItem* item) -{ - GdkPixbuf* pixbuf; - - g_return_if_fail (MIDORI_IS_SEARCH_ENTRY (search_entry)); - g_return_if_fail (!item || KATZE_IS_ITEM (item)); - - pixbuf = sokoke_web_icon (item ? katze_item_get_icon (item) : NULL, - GTK_ICON_SIZE_MENU, GTK_WIDGET (search_entry)); - gtk_icon_entry_set_icon_from_pixbuf (GTK_ICON_ENTRY (search_entry), - GTK_ICON_ENTRY_PRIMARY, - pixbuf); - g_object_unref (pixbuf); - - if (item) - { - katze_object_assign (search_entry->current_item, g_object_ref (item)); - sokoke_entry_set_default_text (GTK_ENTRY (search_entry), - katze_item_get_name (item)); - } - else - { - katze_object_assign (search_entry->current_item, NULL); - sokoke_entry_set_default_text (GTK_ENTRY (search_entry), ""); - } - - g_object_notify (G_OBJECT (search_entry), "current-item"); -} - -/** - * midori_search_entry_get_current_item: - * @search_entry: a #MidoriSearchEntry - * - * Retrieves the currently selected item. - * - * Return value: the selected web item, or %NULL - **/ -KatzeItem* -midori_search_entry_get_current_item (MidoriSearchEntry* search_entry) -{ - g_return_val_if_fail (MIDORI_IS_SEARCH_ENTRY (search_entry), NULL); - - return search_entry->current_item; -} - -static void -midori_search_entry_dialog_render_icon_cb (GtkTreeViewColumn* column, - GtkCellRenderer* renderer, - GtkTreeModel* model, - GtkTreeIter* iter, - GtkWidget* treeview) -{ - KatzeItem* item; - const gchar* icon; - GdkPixbuf* pixbuf; - - gtk_tree_model_get (model, iter, 0, &item, -1); - - icon = katze_item_get_icon (item); - if (icon) - { - pixbuf = sokoke_web_icon (icon, GTK_ICON_SIZE_DND, treeview); - g_object_set (renderer, "pixbuf", pixbuf, NULL); - if (pixbuf) - g_object_unref (pixbuf); - } - else - g_object_set (renderer, "pixbuf", NULL, NULL); -} - -static void -midori_search_entry_dialog_render_text (GtkTreeViewColumn* column, - GtkCellRenderer* renderer, - GtkTreeModel* model, - GtkTreeIter* iter, - GtkWidget* treeview) -{ - KatzeItem* item; - const gchar* name; - const gchar* text; - gchar* markup; - - gtk_tree_model_get (model, iter, 0, &item, -1); - name = katze_item_get_name (item); - text = katze_item_get_text (item); - markup = g_markup_printf_escaped ("%s\n%s", name, text ? text : ""); - g_object_set (renderer, "markup", markup, NULL); - g_free (markup); -} - -static void -midori_search_entry_editor_name_changed_cb (GtkWidget* widget, - GtkWidget* dialog) -{ - const gchar* text = gtk_entry_get_text (GTK_ENTRY (widget)); - gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), - GTK_RESPONSE_ACCEPT, text && *text); -} - -const gchar* -STR_NON_NULL (const gchar* string) -{ - return string ? string : ""; -} - -static void -midori_search_entry_get_editor (GtkWidget* treeview, - gboolean new_engine) -{ - MidoriSearchEntry* search_entry; - GtkWidget* dialog; - GtkSizeGroup* sizegroup; - KatzeItem* item; - GtkWidget* hbox; - GtkWidget* label; - GtkTreeModel* liststore; - GtkTreeIter iter; - GtkTreeSelection* selection; - GtkWidget* entry_name; - GtkWidget* entry_description; - GtkWidget* entry_uri; - GtkWidget* entry_icon; - GtkWidget* entry_token; - - GtkWidget* toplevel = gtk_widget_get_toplevel (treeview); - dialog = gtk_dialog_new_with_buttons ( - new_engine ? _("Add search engine") : _("Edit search engine"), - toplevel ? GTK_WINDOW (toplevel) : NULL, - GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - new_engine ? GTK_STOCK_ADD : GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, - NULL); - gtk_window_set_icon_name (GTK_WINDOW (dialog), - new_engine ? GTK_STOCK_ADD : GTK_STOCK_REMOVE); - gtk_container_set_border_width (GTK_CONTAINER (dialog), 5); - gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), 5); - sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); - - if (new_engine) - { - item = katze_item_new (); - gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), - GTK_RESPONSE_ACCEPT, FALSE); - } - else - { - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)); - gtk_tree_selection_get_selected (selection, &liststore, &iter); - gtk_tree_model_get (liststore, &iter, 0, &item, -1); - } - - hbox = gtk_hbox_new (FALSE, 8); - gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); - label = gtk_label_new_with_mnemonic (_("_Name:")); - gtk_size_group_add_widget (sizegroup, label); - gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); - entry_name = gtk_entry_new (); - g_signal_connect (entry_name, "changed", - G_CALLBACK (midori_search_entry_editor_name_changed_cb), dialog); - gtk_entry_set_activates_default (GTK_ENTRY (entry_name), TRUE); - if (!new_engine) - gtk_entry_set_text (GTK_ENTRY (entry_name), - STR_NON_NULL (katze_item_get_name (item))); - gtk_box_pack_start (GTK_BOX (hbox), entry_name, TRUE, TRUE, 0); - gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), hbox); - gtk_widget_show_all (hbox); - - hbox = gtk_hbox_new (FALSE, 8); - gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); - label = gtk_label_new_with_mnemonic (_("_Description:")); - gtk_size_group_add_widget (sizegroup, label); - gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); - entry_description = gtk_entry_new (); - gtk_entry_set_activates_default (GTK_ENTRY (entry_description), TRUE); - if (!new_engine) - gtk_entry_set_text (GTK_ENTRY (entry_description) - , STR_NON_NULL (katze_item_get_text (item))); - gtk_box_pack_start (GTK_BOX (hbox), entry_description, TRUE, TRUE, 0); - gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), hbox); - gtk_widget_show_all (hbox); - - hbox = gtk_hbox_new (FALSE, 8); - gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); - label = gtk_label_new_with_mnemonic (_("_URL:")); - gtk_size_group_add_widget (sizegroup, label); - gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); - entry_uri = gtk_entry_new (); - gtk_entry_set_activates_default (GTK_ENTRY (entry_uri), TRUE); - if (!new_engine) - gtk_entry_set_text (GTK_ENTRY (entry_uri) - , STR_NON_NULL (katze_item_get_uri (item))); - gtk_box_pack_start (GTK_BOX (hbox), entry_uri, TRUE, TRUE, 0); - gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), hbox); - gtk_widget_show_all (hbox); - - hbox = gtk_hbox_new (FALSE, 8); - gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); - label = gtk_label_new_with_mnemonic (_("_Icon (name or file):")); - gtk_size_group_add_widget (sizegroup, label); - gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); - entry_icon = gtk_entry_new (); - gtk_entry_set_activates_default (GTK_ENTRY (entry_icon), TRUE); - if (!new_engine) - gtk_entry_set_text (GTK_ENTRY (entry_icon) - , STR_NON_NULL (katze_item_get_icon (item))); - gtk_box_pack_start (GTK_BOX (hbox), entry_icon, TRUE, TRUE, 0); - gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), hbox); - gtk_widget_show_all (hbox); - - hbox = gtk_hbox_new (FALSE, 8); - gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); - label = gtk_label_new_with_mnemonic (_("_Token:")); - gtk_size_group_add_widget (sizegroup, label); - gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); - entry_token = gtk_entry_new (); - gtk_entry_set_activates_default (GTK_ENTRY (entry_token), TRUE); - if (!new_engine) - gtk_entry_set_text (GTK_ENTRY (entry_token) - , STR_NON_NULL (katze_item_get_token (item))); - gtk_box_pack_start (GTK_BOX (hbox), entry_token, TRUE, TRUE, 0); - gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), hbox); - gtk_widget_show_all (hbox); - - gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT); - if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) - { - g_object_set (item, - "name", gtk_entry_get_text (GTK_ENTRY (entry_name)), - "text", gtk_entry_get_text (GTK_ENTRY (entry_description)), - "uri", gtk_entry_get_text (GTK_ENTRY (entry_uri)), - "icon", gtk_entry_get_text (GTK_ENTRY (entry_icon)), - "token", gtk_entry_get_text (GTK_ENTRY (entry_token)), - NULL); - - search_entry = g_object_get_data (G_OBJECT (treeview), "search-entry"); - if (new_engine) - katze_array_add_item (search_entry->search_engines, item); - } - gtk_widget_destroy (dialog); -} - -static void -midori_search_entry_dialog_add_cb (GtkWidget* widget, - GtkWidget* treeview) -{ - MidoriSearchEntry* search_entry; - - search_entry = g_object_get_data (G_OBJECT (treeview), "search-entry"); - midori_search_entry_get_editor (treeview, TRUE); -} - -static void -midori_search_entry_dialog_edit_cb (GtkWidget* widget, - GtkWidget* treeview) -{ - MidoriSearchEntry* search_entry; - GtkTreeSelection* selection; - - search_entry = g_object_get_data (G_OBJECT (treeview), "search-entry"); - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)); - if (gtk_tree_selection_get_selected (selection, NULL, NULL)) - midori_search_entry_get_editor (treeview, FALSE); -} - -static void -midori_search_entry_dialog_remove_cb (GtkWidget* widget, - GtkWidget* treeview) -{ - MidoriSearchEntry* search_entry; - GtkTreeSelection* selection; - GtkTreeModel* liststore; - GtkTreeIter iter; - KatzeItem* item; - KatzeArray* search_engines; - - search_entry = g_object_get_data (G_OBJECT (treeview), "search-entry"); - search_engines = search_entry->search_engines; - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)); - if (gtk_tree_selection_get_selected (selection, &liststore, &iter)) - { - gtk_tree_model_get (liststore, &iter, 0, &item, -1); - katze_array_remove_item (search_engines, item); - g_object_unref (item); - /* FIXME: we want to allow undo of some kind */ - } -} - -static void -midori_search_entry_treeview_selection_cb (GtkTreeSelection* selection, - GtkWidget* treeview) -{ - gboolean selected; - GtkWidget* edit_button; - GtkWidget* remove_button; - - selected = gtk_tree_selection_get_selected (selection, NULL, NULL); - - edit_button = g_object_get_data (G_OBJECT (treeview), "edit-button"); - remove_button = g_object_get_data (G_OBJECT (treeview), "remove-button"); - - gtk_widget_set_sensitive (edit_button, selected); - gtk_widget_set_sensitive (remove_button, selected); -} - -static void -midori_search_entry_dialog_engines_add_item_cb (KatzeArray* list, - KatzeItem* item, - GtkWidget* treeview) -{ - GtkTreeModel* liststore; - GtkTreeIter iter; - - liststore = gtk_tree_view_get_model (GTK_TREE_VIEW (treeview)); - gtk_list_store_append (GTK_LIST_STORE (liststore), &iter); - gtk_list_store_set (GTK_LIST_STORE (liststore), &iter, 0, item, -1); -} - -static void -midori_search_entry_dialog_engines_remove_item_cb (KatzeArray* list, - KatzeItem* item, - GtkWidget* treeview) -{ - GtkTreeModel* liststore; - GtkTreeIter iter; - gboolean valid; - KatzeItem* found_item; - - liststore = gtk_tree_view_get_model (GTK_TREE_VIEW (treeview)); - valid = gtk_tree_model_get_iter_first (liststore, &iter); - while (valid) - { - gtk_tree_model_get (liststore, &iter, 0, &found_item, -1); - if (found_item == item) - { - gtk_list_store_remove (GTK_LIST_STORE (liststore), &iter); - valid = FALSE; - } - else - valid = gtk_tree_model_iter_next (liststore, &iter); - } -} - -static void -midori_search_entry_treeview_destroy_cb (GtkWidget* treeview, - GtkWidget* search_entry) -{ - g_signal_handlers_disconnect_by_func ( - MIDORI_SEARCH_ENTRY (search_entry)->search_engines, - midori_search_entry_dialog_engines_add_item_cb, treeview); - g_signal_handlers_disconnect_by_func ( - MIDORI_SEARCH_ENTRY (search_entry)->search_engines, - midori_search_entry_dialog_engines_remove_item_cb, treeview); -} - -/** - * midori_search_entry_get_dialog: - * @search_entry: a #MidoriSearchEntry - * - * Obtains a dialog that provides an interface for managing - * the list of search engines. - * - * A new dialog is created each time, so it may be a good idea - * to store the pointer for the life time of the dialog. - * - * Return value: a dialog - **/ -GtkWidget* -midori_search_entry_get_dialog (MidoriSearchEntry* search_entry) -{ - static GtkWidget* dialog = NULL; - const gchar* dialog_title; - GtkWidget* toplevel; - gint width, height; - GtkWidget* xfce_heading; - GtkWidget* hbox; - GtkTreeViewColumn* column; - GtkCellRenderer* renderer_text; - GtkCellRenderer* renderer_pixbuf; - GtkListStore* liststore; - GtkWidget* treeview; - GtkWidget* scrolled; - guint n, i; - KatzeItem* item; - GtkWidget* vbox; - GtkWidget* button; - - g_return_val_if_fail (MIDORI_IS_SEARCH_ENTRY (search_entry), NULL); - - /* If there is a dialog, use that. We want only one. */ - if (dialog) - return dialog; - - dialog_title = _("Manage search engines"); - toplevel = gtk_widget_get_toplevel (GTK_WIDGET (search_entry)); - dialog = gtk_dialog_new_with_buttons (dialog_title, - toplevel ? GTK_WINDOW (toplevel) : NULL, - GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR, - GTK_STOCK_HELP, GTK_RESPONSE_HELP, - GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, - NULL); - g_signal_connect (dialog, "destroy", - G_CALLBACK (gtk_widget_destroyed), &dialog); - gtk_window_set_icon_name (GTK_WINDOW (dialog), GTK_STOCK_PROPERTIES); - /* TODO: Implement some kind of help function */ - gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), - GTK_RESPONSE_HELP, FALSE); - sokoke_widget_get_text_size (dialog, "M", &width, &height); - gtk_window_set_default_size (GTK_WINDOW (dialog), width * 42, -1); - g_signal_connect (dialog, "response", - G_CALLBACK (gtk_widget_destroy), dialog); - /* TODO: Do we want tooltips for explainations or can we omit that? - We need mnemonics */ - if ((xfce_heading = sokoke_xfce_header_new ( - gtk_window_get_icon_name (GTK_WINDOW (dialog)), dialog_title))) - gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), - xfce_heading, FALSE, FALSE, 0); - hbox = gtk_hbox_new (FALSE, 0); - gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), hbox, - TRUE, TRUE, 12); - liststore = gtk_list_store_new (1, KATZE_TYPE_ITEM); - treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (liststore)); - g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)), - "changed", G_CALLBACK (midori_search_entry_treeview_selection_cb), - treeview); - g_object_set_data (G_OBJECT (treeview), "search-entry", search_entry); - gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE); - column = gtk_tree_view_column_new (); - renderer_pixbuf = gtk_cell_renderer_pixbuf_new (); - gtk_tree_view_column_pack_start (column, renderer_pixbuf, FALSE); - gtk_tree_view_column_set_cell_data_func (column, renderer_pixbuf, - (GtkTreeCellDataFunc)midori_search_entry_dialog_render_icon_cb, - treeview, NULL); - renderer_text = gtk_cell_renderer_text_new (); - gtk_tree_view_column_pack_start (column, renderer_text, TRUE); - gtk_tree_view_column_set_cell_data_func (column, renderer_text, - (GtkTreeCellDataFunc)midori_search_entry_dialog_render_text, - treeview, NULL); - gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column); - scrolled = gtk_scrolled_window_new (NULL, NULL); - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled), - GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - gtk_container_add (GTK_CONTAINER (scrolled), treeview); - gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled), - GTK_SHADOW_IN); - gtk_box_pack_start (GTK_BOX (hbox), scrolled, TRUE, TRUE, 5); - n = katze_array_get_length (search_entry->search_engines); - for (i = 0; i < n; i++) - { - item = katze_array_get_nth_item (search_entry->search_engines, i); - gtk_list_store_insert_with_values (GTK_LIST_STORE (liststore), - NULL, i, 0, item, -1); - } - g_object_unref (liststore); - g_signal_connect (treeview, "destroy", - G_CALLBACK (midori_search_entry_treeview_destroy_cb), search_entry); - vbox = gtk_vbox_new (FALSE, 4); - gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 4); - button = gtk_button_new_from_stock (GTK_STOCK_ADD); - g_signal_connect (button, "clicked", - G_CALLBACK (midori_search_entry_dialog_add_cb), treeview); - gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); - button = gtk_button_new_from_stock (GTK_STOCK_EDIT); - g_signal_connect (button, "clicked", - G_CALLBACK (midori_search_entry_dialog_edit_cb), treeview); - gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); - g_object_set_data (G_OBJECT (treeview), "edit-button", button); - if (!n) - gtk_widget_set_sensitive (button, FALSE); - button = gtk_button_new_from_stock (GTK_STOCK_REMOVE); - g_signal_connect (button, "clicked", - G_CALLBACK (midori_search_entry_dialog_remove_cb), treeview); - gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); - if (!n) - gtk_widget_set_sensitive (button, FALSE); - g_object_set_data (G_OBJECT (treeview), "remove-button", button); - button = gtk_label_new (""); /* This is an invisible separator */ - gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 12); - button = gtk_button_new_from_stock (GTK_STOCK_GO_DOWN); - gtk_widget_set_sensitive (button, FALSE); - gtk_box_pack_end (GTK_BOX (vbox), button, FALSE, FALSE, 0); - button = gtk_button_new_from_stock (GTK_STOCK_GO_UP); - gtk_widget_set_sensitive (button, FALSE); - gtk_box_pack_end (GTK_BOX (vbox), button, FALSE, FALSE, 0); - gtk_widget_show_all (GTK_DIALOG (dialog)->vbox); - - g_object_connect (search_entry->search_engines, - "signal-after::add-item", - midori_search_entry_dialog_engines_add_item_cb, treeview, - "signal-after::remove-item", - midori_search_entry_dialog_engines_remove_item_cb, treeview, - NULL); - - return dialog; -} diff --git a/midori/midori-searchentry.h b/midori/midori-searchentry.h deleted file mode 100644 index 176f34d2..00000000 --- a/midori/midori-searchentry.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - Copyright (C) 2008 Christian Dywan - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - See the file COPYING for the full license text. -*/ - -#ifndef __MIDORI_SEARCH_ENTRY_H__ -#define __MIDORI_SEARCH_ENTRY_H__ - -#include "gtkiconentry.h" - -#include - -#include - -G_BEGIN_DECLS - -#define MIDORI_TYPE_SEARCH_ENTRY \ - (midori_search_entry_get_type ()) -#define MIDORI_SEARCH_ENTRY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST ((obj), MIDORI_TYPE_SEARCH_ENTRY, MidoriSearchEntry)) -#define MIDORI_SEARCH_ENTRY_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST ((klass), MIDORI_TYPE_SEARCH_ENTRY, MidoriSearchEntryClass)) -#define MIDORI_IS_SEARCH_ENTRY(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MIDORI_TYPE_SEARCH_ENTRY)) -#define MIDORI_IS_SEARCH_ENTRY_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE ((klass), MIDORI_TYPE_SEARCH_ENTRY)) -#define MIDORI_SEARCH_ENTRY_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS ((obj), MIDORI_TYPE_SEARCH_ENTRY, MidoriSearchEntryClass)) - -typedef struct _MidoriSearchEntry MidoriSearchEntry; -typedef struct _MidoriSearchEntryClass MidoriSearchEntryClass; - -struct _MidoriSearchEntryClass -{ - GtkIconEntryClass parent_class; -}; - -GType -midori_search_entry_get_type (void); - -GtkWidget* -midori_search_entry_new (void); - -KatzeArray* -midori_search_entry_get_search_engines (MidoriSearchEntry* search_entry); - -void -midori_search_entry_set_search_engines (MidoriSearchEntry* search_entry, - KatzeArray* name); - -KatzeItem* -midori_search_entry_get_current_item (MidoriSearchEntry* search_entry); - -void -midori_search_entry_set_current_item (MidoriSearchEntry* search_entry, - KatzeItem* name); - -GtkWidget* -midori_search_entry_get_dialog (MidoriSearchEntry* search_entry); - -G_END_DECLS - -#endif /* __MIDORI_SEARCH_ENTRY_H__ */ diff --git a/po/POTFILES.in b/po/POTFILES.in index 91045bb6..61ab1ba7 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -11,7 +11,7 @@ midori/midori-websettings.c midori/midori-view.c midori/midori-source.c midori/midori-preferences.c -midori/midori-searchentry.c +midori/midori-searchaction.c midori/sokoke.c midori/gjs.c katze/katze-throbber.c