2
Copyright (C) 2007 Christian Dywan <christian@twotoasts.de>
4
This library is free software; you can redistribute it and/or
5
modify it under the terms of the GNU Lesser General Public
6
License as published by the Free Software Foundation; either
7
version 2.1 of the License, or (at your option) any later version.
9
See the file COPYING for the full license text.
12
#include "webSearch.h"
20
#include <gdk/gdkkeysyms.h>
21
#include <glib/gi18n.h>
24
load_web_icon (const gchar* icon, GtkIconSize size, GtkWidget* widget)
26
g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
27
GdkPixbuf* pixbuf = NULL;
30
// TODO: We want to allow http as well, maybe also base64?
31
const gchar* icon_ready = g_str_has_prefix (icon, "file://")
33
GtkStockItem stock_id;
34
if (gtk_stock_lookup (icon, &stock_id))
35
pixbuf = gtk_widget_render_icon (widget, icon_ready, size, NULL);
39
gtk_icon_size_lookup (size, &width, &height);
40
if (gtk_widget_has_screen (widget))
42
GdkScreen* screen = gtk_widget_get_screen (widget);
43
pixbuf = gtk_icon_theme_load_icon (
44
gtk_icon_theme_get_for_screen (screen), icon,
45
MAX (width, height), GTK_ICON_LOOKUP_USE_BUILTIN, NULL);
49
pixbuf = gdk_pixbuf_new_from_file_at_size (icon_ready, 16, 16, NULL);
52
pixbuf = gtk_widget_render_icon (widget, GTK_STOCK_FIND, size, NULL);
56
void update_searchEngine(guint index, GtkWidget* search)
58
guint n = g_list_length(searchEngines);
59
// Display a default icon in case we have no engines
61
sexy_icon_entry_set_icon(SEXY_ICON_ENTRY(search), SEXY_ICON_ENTRY_PRIMARY
62
, GTK_IMAGE(gtk_image_new_from_stock(GTK_STOCK_FIND, GTK_ICON_SIZE_MENU)));
63
// Change the icon and default text according to the chosen engine
66
// Reset in case the index is out of range
69
SearchEngine* engine = (SearchEngine*)g_list_nth_data(searchEngines, index);
70
GdkPixbuf* pixbuf = load_web_icon(search_engine_get_icon(engine)
71
, GTK_ICON_SIZE_MENU, search);
72
sexy_icon_entry_set_icon(SEXY_ICON_ENTRY(search)
73
, SEXY_ICON_ENTRY_PRIMARY, GTK_IMAGE(gtk_image_new_from_pixbuf(pixbuf)));
74
g_object_unref(pixbuf);
75
sokoke_entry_set_default_text(GTK_ENTRY(search)
76
, search_engine_get_short_name(engine));
77
// config->searchEngine = index;
81
void on_webSearch_engine_activate(GtkWidget* widget, MidoriBrowser* browser)
83
guint index = GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(widget), "engine"));
84
update_searchEngine(index, widget);
87
void on_webSearch_icon_released(GtkWidget* widget, SexyIconEntryPosition* pos
88
, gint button, MidoriBrowser* browser)
90
GtkWidget* menu = gtk_menu_new();
91
guint n = g_list_length(searchEngines);
96
for(i = 0; i < n; i++)
98
SearchEngine* engine = (SearchEngine*)g_list_nth_data(searchEngines, i);
99
menuitem = gtk_image_menu_item_new_with_label(
100
search_engine_get_short_name(engine));
101
GdkPixbuf* pixbuf = load_web_icon(search_engine_get_icon(engine)
102
, GTK_ICON_SIZE_MENU, menuitem);
103
GtkWidget* icon = gtk_image_new_from_pixbuf(pixbuf);
104
gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menuitem), icon);
105
g_object_unref(pixbuf);
106
gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
107
g_object_set_data(G_OBJECT(menuitem), "engine", GUINT_TO_POINTER(i));
108
g_signal_connect(menuitem, "activate"
109
, G_CALLBACK(on_webSearch_engine_activate), browser);
110
gtk_widget_show(menuitem);
115
menuitem = gtk_image_menu_item_new_with_label(_("Empty"));
116
gtk_widget_set_sensitive(menuitem, FALSE);
117
gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
118
gtk_widget_show(menuitem);
121
/*menuitem = gtk_separator_menu_item_new();
122
gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
123
gtk_widget_show(menuitem);
124
GtkAction* action = gtk_action_group_get_action(
125
browser->actiongroup, "ManageSearchEngines");
126
menuitem = gtk_action_create_menu_item(action);
127
gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
128
gtk_widget_show(menuitem);*/
129
sokoke_widget_popup(widget, GTK_MENU(menu),
130
NULL, SOKOKE_MENU_POSITION_LEFT);
133
static void on_webSearch_engines_render_icon(GtkTreeViewColumn* column
134
, GtkCellRenderer* renderer, GtkTreeModel* model, GtkTreeIter* iter
135
, GtkWidget* treeview)
137
SearchEngine* searchEngine;
138
gtk_tree_model_get(model, iter, ENGINES_COL_ENGINE, &searchEngine, -1);
140
// TODO: Would it be better to not do this on every redraw?
141
const gchar* icon = search_engine_get_icon(searchEngine);
144
GdkPixbuf* pixbuf = load_web_icon(icon, GTK_ICON_SIZE_DND, treeview);
145
g_object_set(renderer, "pixbuf", pixbuf, NULL);
147
g_object_unref(pixbuf);
150
g_object_set(renderer, "pixbuf", NULL, NULL);
153
static void on_webSearch_engines_render_text(GtkTreeViewColumn* column
154
, GtkCellRenderer* renderer, GtkTreeModel* model, GtkTreeIter* iter
155
, GtkWidget* treeview)
157
SearchEngine* searchEngine;
158
gtk_tree_model_get(model, iter, ENGINES_COL_ENGINE, &searchEngine, -1);
159
const gchar* name = search_engine_get_short_name(searchEngine);
160
const gchar* description = search_engine_get_description(searchEngine);
161
gchar* markup = g_markup_printf_escaped("<b>%s</b>\n%s", name, description);
162
g_object_set(renderer, "markup", markup, NULL);
166
static void webSearch_toggle_edit_buttons(gboolean sensitive, CWebSearch* webSearch)
168
gtk_widget_set_sensitive(webSearch->edit, sensitive);
169
gtk_widget_set_sensitive(webSearch->remove, sensitive);
172
static void on_webSearch_shortName_changed(GtkWidget* widget, GtkWidget* dialog)
174
const gchar* text = gtk_entry_get_text(GTK_ENTRY(widget));
175
gtk_dialog_set_response_sensitive(GTK_DIALOG(dialog)
176
, GTK_RESPONSE_ACCEPT, text && *text);
179
const gchar* STR_NON_NULL(const gchar* string)
181
return string ? string : "";
184
static void webSearch_editEngine_dialog_new(gboolean newEngine, CWebSearch* webSearch)
186
GtkWidget* dialog = gtk_dialog_new_with_buttons(
187
newEngine ? _("Add search engine") : _("Edit search engine")
188
, GTK_WINDOW(webSearch->window)
189
, GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR
190
, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL
191
, newEngine ? GTK_STOCK_ADD : GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT
193
gtk_window_set_icon_name(GTK_WINDOW(dialog)
194
, newEngine ? GTK_STOCK_ADD : GTK_STOCK_REMOVE);
195
gtk_container_set_border_width(GTK_CONTAINER(dialog), 5);
196
gtk_container_set_border_width(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), 5);
197
GtkSizeGroup* sizegroup = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
199
SearchEngine* searchEngine;
200
GtkTreeModel* liststore;
204
searchEngine = search_engine_new();
205
gtk_dialog_set_response_sensitive(GTK_DIALOG(dialog)
206
, GTK_RESPONSE_ACCEPT, FALSE);
210
GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(webSearch->treeview));
211
gtk_tree_selection_get_selected(selection, &liststore, &iter);
212
gtk_tree_model_get(liststore, &iter, ENGINES_COL_ENGINE, &searchEngine, -1);
215
GtkWidget* hbox = gtk_hbox_new(FALSE, 8);
216
gtk_container_set_border_width(GTK_CONTAINER(hbox), 5);
217
GtkWidget* label = gtk_label_new_with_mnemonic(_("_Name:"));
218
gtk_size_group_add_widget(sizegroup, label);
219
gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
220
GtkWidget* entry_shortName = gtk_entry_new();
221
g_signal_connect(entry_shortName, "changed"
222
, G_CALLBACK(on_webSearch_shortName_changed), dialog);
223
gtk_entry_set_activates_default(GTK_ENTRY(entry_shortName), TRUE);
225
gtk_entry_set_text(GTK_ENTRY(entry_shortName)
226
, search_engine_get_short_name(searchEngine));
227
gtk_box_pack_start(GTK_BOX(hbox), entry_shortName, TRUE, TRUE, 0);
228
gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), hbox);
229
gtk_widget_show_all(hbox);
231
hbox = gtk_hbox_new(FALSE, 8);
232
gtk_container_set_border_width(GTK_CONTAINER(hbox), 5);
233
label = gtk_label_new_with_mnemonic(_("_Description:"));
234
gtk_size_group_add_widget(sizegroup, label);
235
gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
236
GtkWidget* entry_description = gtk_entry_new();
237
gtk_entry_set_activates_default(GTK_ENTRY(entry_description), TRUE);
239
gtk_entry_set_text(GTK_ENTRY(entry_description)
240
, STR_NON_NULL(search_engine_get_description(searchEngine)));
241
gtk_box_pack_start(GTK_BOX(hbox), entry_description, TRUE, TRUE, 0);
242
gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), hbox);
243
gtk_widget_show_all(hbox);
245
hbox = gtk_hbox_new(FALSE, 8);
246
gtk_container_set_border_width(GTK_CONTAINER(hbox), 5);
247
label = gtk_label_new_with_mnemonic(_("_URL:"));
248
gtk_size_group_add_widget(sizegroup, label);
249
gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
250
GtkWidget* entry_url = gtk_entry_new();
251
gtk_entry_set_activates_default(GTK_ENTRY(entry_url), TRUE);
253
gtk_entry_set_text(GTK_ENTRY(entry_url)
254
, STR_NON_NULL(search_engine_get_url(searchEngine)));
255
gtk_box_pack_start(GTK_BOX(hbox), entry_url, TRUE, TRUE, 0);
256
gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), hbox);
257
gtk_widget_show_all(hbox);
259
hbox = gtk_hbox_new(FALSE, 8);
260
gtk_container_set_border_width(GTK_CONTAINER(hbox), 5);
261
label = gtk_label_new_with_mnemonic(_("_Icon (name or file):"));
262
gtk_size_group_add_widget(sizegroup, label);
263
gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
264
GtkWidget* entry_icon = gtk_entry_new();
265
gtk_entry_set_activates_default(GTK_ENTRY(entry_icon), TRUE);
267
gtk_entry_set_text(GTK_ENTRY(entry_icon)
268
, STR_NON_NULL(search_engine_get_icon(searchEngine)));
269
gtk_box_pack_start(GTK_BOX(hbox), entry_icon, TRUE, TRUE, 0);
270
gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), hbox);
271
gtk_widget_show_all(hbox);
273
hbox = gtk_hbox_new(FALSE, 8);
274
gtk_container_set_border_width(GTK_CONTAINER(hbox), 5);
275
label = gtk_label_new_with_mnemonic(_("_Keyword:"));
276
gtk_size_group_add_widget(sizegroup, label);
277
gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
278
GtkWidget* entry_keyword = gtk_entry_new();
279
gtk_entry_set_activates_default(GTK_ENTRY(entry_keyword), TRUE);
281
gtk_entry_set_text(GTK_ENTRY(entry_keyword)
282
, STR_NON_NULL(search_engine_get_keyword(searchEngine)));
283
gtk_box_pack_start(GTK_BOX(hbox), entry_keyword, TRUE, TRUE, 0);
284
gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), hbox);
285
gtk_widget_show_all(hbox);
287
gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
288
if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)
290
search_engine_set_short_name(searchEngine
291
, gtk_entry_get_text(GTK_ENTRY(entry_shortName)));
292
search_engine_set_description(searchEngine
293
, gtk_entry_get_text(GTK_ENTRY(entry_description)));
294
search_engine_set_url(searchEngine
295
, gtk_entry_get_text(GTK_ENTRY(entry_url)));
296
/*search_engine_set_input_encoding(searchEngine
297
, gtk_entry_get_text(GTK_ENTRY(entry_inputEncoding)));*/
298
search_engine_set_icon(searchEngine
299
, gtk_entry_get_text(GTK_ENTRY(entry_icon)));
300
search_engine_set_keyword(searchEngine
301
, gtk_entry_get_text(GTK_ENTRY(entry_keyword)));
305
searchEngines = g_list_append(searchEngines, searchEngine);
306
liststore = gtk_tree_view_get_model(GTK_TREE_VIEW(webSearch->treeview));
307
gtk_list_store_append(GTK_LIST_STORE(liststore), &iter);
309
gtk_list_store_set(GTK_LIST_STORE(liststore), &iter
310
, ENGINES_COL_ENGINE, searchEngine, -1);
311
webSearch_toggle_edit_buttons(TRUE, webSearch);
313
gtk_widget_destroy(dialog);
316
static void on_webSearch_add(GtkWidget* widget, CWebSearch* webSearch)
318
webSearch_editEngine_dialog_new(TRUE, webSearch);
321
static void on_webSearch_edit(GtkWidget* widget, CWebSearch* webSearch)
323
webSearch_editEngine_dialog_new(FALSE, webSearch);
326
static void on_webSearch_remove(GtkWidget* widget, CWebSearch* webSearch)
328
GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(webSearch->treeview));
329
GtkTreeModel* liststore;
331
gtk_tree_selection_get_selected(selection, &liststore, &iter);
332
SearchEngine* searchEngine;
333
gtk_tree_model_get(liststore, &iter, ENGINES_COL_ENGINE, &searchEngine, -1);
334
gtk_list_store_remove(GTK_LIST_STORE(liststore), &iter);
335
search_engine_free(searchEngine);
336
searchEngines = g_list_remove(searchEngines, searchEngine);
337
//update_searchEngine(config->searchEngine, webSearch->browser);
338
webSearch_toggle_edit_buttons(g_list_nth(searchEngines, 0) != NULL, webSearch);
339
// FIXME: we want to allow undo of some kind
342
GtkWidget* webSearch_manageSearchEngines_dialog_new(MidoriBrowser* browser)
344
const gchar* dialogTitle = _("Manage search engines");
345
GtkWidget* dialog = gtk_dialog_new_with_buttons(dialogTitle
346
, GTK_WINDOW(browser)
347
, GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR
353
gtk_window_set_icon_name(GTK_WINDOW(dialog), GTK_STOCK_PROPERTIES);
354
// TODO: Implement some kind of help function
355
gtk_dialog_set_response_sensitive(GTK_DIALOG(dialog)
356
, GTK_RESPONSE_HELP, FALSE); //...
357
gint iWidth, iHeight;
358
sokoke_widget_get_text_size(dialog, "M", &iWidth, &iHeight);
359
gtk_window_set_default_size(GTK_WINDOW(dialog), iWidth * 45, -1);
360
g_signal_connect(dialog, "response", G_CALLBACK(gtk_widget_destroy), dialog);
361
// TODO: Do we want tooltips for explainations or can we omit that?
362
// TODO: We need mnemonics
363
// TODO: Take multiple windows into account when applying changes
364
GtkWidget* xfce_heading;
365
if((xfce_heading = sokoke_xfce_header_new(
366
gtk_window_get_icon_name(GTK_WINDOW(dialog)), dialogTitle)))
367
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), xfce_heading, FALSE, FALSE, 0);
368
GtkWidget* hbox = gtk_hbox_new(FALSE, 0);
369
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox, TRUE, TRUE, 12);
370
GtkTreeViewColumn* column;
371
GtkCellRenderer* renderer_text; GtkCellRenderer* renderer_pixbuf;
372
GtkListStore* liststore = gtk_list_store_new(ENGINES_COL_N
373
, G_TYPE_SEARCH_ENGINE);
374
GtkWidget* treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(liststore));
375
gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), FALSE);
376
column = gtk_tree_view_column_new();
377
renderer_pixbuf = gtk_cell_renderer_pixbuf_new();
378
gtk_tree_view_column_pack_start(column, renderer_pixbuf, FALSE);
379
gtk_tree_view_column_set_cell_data_func(column, renderer_pixbuf
380
, (GtkTreeCellDataFunc)on_webSearch_engines_render_icon, treeview, NULL);
381
renderer_text = gtk_cell_renderer_text_new();
382
gtk_tree_view_column_pack_start(column, renderer_text, TRUE);
383
gtk_tree_view_column_set_cell_data_func(column, renderer_text
384
, (GtkTreeCellDataFunc)on_webSearch_engines_render_text, treeview, NULL);
385
gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
386
GtkWidget* scrolled = gtk_scrolled_window_new(NULL, NULL);
387
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled)
388
, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
389
gtk_container_add(GTK_CONTAINER(scrolled), treeview);
390
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
391
gtk_box_pack_start(GTK_BOX(hbox), scrolled, TRUE, TRUE, 5);
392
guint n = g_list_length(searchEngines);
394
for(i = 0; i < n; i++)
396
SearchEngine* searchEngine = (SearchEngine*)g_list_nth_data(searchEngines, i);
397
gtk_list_store_insert_with_values(GTK_LIST_STORE(liststore), NULL, i
398
, ENGINES_COL_ENGINE, searchEngine, -1);
400
g_object_unref(liststore);
401
CWebSearch* webSearch = g_new0(CWebSearch, 1);
402
webSearch->browser = browser;
403
webSearch->window = dialog;
404
webSearch->treeview = treeview;
405
g_signal_connect(dialog, "response", G_CALLBACK(g_free), webSearch);
406
GtkWidget* vbox = gtk_vbox_new(FALSE, 4);
407
gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 4);
408
GtkWidget* button = gtk_button_new_from_stock(GTK_STOCK_ADD);
409
g_signal_connect(button, "clicked", G_CALLBACK(on_webSearch_add), webSearch);
410
gtk_box_pack_start(GTK_BOX(vbox), button, FALSE, FALSE, 0);
411
button = gtk_button_new_from_stock(GTK_STOCK_EDIT);
412
g_signal_connect(button, "clicked", G_CALLBACK(on_webSearch_edit), webSearch);
413
gtk_box_pack_start(GTK_BOX(vbox), button, FALSE, FALSE, 0);
414
webSearch->edit = button;
415
button = gtk_button_new_from_stock(GTK_STOCK_REMOVE);
416
g_signal_connect(button, "clicked", G_CALLBACK(on_webSearch_remove), webSearch);
417
gtk_box_pack_start(GTK_BOX(vbox), button, FALSE, FALSE, 0);
418
webSearch->remove = button;
419
button = gtk_label_new(""); // This is an invisible separator
420
gtk_box_pack_start(GTK_BOX(vbox), button, TRUE, TRUE, 12);
421
button = gtk_button_new_from_stock(GTK_STOCK_GO_DOWN);
422
gtk_widget_set_sensitive(button, FALSE); //...
423
gtk_box_pack_end(GTK_BOX(vbox), button, FALSE, FALSE, 0);
424
button = gtk_button_new_from_stock(GTK_STOCK_GO_UP);
425
gtk_widget_set_sensitive(button, FALSE); //...
426
gtk_box_pack_end(GTK_BOX(vbox), button, FALSE, FALSE, 0);
427
webSearch_toggle_edit_buttons(n > 0, webSearch);
428
gtk_widget_show_all(GTK_DIALOG(dialog)->vbox);
432
gboolean on_webSearch_key_down(GtkWidget* widget, GdkEventKey* event, MidoriBrowser* browser)
434
GdkModifierType state = (GdkModifierType)0;
435
gint x, y; gdk_window_get_pointer(NULL, &x, &y, &state);
436
if(!(state & GDK_CONTROL_MASK))
438
switch(event->keyval)
441
//update_searchEngine(config->searchEngine - 1, browser);
444
//update_searchEngine(config->searchEngine + 1, browser);
450
gboolean on_webSearch_scroll(GtkWidget* webView, GdkEventScroll* event, MidoriBrowser* browser)
452
if(event->direction == GDK_SCROLL_DOWN)
453
;//update_searchEngine(config->searchEngine + 1, browser);
454
else if(event->direction == GDK_SCROLL_UP)
455
;//update_searchEngine(config->searchEngine - 1, browser);
459
void on_webSearch_activate(GtkWidget* widget, MidoriBrowser* browser)
461
const gchar* keywords = gtk_entry_get_text(GTK_ENTRY(widget));
463
SearchEngine* searchEngine = (SearchEngine*)g_list_nth_data(searchEngines, 0/*config->searchEngine*/);
465
url = searchEngine->url;
466
else // The location search is our fallback
467
url = "";//config->locationSearch;
469
if(strstr(url, "%s"))
470
search = g_strdup_printf(url, keywords);
472
search = g_strconcat(url, " ", keywords, NULL);
473
sokoke_entry_append_completion(GTK_ENTRY(widget), keywords);
474
GtkWidget* webView = midori_browser_get_current_web_view(browser);
475
webkit_web_view_open(WEBKIT_WEB_VIEW(webView), search);