From ba6386850ec44184801b86a299742222ae3b8750 Mon Sep 17 00:00:00 2001 From: Christian Dywan Date: Sun, 5 Oct 2008 23:25:02 +0200 Subject: [PATCH] Implement the search widget as an action The most part of the search entry code is merely moved to the new action. We remove the original entry now, the action is all we need. --- midori/Makefile.am | 2 +- midori/midori-browser.c | 196 +++--- midori/midori-searchaction.c | 1140 ++++++++++++++++++++++++++++++++++ midori/midori-searchaction.h | 64 ++ midori/midori-searchentry.c | 891 -------------------------- midori/midori-searchentry.h | 69 -- po/POTFILES.in | 2 +- 7 files changed, 1300 insertions(+), 1064 deletions(-) create mode 100644 midori/midori-searchaction.c create mode 100644 midori/midori-searchaction.h delete mode 100644 midori/midori-searchentry.c delete mode 100644 midori/midori-searchentry.h 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