X-Git-Url: http://git.claws-mail.org/?p=claws.git;a=blobdiff_plain;f=src%2Fgtk%2Fquicksearch.c;h=33c883ed29c2e6e2a943c331e0e9399a11dfaa7b;hp=c38f4c6a3580a0d5af32e5a85a70f35ecfdb483d;hb=2af61e1324d616b7039e95ef0a220998c69df487;hpb=2352178a0ef1b8b3001a38089afcfd0d196a5be1 diff --git a/src/gtk/quicksearch.c b/src/gtk/quicksearch.c index c38f4c6a3..33c883ed2 100644 --- a/src/gtk/quicksearch.c +++ b/src/gtk/quicksearch.c @@ -1,10 +1,10 @@ /* - * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client - * Copyright (C) 2004 Hiroyuki Yamamoto & the Sylpheed-Claws team + * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client + * Copyright (C) 1999-2018 Colin Leroy and the Claws Mail team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or + * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, @@ -13,12 +13,12 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * along with this program. If not, see . */ #ifdef HAVE_CONFIG_H # include "config.h" +#include "claws-features.h" #endif #include @@ -28,7 +28,11 @@ #include #include +#if !GTK_CHECK_VERSION(3, 0, 0) +#include "gtkcmoptionmenu.h" +#endif #include "utils.h" +#include "combobox.h" #include "menu.h" #include "prefs_common.h" #include "description_window.h" @@ -38,14 +42,25 @@ #include "folderview.h" #include "folder.h" #include "prefs_matcher.h" -#include "sylpheed.h" +#include "claws.h" #include "statusbar.h" +#include "advsearch.h" +#include "alertpanel.h" + +struct _QuickSearchRequest +{ + AdvancedSearchType type; + gchar *matchstring; +}; +typedef struct _QuickSearchRequest QuickSearchRequest; struct _QuickSearch { GtkWidget *hbox_search; GtkWidget *search_type; +#if !GTK_CHECK_VERSION(3, 0, 0) GtkWidget *search_type_opt; +#endif GtkWidget *search_string_entry; GtkWidget *search_condition_expression; GtkWidget *search_description; @@ -53,71 +68,187 @@ struct _QuickSearch gboolean active; gchar *search_string; - MatcherList *matcher_list; + QuickSearchRequest request; QuickSearchExecuteCallback callback; gpointer callback_data; gboolean running; gboolean has_focus; - gboolean matching; - gboolean deferred_free; - FolderItem *root_folder_item; - gboolean is_fast; gboolean in_typing; guint press_timeout_id; + + GList *normal_search_strings; + GList *extended_search_strings; + + /* dynamic and autorun qs settings are exclusive*/ + GtkWidget *dynamic_menuitem; + GtkWidget *autorun_menuitem; + + AdvancedSearch *asearch; + gboolean want_reexec; + gboolean want_history; }; -static void quicksearch_set_running(QuickSearch *quicksearch, gboolean run); -static void quicksearch_set_active(QuickSearch *quicksearch, gboolean active); -static void quicksearch_reset_folder_items(QuickSearch *quicksearch, FolderItem *folder_item); +static GdkColor qs_active_bgcolor = { + (gulong)0, + (gushort)0, + (gushort)0, + (gushort)0 +}; -gboolean quicksearch_is_fast(QuickSearch *quicksearch) +static GdkColor qs_active_color = { + (gulong)0, + (gushort)0, + (gushort)0, + (gushort)0 +}; + +static GdkColor qs_error_bgcolor = { + (gulong)0, + (gushort)0, + (gushort)0, + (gushort)0 +}; + +static GdkColor qs_error_color = { + (gulong)0, + (gushort)0, + (gushort)0, + (gushort)0 +}; + +void quicksearch_set_on_progress_cb(QuickSearch* search, + gboolean (*cb)(gpointer data, guint at, guint matched, guint total), gpointer data) { - return quicksearch->is_fast; + advsearch_set_on_progress_cb(search->asearch, cb, data); } -static void prepare_matcher(QuickSearch *quicksearch) +static void quicksearch_set_running(QuickSearch *quicksearch, gboolean run); +static void quicksearch_set_matchstring(QuickSearch *quicksearch, const gchar *matchstring); +static void quicksearch_set_active(QuickSearch *quicksearch, gboolean active); +static void quicksearch_set_popdown_strings(QuickSearch *quicksearch); + +static void quicksearch_add_to_history(QuickSearch* quicksearch) { - const gchar *search_string = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(quicksearch->search_string_entry)->entry)); + gchar* search_string = quicksearch->request.matchstring; + + /* add to history, for extended search add only correct matching rules */ + if (quicksearch->want_history && !quicksearch->in_typing && search_string && strlen(search_string) != 0) { + switch (prefs_common.summary_quicksearch_type) { + case ADVANCED_SEARCH_EXTENDED: + if (advsearch_has_proper_predicate(quicksearch->asearch)) { + quicksearch->extended_search_strings = + add_history(quicksearch->extended_search_strings, + search_string); + prefs_common.summary_quicksearch_history = + add_history(prefs_common.summary_quicksearch_history, + search_string); + } + break; + default: + quicksearch->normal_search_strings = + add_history(quicksearch->normal_search_strings, + search_string); + prefs_common.summary_quicksearch_history = + add_history(prefs_common.summary_quicksearch_history, + search_string); + break; + } - if (search_string == NULL || search_string[0] == '\0') { - quicksearch_set_active(quicksearch, FALSE); + quicksearch_set_popdown_strings(quicksearch); } - if (quicksearch->matcher_list != NULL) { - if (quicksearch->matching) { - quicksearch->deferred_free = TRUE; - return; - } - quicksearch->deferred_free = FALSE; - matcherlist_free(quicksearch->matcher_list); - quicksearch->matcher_list = NULL; - } + quicksearch->want_history = FALSE; +} - if (search_string == NULL || search_string[0] == '\0') { +static void quicksearch_invoke_execute(QuickSearch *quicksearch, gboolean run_only_if_fast) +{ + if (quicksearch->running) { + quicksearch->want_reexec = TRUE; + advsearch_abort(quicksearch->asearch); return; } - if (prefs_common.summary_quicksearch_type == QUICK_SEARCH_EXTENDED) { - char *newstr = NULL; - - newstr = expand_search_string(search_string); - if (newstr && newstr[0] != '\0') { - quicksearch->matcher_list = matcher_parser_get_cond(newstr, &quicksearch->is_fast); - g_free(newstr); - } else { - quicksearch->matcher_list = NULL; - quicksearch_set_active(quicksearch, FALSE); + do { + gboolean active = quicksearch->request.matchstring != NULL + && g_strcmp0(quicksearch->request.matchstring, ""); + advsearch_set(quicksearch->asearch, quicksearch->request.type, + quicksearch->request.matchstring); + if (run_only_if_fast && !advsearch_is_fast(quicksearch->asearch)) return; + + quicksearch_add_to_history(quicksearch); + + quicksearch_set_active(quicksearch, active); + + quicksearch->want_reexec = FALSE; + quicksearch_set_running(quicksearch, TRUE); + if (quicksearch->callback != NULL) + quicksearch->callback(quicksearch, quicksearch->callback_data); + quicksearch_set_running(quicksearch, FALSE); + } while (quicksearch->want_reexec); +} + +gboolean quicksearch_run_on_folder(QuickSearch* quicksearch, FolderItem *folderItem, MsgInfoList **result) +{ + if (quicksearch_has_sat_predicate(quicksearch)) { + gboolean was_running = quicksearch_is_running(quicksearch); + gboolean searchres; + + if (!was_running) + quicksearch_set_running(quicksearch, TRUE); + + main_window_cursor_wait(mainwindow_get_mainwindow()); + searchres = advsearch_search_msgs_in_folders(quicksearch->asearch, result, folderItem, FALSE); + main_window_cursor_normal(mainwindow_get_mainwindow()); + + if (!was_running) + quicksearch_set_running(quicksearch, FALSE); + + if (quicksearch->want_reexec) { + advsearch_set(quicksearch->asearch, quicksearch->request.type, ""); } - } else { - quicksearch->is_fast = TRUE; - g_free(quicksearch->search_string); - quicksearch->search_string = g_strdup(search_string); - } + return searchres; + } else + return FALSE; +} - quicksearch_set_active(quicksearch, TRUE); +gboolean quicksearch_is_fast(QuickSearch *quicksearch) +{ + return advsearch_is_fast(quicksearch->asearch); +} + +static void quicksearch_set_type(QuickSearch *quicksearch, gint type) +{ +#if !GTK_CHECK_VERSION(3, 0, 0) + gint index; + quicksearch->request.type = type; + index = menu_find_option_menu_index(GTK_CMOPTION_MENU(quicksearch->search_type_opt), + GINT_TO_POINTER(type), + NULL); + gtk_cmoption_menu_set_history(GTK_CMOPTION_MENU(quicksearch->search_type_opt), index); +#endif +} + +static gchar *quicksearch_get_text(QuickSearch * quicksearch) +{ + gchar *search_string = gtk_editable_get_chars(GTK_EDITABLE(gtk_bin_get_child(GTK_BIN((quicksearch->search_string_entry)))), 0, -1); + + return search_string; +} + +static void quicksearch_set_popdown_strings(QuickSearch *quicksearch) +{ + GtkWidget *search_string_entry = quicksearch->search_string_entry; + + combobox_unset_popdown_strings(GTK_COMBO_BOX_TEXT(search_string_entry)); + if (prefs_common.summary_quicksearch_type == ADVANCED_SEARCH_EXTENDED) + combobox_set_popdown_strings(GTK_COMBO_BOX_TEXT(search_string_entry), + quicksearch->extended_search_strings); + else + combobox_set_popdown_strings(GTK_COMBO_BOX_TEXT(search_string_entry), + quicksearch->normal_search_strings); } static void update_extended_buttons (QuickSearch *quicksearch) @@ -125,10 +256,10 @@ static void update_extended_buttons (QuickSearch *quicksearch) GtkWidget *expr_btn = quicksearch->search_condition_expression; GtkWidget *ext_btn = quicksearch->search_description; - g_return_if_fail(expr_btn != NULL); - g_return_if_fail(ext_btn != NULL); + cm_return_if_fail(expr_btn != NULL); + cm_return_if_fail(ext_btn != NULL); - if (prefs_common.summary_quicksearch_type == QUICK_SEARCH_EXTENDED) { + if (prefs_common.summary_quicksearch_type == ADVANCED_SEARCH_EXTENDED) { gtk_widget_show(expr_btn); gtk_widget_show(ext_btn); } else { @@ -159,27 +290,13 @@ gboolean quicksearch_has_focus(QuickSearch *quicksearch) static void searchbar_run(QuickSearch *quicksearch, gboolean run_only_if_fast) { - const gchar *search_string = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(quicksearch->search_string_entry)->entry)); - - /* add to history */ - if (!quicksearch->in_typing && search_string && strlen(search_string) != 0) { - prefs_common.summary_quicksearch_history = - add_history(prefs_common.summary_quicksearch_history, - search_string); - gtk_combo_set_popdown_strings(GTK_COMBO(quicksearch->search_string_entry), - prefs_common.summary_quicksearch_history); - } + gchar *search_string = quicksearch_get_text(quicksearch); + quicksearch_set_matchstring(quicksearch, search_string); + g_free(search_string); - prepare_matcher(quicksearch); - if (run_only_if_fast && !quicksearch->is_fast) - return; - if (quicksearch->matcher_list == NULL && - prefs_common.summary_quicksearch_type == QUICK_SEARCH_EXTENDED) - return; - quicksearch_set_running(quicksearch, TRUE); - if (quicksearch->callback != NULL) - quicksearch->callback(quicksearch, quicksearch->callback_data); - quicksearch_set_running(quicksearch, FALSE); + quicksearch->want_history = TRUE; + + quicksearch_invoke_execute(quicksearch, run_only_if_fast); } static int searchbar_changed_timeout(void *data) @@ -192,44 +309,67 @@ static int searchbar_changed_timeout(void *data) return FALSE; } -static gboolean searchbar_changed_cb(GtkWidget *widget, QuickSearch *qs) +static void searchbar_changed_cb(GtkWidget *widget, QuickSearch *qs) { + if (!qs->has_focus && prefs_common.summary_quicksearch_autorun) { + gtk_widget_grab_focus(qs->search_string_entry); + searchbar_run(qs, TRUE); + return; + } + if (prefs_common.summary_quicksearch_dynamic) { - if (qs->press_timeout_id != -1) { - gtk_timeout_remove(qs->press_timeout_id); + if (qs->press_timeout_id != 0) { + g_source_remove(qs->press_timeout_id); } - qs->press_timeout_id = gtk_timeout_add(500, + qs->press_timeout_id = g_timeout_add(500, searchbar_changed_timeout, qs); } - return FALSE; + if (!qs->has_focus) + gtk_widget_grab_focus(qs->search_string_entry); } static gboolean searchbar_pressed(GtkWidget *widget, GdkEventKey *event, QuickSearch *quicksearch) { - if (event != NULL && event->keyval == GDK_Escape) { + if (event != NULL && (event->keyval == GDK_KEY_ISO_Left_Tab)) { + /* Shift+Tab moves focus "back" */ + gtk_widget_grab_focus(quicksearch->search_type_opt); + return TRUE; + } + if (event != NULL && (event->keyval == GDK_KEY_Tab)) { + /* Just Tab moves focus "forwards" */ + gtk_widget_grab_focus(quicksearch->clear_search); + return TRUE; + } - const gchar *str; + if (event != NULL && (event->keyval == GDK_KEY_Escape)) { + gchar *str; quicksearch->in_typing = FALSE; - str = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(quicksearch->search_string_entry)->entry)); - g_return_val_if_fail(str != NULL, TRUE); + str = quicksearch_get_text(quicksearch); + cm_return_val_if_fail(str != NULL, TRUE); /* If the string entry is empty -> hide quicksearch bar. If not -> empty it */ if (!*str) { - quicksearch_hide(quicksearch); + summaryview_activate_quicksearch( + mainwindow_get_mainwindow()->summaryview, + FALSE); } else { quicksearch_set(quicksearch, prefs_common.summary_quicksearch_type, ""); gtk_widget_grab_focus( - GTK_WIDGET(GTK_COMBO(quicksearch->search_string_entry)->entry)); + mainwindow_get_mainwindow()->summaryview->ctree); } - + g_free(str); return TRUE; } - if (event != NULL && event->keyval == GDK_Return) { + if (event != NULL && (event->keyval == GDK_KEY_Return || event->keyval == GDK_KEY_KP_Enter)) { + if (quicksearch->press_timeout_id != 0) { + g_source_remove(quicksearch->press_timeout_id); + quicksearch->press_timeout_id = 0; + } quicksearch->in_typing = FALSE; /* add expression to history list and exec quicksearch */ searchbar_run(quicksearch, FALSE); @@ -238,31 +378,32 @@ static gboolean searchbar_pressed(GtkWidget *widget, GdkEventKey *event, return TRUE; } + if (event && (event->keyval == GDK_KEY_Down || event->keyval == GDK_KEY_Up)) { + combobox_set_value_from_arrow_key( + GTK_COMBO_BOX(quicksearch->search_string_entry), + event->keyval); + return TRUE; + } + return FALSE; } static gboolean searchtype_changed(GtkMenuItem *widget, gpointer data) { QuickSearch *quicksearch = (QuickSearch *)data; - const gchar *search_string = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(quicksearch->search_string_entry)->entry)); prefs_common.summary_quicksearch_type = GPOINTER_TO_INT(g_object_get_data( G_OBJECT(GTK_MENU_ITEM(gtk_menu_get_active( GTK_MENU(quicksearch->search_type)))), MENU_VAL_ID)); + quicksearch->request.type = prefs_common.summary_quicksearch_type; /* Show extended search description button, only when Extended is selected */ update_extended_buttons(quicksearch); + quicksearch_set_popdown_strings(quicksearch); - if (!search_string || strlen(search_string) == 0) { - return TRUE; - } - - prepare_matcher(quicksearch); + quicksearch_invoke_execute(quicksearch, FALSE); + gtk_widget_grab_focus(quicksearch->search_string_entry); - quicksearch_set_running(quicksearch, TRUE); - if (quicksearch->callback != NULL) - quicksearch->callback(quicksearch, quicksearch->callback_data); - quicksearch_set_running(quicksearch, FALSE); return TRUE; } @@ -270,24 +411,14 @@ static gboolean searchtype_recursive_changed(GtkMenuItem *widget, gpointer data) { QuickSearch *quicksearch = (QuickSearch *)data; gboolean checked = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget)); - const gchar *search_string = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(quicksearch->search_string_entry)->entry)); prefs_common.summary_quicksearch_recurse = checked; /* reselect the search type */ - gtk_option_menu_set_history(GTK_OPTION_MENU(quicksearch->search_type_opt), - prefs_common.summary_quicksearch_type); + quicksearch_set_type(quicksearch, prefs_common.summary_quicksearch_type); - if (!search_string || strlen(search_string) == 0) { - return TRUE; - } + quicksearch_invoke_execute(quicksearch, FALSE); - prepare_matcher(quicksearch); - - quicksearch_set_running(quicksearch, TRUE); - if (quicksearch->callback != NULL) - quicksearch->callback(quicksearch, quicksearch->callback_data); - quicksearch_set_running(quicksearch, FALSE); return TRUE; } @@ -299,8 +430,7 @@ static gboolean searchtype_sticky_changed(GtkMenuItem *widget, gpointer data) prefs_common.summary_quicksearch_sticky = checked; /* reselect the search type */ - gtk_option_menu_set_history(GTK_OPTION_MENU(quicksearch->search_type_opt), - prefs_common.summary_quicksearch_type); + quicksearch_set_type(quicksearch, prefs_common.summary_quicksearch_type); return TRUE; } @@ -311,10 +441,30 @@ static gboolean searchtype_dynamic_changed(GtkMenuItem *widget, gpointer data) gboolean checked = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget)); prefs_common.summary_quicksearch_dynamic = checked; + if (checked) + gtk_check_menu_item_set_active( + GTK_CHECK_MENU_ITEM(quicksearch->autorun_menuitem), + FALSE); /* reselect the search type */ - gtk_option_menu_set_history(GTK_OPTION_MENU(quicksearch->search_type_opt), - prefs_common.summary_quicksearch_type); + quicksearch_set_type(quicksearch, prefs_common.summary_quicksearch_type); + + return TRUE; +} + +static gboolean searchtype_autorun_changed(GtkMenuItem *widget, gpointer data) +{ + QuickSearch *quicksearch = (QuickSearch *)data; + gboolean checked = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget)); + + prefs_common.summary_quicksearch_autorun = checked; + if (checked) + gtk_check_menu_item_set_active( + GTK_CHECK_MENU_ITEM(quicksearch->dynamic_menuitem), + FALSE); + + /* reselect the search type */ + quicksearch_set_type(quicksearch, prefs_common.summary_quicksearch_type); return TRUE; } @@ -326,36 +476,42 @@ static gboolean searchtype_dynamic_changed(GtkMenuItem *widget, gpointer data) */ static gchar *search_descr_strings[] = { "a", N_("all messages"), - "ag #", N_("messages whose age is greater than #"), - "al #", N_("messages whose age is less than #"), + "ag #", N_("messages whose age is greater than # days"), + "al #", N_("messages whose age is less than # days"), + "agh #", N_("messages whose age is greater than # hours"), + "alh #", N_("messages whose age is less than # hours"), "b S", N_("messages which contain S in the message body"), "B S", N_("messages which contain S in the whole message"), "c S", N_("messages carbon-copied to S"), - "C S", N_("message is either to: or cc: to S"), + "C S", N_("message is either To: or Cc: to S"), "D", N_("deleted messages"), /** how I can filter deleted messages **/ "e S", N_("messages which contain S in the Sender field"), "E S", N_("true if execute \"S\" succeeds"), "f S", N_("messages originating from user S"), "F", N_("forwarded messages"), - "h S", N_("messages which contain header S"), + "ha", N_("messages which have attachments"), + "h S", N_("messages which contain S in any header name or value"), + "H S", N_("messages which contain S in the value of any header"), "i S", N_("messages which contain S in Message-ID header"), - "I S", N_("messages which contain S in inreplyto header"), + "I S", N_("messages which contain S in In-Reply-To header"), "k #", N_("messages which are marked with color #"), "L", N_("locked messages"), "n S", N_("messages which are in newsgroup S"), "N", N_("new messages"), "O", N_("old messages"), "p", N_("incomplete messages (not entirely downloaded)"), - "r", N_("messages which have been replied to"), + "r", N_("messages which you have replied to"), "R", N_("read messages"), "s S", N_("messages which contain S in subject"), - "se #", N_("messages whose score is equal to #"), - "sg #", N_("messages whose score is greater than #"), - "sl #", N_("messages whose score is lower than #"), - "Se #", N_("messages whose size is equal to #"), - "Sg #", N_("messages whose size is greater than #"), - "Ss #", N_("messages whose size is smaller than #"), + "se #", N_("messages whose score is equal to # points"), + "sg #", N_("messages whose score is greater than # points"), + "sl #", N_("messages whose score is lower than # points"), + "Se #", N_("messages whose size is equal to # bytes"), + "Sg #", N_("messages whose size is greater than # bytes"), + "Ss #", N_("messages whose size is smaller than # bytes"), "t S", N_("messages which have been sent to S"), + "tg S", N_("messages which tags contain S"), + "tagged",N_("messages which have tag(s)"), "T", N_("marked messages"), "U", N_("unread messages"), "x S", N_("messages which contain S in References header"), @@ -366,24 +522,28 @@ static gchar *search_descr_strings[] = { "|", N_("logical OR operator"), "! or ~", N_("logical NOT operator"), "%", N_("case sensitive search"), + "#", N_("match using regular expressions instead of substring search"), "", "" , - " ", N_("all filtering expressions are allowed"), + " ", N_("all filtering expressions are allowed, but cannot be mixed " + "through logical operators with the expressions above"), NULL, NULL }; static DescriptionWindow search_descr = { NULL, NULL, + FALSE, 2, N_("Extended Search"), N_("Extended Search allows the user to define criteria that messages must " - "have in order to match and be displayed in the message list.\n\n" + "have in order to match and be displayed in the message list.\n" "The following symbols can be used:"), search_descr_strings }; static void search_description_cb(GtkWidget *widget) { + search_descr.parent = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "description_window"); description_window_create(&search_descr); }; @@ -403,7 +563,7 @@ static void search_condition_expr_done(MatcherList * matchers) { gchar *str; - g_return_if_fail( + cm_return_if_fail( mainwindow_get_mainwindow()->summaryview->quicksearch != NULL); if (matchers == NULL) @@ -423,18 +583,17 @@ static void search_condition_expr_done(MatcherList * matchers) static gboolean search_condition_expr(GtkMenuItem *widget, gpointer data) { - const gchar * cond_str; + gchar * cond_str; MatcherList * matchers = NULL; - g_return_val_if_fail( + cm_return_val_if_fail( mainwindow_get_mainwindow()->summaryview->quicksearch != NULL, FALSE); - /* re-use it the current quicksearch value if it's a condition expression, + /* re-use the current quicksearch value if it's a condition expression, otherwise ignore it silently */ - cond_str = gtk_entry_get_text( - GTK_ENTRY(GTK_COMBO(mainwindow_get_mainwindow()->summaryview->quicksearch-> - search_string_entry)->entry)); + cond_str = quicksearch_get_text(mainwindow_get_mainwindow()->summaryview->quicksearch); + if (*cond_str != '\0') { matchers = matcher_parser_get_cond((gchar*)cond_str, NULL); } @@ -444,15 +603,49 @@ static gboolean search_condition_expr(GtkMenuItem *widget, gpointer data) if (matchers != NULL) matcherlist_free(matchers); + g_free(cond_str); + return TRUE; }; +static void quicksearch_set_button(GtkButton *button, const gchar *icon, const gchar *text) +{ + GList *children = gtk_container_get_children(GTK_CONTAINER(button)); + GList *cur; + GtkWidget *box; + gboolean icon_visible; + + g_object_get(gtk_settings_get_default(), + "gtk-button-images", &icon_visible, + NULL); + + for (cur = children; cur; cur = cur->next) + gtk_container_remove(GTK_CONTAINER(button), GTK_WIDGET(cur->data)); + + g_list_free(children); + box = gtk_hbox_new(FALSE, 0); + + gtk_container_add(GTK_CONTAINER(button), box); + if (icon_visible || !text || !*text) + gtk_box_pack_start(GTK_BOX(box), gtk_image_new_from_stock(icon, + GTK_ICON_SIZE_BUTTON), FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(box), gtk_label_new_with_mnemonic(text), FALSE, FALSE, 0); + gtk_widget_show_all(box); +} + +static void quicksearch_error(gpointer data) +{ + alertpanel_error(_("Something went wrong during search. Please check your logs.")); +} + QuickSearch *quicksearch_new() { QuickSearch *quicksearch; GtkWidget *hbox_search; +#if !GTK_CHECK_VERSION(3, 0, 0) GtkWidget *search_type_opt; +#endif GtkWidget *search_type; GtkWidget *search_string_entry; GtkWidget *search_hbox; @@ -460,31 +653,59 @@ QuickSearch *quicksearch_new() GtkWidget *clear_search; GtkWidget *search_condition_expression; GtkWidget *menuitem; - GtkTooltips *search_cond_expr_tip; + GtkWidget *vbox; quicksearch = g_new0(QuickSearch, 1); + quicksearch->asearch = advsearch_new(); + advsearch_set_on_error_cb(quicksearch->asearch, quicksearch_error, NULL); + + /* init. values initally found in quicksearch_new(). + There's no need to init. all pointers to NULL since we use g_new0 + */ + quicksearch->active = FALSE; + quicksearch->running = FALSE; + quicksearch->in_typing = FALSE; + quicksearch->press_timeout_id = 0; + quicksearch->normal_search_strings = NULL; + quicksearch->extended_search_strings = NULL; + /* quick search */ hbox_search = gtk_hbox_new(FALSE, 0); - search_type_opt = gtk_option_menu_new(); +#if !GTK_CHECK_VERSION(3, 0, 0) + search_type_opt = gtk_cmoption_menu_new(); gtk_widget_show(search_type_opt); gtk_box_pack_start(GTK_BOX(hbox_search), search_type_opt, FALSE, FALSE, 0); +#endif search_type = gtk_menu_new(); - MENUITEM_ADD (search_type, menuitem, _("Subject"), QUICK_SEARCH_SUBJECT); + MENUITEM_ADD (search_type, menuitem, + prefs_common_translated_header_name("Subject"), ADVANCED_SEARCH_SUBJECT); g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK(searchtype_changed), quicksearch); - MENUITEM_ADD (search_type, menuitem, _("From"), QUICK_SEARCH_FROM); + MENUITEM_ADD (search_type, menuitem, + prefs_common_translated_header_name("From"), ADVANCED_SEARCH_FROM); g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK(searchtype_changed), quicksearch); - MENUITEM_ADD (search_type, menuitem, _("To"), QUICK_SEARCH_TO); + MENUITEM_ADD (search_type, menuitem, + prefs_common_translated_header_name("To"), ADVANCED_SEARCH_TO); g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK(searchtype_changed), quicksearch); - MENUITEM_ADD (search_type, menuitem, _("Extended"), QUICK_SEARCH_EXTENDED); + MENUITEM_ADD (search_type, menuitem, + prefs_common_translated_header_name("Tag"), ADVANCED_SEARCH_TAG); + g_signal_connect(G_OBJECT(menuitem), "activate", + G_CALLBACK(searchtype_changed), + quicksearch); + MENUITEM_ADD (search_type, menuitem, + _("From/To/Cc/Subject/Tag"), ADVANCED_SEARCH_MIXED); + g_signal_connect(G_OBJECT(menuitem), "activate", + G_CALLBACK(searchtype_changed), + quicksearch); + MENUITEM_ADD (search_type, menuitem, _("Extended"), ADVANCED_SEARCH_EXTENDED); g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK(searchtype_changed), quicksearch); @@ -496,7 +717,6 @@ QuickSearch *quicksearch_new() gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuitem), prefs_common.summary_quicksearch_recurse); - g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK(searchtype_recursive_changed), quicksearch); @@ -517,208 +737,253 @@ QuickSearch *quicksearch_new() gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuitem), prefs_common.summary_quicksearch_dynamic); + quicksearch->dynamic_menuitem = menuitem; + g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK(searchtype_dynamic_changed), quicksearch); - gtk_option_menu_set_menu(GTK_OPTION_MENU(search_type_opt), search_type); + menuitem = gtk_check_menu_item_new_with_label(_("Run on select")); + gtk_menu_shell_append(GTK_MENU_SHELL(search_type), menuitem); + + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuitem), + prefs_common.summary_quicksearch_autorun); + + quicksearch->autorun_menuitem = menuitem; + + g_signal_connect(G_OBJECT(menuitem), "activate", + G_CALLBACK(searchtype_autorun_changed), + quicksearch); + +#if !GTK_CHECK_VERSION(3, 0, 0) + gtk_cmoption_menu_set_menu(GTK_CMOPTION_MENU(search_type_opt), search_type); - gtk_option_menu_set_history(GTK_OPTION_MENU(search_type_opt), prefs_common.summary_quicksearch_type); + quicksearch->search_type_opt = search_type_opt; +#endif + quicksearch_set_type(quicksearch, prefs_common.summary_quicksearch_type); gtk_widget_show(search_type); - search_string_entry = gtk_combo_new(); - gtk_box_pack_start(GTK_BOX(hbox_search), search_string_entry, FALSE, FALSE, 2); - gtk_combo_set_value_in_list(GTK_COMBO(search_string_entry), FALSE, TRUE); - gtk_combo_set_case_sensitive(GTK_COMBO(search_string_entry), TRUE); - if (prefs_common.summary_quicksearch_history) - gtk_combo_set_popdown_strings(GTK_COMBO(search_string_entry), - prefs_common.summary_quicksearch_history); - gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(search_string_entry)->entry), ""); + search_string_entry = gtk_combo_box_text_new_with_entry (); + gtk_combo_box_set_active(GTK_COMBO_BOX(search_string_entry), -1); + + vbox = gtk_vbox_new(TRUE, 0); + gtk_box_pack_start(GTK_BOX(vbox), search_string_entry, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(hbox_search), vbox, TRUE, TRUE, 4); + + gtk_widget_show(vbox); gtk_widget_show(search_string_entry); search_hbox = gtk_hbox_new(FALSE, 5); - -#if GTK_CHECK_VERSION(2, 8, 0) clear_search = gtk_button_new_from_stock(GTK_STOCK_CLEAR); -#else - clear_search = gtk_button_new_with_label(_(" Clear ")); -#endif gtk_box_pack_start(GTK_BOX(search_hbox), clear_search, FALSE, FALSE, 0); g_signal_connect(G_OBJECT(clear_search), "clicked", G_CALLBACK(clear_search_cb), quicksearch); + CLAWS_SET_TIP(clear_search, + _("Clear the current search")); gtk_widget_show(clear_search); -#if GTK_CHECK_VERSION(2, 8, 0) search_condition_expression = gtk_button_new_from_stock(GTK_STOCK_EDIT); -#else - search_condition_expression = gtk_button_new_with_label(" ... "); -#endif gtk_box_pack_start(GTK_BOX(search_hbox), search_condition_expression, FALSE, FALSE, 0); g_signal_connect(G_OBJECT (search_condition_expression), "clicked", G_CALLBACK(search_condition_expr), quicksearch); - search_cond_expr_tip = gtk_tooltips_new(); - gtk_tooltips_set_tip(GTK_TOOLTIPS(search_cond_expr_tip), - search_condition_expression, - _("Edit search criteria"), NULL); + CLAWS_SET_TIP(search_condition_expression, + _("Edit search criteria")); gtk_widget_show(search_condition_expression); -#if GTK_CHECK_VERSION(2, 8, 0) search_description = gtk_button_new_from_stock(GTK_STOCK_INFO); -#else - search_description = gtk_button_new_with_label(_(" Extended Symbols... ")); -#endif gtk_box_pack_start(GTK_BOX(search_hbox), search_description, FALSE, FALSE, 0); g_signal_connect(G_OBJECT(search_description), "clicked", G_CALLBACK(search_description_cb), NULL); + CLAWS_SET_TIP(search_description, + _("Information about extended symbols")); gtk_widget_show(search_description); gtk_box_pack_start(GTK_BOX(hbox_search), search_hbox, FALSE, FALSE, 2); gtk_widget_show(search_hbox); - g_signal_connect(G_OBJECT(GTK_COMBO(search_string_entry)->entry), + g_signal_connect(G_OBJECT(gtk_bin_get_child(GTK_BIN((search_string_entry)))), "key_press_event", G_CALLBACK(searchbar_pressed), quicksearch); - g_signal_connect(G_OBJECT(GTK_COMBO(search_string_entry)->entry), + g_signal_connect(G_OBJECT(gtk_bin_get_child(GTK_BIN((search_string_entry)))), "changed", G_CALLBACK(searchbar_changed_cb), quicksearch); - g_signal_connect(G_OBJECT(GTK_COMBO(search_string_entry)->entry), + g_signal_connect(G_OBJECT(gtk_bin_get_child(GTK_BIN((search_string_entry)))), "focus_in_event", G_CALLBACK(searchbar_focus_evt_in), quicksearch); - g_signal_connect(G_OBJECT(GTK_COMBO(search_string_entry)->entry), + g_signal_connect(G_OBJECT(gtk_bin_get_child(GTK_BIN((search_string_entry)))), "focus_out_event", G_CALLBACK(searchbar_focus_evt_out), quicksearch); quicksearch->hbox_search = hbox_search; quicksearch->search_type = search_type; - quicksearch->search_type_opt = search_type_opt; quicksearch->search_string_entry = search_string_entry; quicksearch->search_condition_expression = search_condition_expression; quicksearch->search_description = search_description; - quicksearch->matcher_list = NULL; quicksearch->active = FALSE; quicksearch->running = FALSE; quicksearch->clear_search = clear_search; quicksearch->in_typing = FALSE; - quicksearch->press_timeout_id = -1; + quicksearch->press_timeout_id = 0; + quicksearch->normal_search_strings = NULL; + quicksearch->extended_search_strings = NULL; + quicksearch_set_button(GTK_BUTTON(quicksearch->search_description), GTK_STOCK_INFO, _("_Information")); + quicksearch_set_button(GTK_BUTTON(quicksearch->search_condition_expression), GTK_STOCK_EDIT, _("E_dit")); + quicksearch_set_button(GTK_BUTTON(quicksearch->clear_search), GTK_STOCK_CLEAR, _("C_lear")); + update_extended_buttons(quicksearch); + gtkut_convert_int_to_gdk_color(prefs_common.color[COL_QS_ACTIVE_BG], + &qs_active_bgcolor); + gtkut_convert_int_to_gdk_color(prefs_common.color[COL_QS_ACTIVE], + &qs_active_color); + gtkut_convert_int_to_gdk_color(prefs_common.color[COL_QS_ERROR_BG], + &qs_error_bgcolor); + gtkut_convert_int_to_gdk_color(prefs_common.color[COL_QS_ERROR], + &qs_error_color); + return quicksearch; } +void quicksearch_relayout(QuickSearch *quicksearch) +{ + switch (prefs_common.layout_mode) { + case NORMAL_LAYOUT: + case WIDE_LAYOUT: + case WIDE_MSGLIST_LAYOUT: + quicksearch_set_button(GTK_BUTTON(quicksearch->search_description), GTK_STOCK_INFO, _("_Information")); + quicksearch_set_button(GTK_BUTTON(quicksearch->search_condition_expression), GTK_STOCK_EDIT, _("E_dit")); + quicksearch_set_button(GTK_BUTTON(quicksearch->clear_search), GTK_STOCK_CLEAR, _("C_lear")); + break; + case SMALL_LAYOUT: + case VERTICAL_LAYOUT: + quicksearch_set_button(GTK_BUTTON(quicksearch->search_description), GTK_STOCK_INFO, ""); + quicksearch_set_button(GTK_BUTTON(quicksearch->search_condition_expression), GTK_STOCK_EDIT, ""); + quicksearch_set_button(GTK_BUTTON(quicksearch->clear_search), GTK_STOCK_CLEAR, ""); + break; + } +} + GtkWidget *quicksearch_get_widget(QuickSearch *quicksearch) { return quicksearch->hbox_search; } +GtkWidget *quicksearch_get_entry(QuickSearch *quicksearch) +{ + return gtk_bin_get_child(GTK_BIN(quicksearch->search_string_entry)); +} + void quicksearch_show(QuickSearch *quicksearch) { - prepare_matcher(quicksearch); + MainWindow *mainwin = mainwindow_get_mainwindow(); + GtkWidget *ctree = NULL; gtk_widget_show(quicksearch->hbox_search); update_extended_buttons(quicksearch); - gtk_widget_grab_focus( - GTK_WIDGET(GTK_COMBO(quicksearch->search_string_entry)->entry)); + gtk_widget_grab_focus(quicksearch->search_string_entry); + + if (!mainwin || !mainwin->summaryview) { + return; + } + + ctree = summary_get_main_widget(mainwin->summaryview); + + if (ctree && mainwin->summaryview->selected) + gtk_cmctree_node_moveto(GTK_CMCTREE(ctree), + mainwin->summaryview->selected, + 0, 0.5, 0); } void quicksearch_hide(QuickSearch *quicksearch) { - quicksearch_set(quicksearch, prefs_common.summary_quicksearch_type, ""); - quicksearch_set_active(quicksearch, FALSE); + if (quicksearch_has_sat_predicate(quicksearch)) { + quicksearch_set(quicksearch, prefs_common.summary_quicksearch_type, ""); + quicksearch_set_active(quicksearch, FALSE); + } gtk_widget_hide(quicksearch->hbox_search); } -void quicksearch_set(QuickSearch *quicksearch, QuickSearchType type, - const gchar *matchstring) +/* + *\brief Sets the matchstring. + * + *\param quicksearch quicksearch to set + *\param matchstring the match string; it is duplicated, not stored + */ +static void quicksearch_set_matchstring(QuickSearch *quicksearch, + const gchar *matchstring) +{ + g_free(quicksearch->request.matchstring); + quicksearch->request.matchstring = g_strdup(matchstring); +} + +void quicksearch_set(QuickSearch *quicksearch, AdvancedSearchType type, const gchar *matchstring) { - gtk_option_menu_set_history(GTK_OPTION_MENU(quicksearch->search_type_opt), - type); + quicksearch_set_type(quicksearch, type); + + if (!matchstring || !(*matchstring)) + quicksearch->in_typing = FALSE; - g_signal_handlers_block_by_func(G_OBJECT(GTK_COMBO(quicksearch->search_string_entry)->entry), - G_CALLBACK(searchbar_changed_cb), quicksearch); - gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(quicksearch->search_string_entry)->entry), + quicksearch_set_matchstring(quicksearch, matchstring); + + g_signal_handlers_block_by_func(G_OBJECT(gtk_bin_get_child(GTK_BIN((quicksearch->search_string_entry)))), + G_CALLBACK(searchbar_changed_cb), quicksearch); + gtk_entry_set_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN((quicksearch->search_string_entry)))), matchstring); - g_signal_handlers_unblock_by_func(G_OBJECT(GTK_COMBO(quicksearch->search_string_entry)->entry), - G_CALLBACK(searchbar_changed_cb), quicksearch); + g_signal_handlers_unblock_by_func(G_OBJECT(gtk_bin_get_child(GTK_BIN((quicksearch->search_string_entry)))), + G_CALLBACK(searchbar_changed_cb), quicksearch); prefs_common.summary_quicksearch_type = type; - prepare_matcher(quicksearch); - - quicksearch_set_running(quicksearch, TRUE); - if (quicksearch->callback != NULL) - quicksearch->callback(quicksearch, quicksearch->callback_data); - quicksearch_set_running(quicksearch, FALSE); + quicksearch_invoke_execute(quicksearch, FALSE); } -gboolean quicksearch_is_active(QuickSearch *quicksearch) +gboolean quicksearch_has_sat_predicate(QuickSearch *quicksearch) { - return quicksearch->active && - (prefs_common.summary_quicksearch_type != QUICK_SEARCH_EXTENDED - || quicksearch->matcher_list != NULL); + return quicksearch->active && advsearch_has_proper_predicate(quicksearch->asearch); } static void quicksearch_set_active(QuickSearch *quicksearch, gboolean active) { - static GdkColor yellow; - static GdkColor red; - static GdkColor black; - static gboolean colors_initialised = FALSE; gboolean error = FALSE; - if (!colors_initialised) { - gdk_color_parse("#f5f6be", &yellow); - gdk_color_parse("#000000", &black); - gdk_color_parse("#ff7070", &red); - colors_initialised = gdk_colormap_alloc_color( - gdk_colormap_get_system(), &yellow, FALSE, TRUE); - colors_initialised &= gdk_colormap_alloc_color( - gdk_colormap_get_system(), &black, FALSE, TRUE); - colors_initialised &= gdk_colormap_alloc_color( - gdk_colormap_get_system(), &red, FALSE, TRUE); - } - quicksearch->active = active; if (active && - (prefs_common.summary_quicksearch_type == QUICK_SEARCH_EXTENDED - && quicksearch->matcher_list == NULL)) + (prefs_common.summary_quicksearch_type == ADVANCED_SEARCH_EXTENDED + && !advsearch_has_proper_predicate(quicksearch->asearch))) error = TRUE; if (active) { gtk_widget_set_sensitive(quicksearch->clear_search, TRUE); - if (colors_initialised) { gtk_widget_modify_base( - GTK_COMBO(quicksearch->search_string_entry)->entry, - GTK_STATE_NORMAL, error ? &red : &yellow); + gtk_bin_get_child(GTK_BIN((quicksearch->search_string_entry))), + GTK_STATE_NORMAL, error ? &qs_error_bgcolor : &qs_active_bgcolor); gtk_widget_modify_text( - GTK_COMBO(quicksearch->search_string_entry)->entry, - GTK_STATE_NORMAL, &black); - } + gtk_bin_get_child(GTK_BIN((quicksearch->search_string_entry))), + GTK_STATE_NORMAL, error ? &qs_error_color : &qs_active_color); } else { gtk_widget_set_sensitive(quicksearch->clear_search, FALSE); - if (colors_initialised) { gtk_widget_modify_base( - GTK_COMBO(quicksearch->search_string_entry)->entry, + gtk_bin_get_child(GTK_BIN((quicksearch->search_string_entry))), GTK_STATE_NORMAL, NULL); gtk_widget_modify_text( - GTK_COMBO(quicksearch->search_string_entry)->entry, + gtk_bin_get_child(GTK_BIN((quicksearch->search_string_entry))), GTK_STATE_NORMAL, NULL); - } } if (!active) { - quicksearch_reset_cur_folder_item(quicksearch); + advsearch_abort(quicksearch->asearch); } } @@ -730,226 +995,6 @@ void quicksearch_set_execute_callback(QuickSearch *quicksearch, quicksearch->callback_data = data; } -gboolean quicksearch_match(QuickSearch *quicksearch, MsgInfo *msginfo) -{ - gchar *searched_header = NULL; - gboolean result = FALSE; - - if (!quicksearch->active) - return TRUE; - - switch (prefs_common.summary_quicksearch_type) { - case QUICK_SEARCH_SUBJECT: - searched_header = msginfo->subject; - break; - case QUICK_SEARCH_FROM: - searched_header = msginfo->from; - break; - case QUICK_SEARCH_TO: - searched_header = msginfo->to; - break; - case QUICK_SEARCH_EXTENDED: - break; - default: - debug_print("unknown search type (%d)\n", prefs_common.summary_quicksearch_type); - break; - } - quicksearch->matching = TRUE; - if (prefs_common.summary_quicksearch_type != QUICK_SEARCH_EXTENDED && - quicksearch->search_string && - searched_header && strcasestr(searched_header, quicksearch->search_string) != NULL) - result = TRUE; - else if ((quicksearch->matcher_list != NULL) && - matcherlist_match(quicksearch->matcher_list, msginfo)) - result = TRUE; - - quicksearch->matching = FALSE; - if (quicksearch->deferred_free) { - prepare_matcher(quicksearch); - } - - return result; -} - -/* allow Mutt-like patterns in quick search */ -gchar *expand_search_string(const gchar *search_string) -{ - int i = 0; - gchar term_char, save_char; - gchar *cmd_start, *cmd_end; - GString *matcherstr; - gchar *returnstr = NULL; - gchar *copy_str; - gboolean casesens, dontmatch; - /* list of allowed pattern abbreviations */ - struct { - gchar *abbreviated; /* abbreviation */ - gchar *command; /* actual matcher command */ - gint numparams; /* number of params for cmd */ - gboolean qualifier; /* do we append regexpcase */ - gboolean quotes; /* do we need quotes */ - } - cmds[] = { - { "a", "all", 0, FALSE, FALSE }, - { "ag", "age_greater", 1, FALSE, FALSE }, - { "al", "age_lower", 1, FALSE, FALSE }, - { "b", "body_part", 1, TRUE, TRUE }, - { "B", "message", 1, TRUE, TRUE }, - { "c", "cc", 1, TRUE, TRUE }, - { "C", "to_or_cc", 1, TRUE, TRUE }, - { "D", "deleted", 0, FALSE, FALSE }, - { "e", "header \"Sender\"", 1, TRUE, TRUE }, - { "E", "execute", 1, FALSE, TRUE }, - { "f", "from", 1, TRUE, TRUE }, - { "F", "forwarded", 0, FALSE, FALSE }, - { "h", "headers_part", 1, TRUE, TRUE }, - { "i", "header \"Message-ID\"", 1, TRUE, TRUE }, - { "I", "inreplyto", 1, TRUE, TRUE }, - { "k", "colorlabel", 1, FALSE, FALSE }, - { "L", "locked", 0, FALSE, FALSE }, - { "n", "newsgroups", 1, TRUE, TRUE }, - { "N", "new", 0, FALSE, FALSE }, - { "O", "~new", 0, FALSE, FALSE }, - { "r", "replied", 0, FALSE, FALSE }, - { "R", "~unread", 0, FALSE, FALSE }, - { "s", "subject", 1, TRUE, TRUE }, - { "se", "score_equal", 1, FALSE, FALSE }, - { "sg", "score_greater", 1, FALSE, FALSE }, - { "sl", "score_lower", 1, FALSE, FALSE }, - { "Se", "size_equal", 1, FALSE, FALSE }, - { "Sg", "size_greater", 1, FALSE, FALSE }, - { "Ss", "size_smaller", 1, FALSE, FALSE }, - { "t", "to", 1, TRUE, TRUE }, - { "T", "marked", 0, FALSE, FALSE }, - { "U", "unread", 0, FALSE, FALSE }, - { "x", "header \"References\"", 1, TRUE, TRUE }, - { "X", "test", 1, FALSE, FALSE }, - { "y", "header \"X-Label\"", 1, TRUE, TRUE }, - { "&", "&", 0, FALSE, FALSE }, - { "|", "|", 0, FALSE, FALSE }, - { "p", "partial", 0, FALSE, FALSE }, - { NULL, NULL, 0, FALSE, FALSE } - }; - - if (search_string == NULL) - return NULL; - - copy_str = g_strdup(search_string); - - matcherstr = g_string_sized_new(16); - cmd_start = copy_str; - while (cmd_start && *cmd_start) { - /* skip all white spaces */ - while (*cmd_start && isspace((guchar)*cmd_start)) - cmd_start++; - cmd_end = cmd_start; - - /* extract a command */ - while (*cmd_end && !isspace((guchar)*cmd_end)) - cmd_end++; - - /* save character */ - save_char = *cmd_end; - *cmd_end = '\0'; - - dontmatch = FALSE; - casesens = FALSE; - - /* ~ and ! mean logical NOT */ - if (*cmd_start == '~' || *cmd_start == '!') - { - dontmatch = TRUE; - cmd_start++; - } - /* % means case sensitive match */ - if (*cmd_start == '%') - { - casesens = TRUE; - cmd_start++; - } - - /* find matching abbreviation */ - for (i = 0; cmds[i].command; i++) { - if (!strcmp(cmd_start, cmds[i].abbreviated)) { - /* restore character */ - *cmd_end = save_char; - - /* copy command */ - if (matcherstr->len > 0) { - g_string_append(matcherstr, " "); - } - if (dontmatch) - g_string_append(matcherstr, "~"); - g_string_append(matcherstr, cmds[i].command); - g_string_append(matcherstr, " "); - - /* stop if no params required */ - if (cmds[i].numparams == 0) - break; - - /* extract a parameter, allow quotes */ - while (*cmd_end && isspace((guchar)*cmd_end)) - cmd_end++; - - cmd_start = cmd_end; - if (*cmd_start == '"') { - term_char = '"'; - cmd_end++; - } - else - term_char = ' '; - - /* extract actual parameter */ - while ((*cmd_end) && (*cmd_end != term_char)) - cmd_end++; - - if (*cmd_end == '"') - cmd_end++; - - save_char = *cmd_end; - *cmd_end = '\0'; - - if (cmds[i].qualifier) { - if (casesens) - g_string_append(matcherstr, "regexp "); - else - g_string_append(matcherstr, "regexpcase "); - } - - /* do we need to add quotes ? */ - if (cmds[i].quotes && term_char != '"') - g_string_append(matcherstr, "\""); - - /* copy actual parameter */ - g_string_append(matcherstr, cmd_start); - - /* do we need to add quotes ? */ - if (cmds[i].quotes && term_char != '"') - g_string_append(matcherstr, "\""); - - /* restore original character */ - *cmd_end = save_char; - - break; - } - } - - if (*cmd_end) - cmd_end++; - cmd_start = cmd_end; - } - - g_free(copy_str); - - /* return search string if no match is found to allow - all available filtering expressions in quicksearch */ - if (matcherstr->len > 0) returnstr = matcherstr->str; - else returnstr = g_strdup(search_string); - - g_string_free(matcherstr, FALSE); - return returnstr; -} - static void quicksearch_set_running(QuickSearch *quicksearch, gboolean run) { quicksearch->running = run; @@ -960,141 +1005,55 @@ gboolean quicksearch_is_running(QuickSearch *quicksearch) return quicksearch->running; } -void quicksearch_pass_key(QuickSearch *quicksearch, guint val, GdkModifierType mod) -{ - GtkEntry *entry = GTK_ENTRY(GTK_COMBO(quicksearch->search_string_entry)->entry); - glong curpos = gtk_editable_get_position(GTK_EDITABLE(entry)); - guint32 c; - char *str = g_strdup(gtk_entry_get_text(entry)); - char *begin = str; - char *end = NULL; - char *new = NULL; - char key[7] = ""; - guint char_len = 0; - - if (gtk_editable_get_selection_bounds(GTK_EDITABLE(entry), NULL, NULL)) { - /* remove selection */ - gtk_editable_delete_selection(GTK_EDITABLE(entry)); - curpos = gtk_editable_get_position(GTK_EDITABLE(entry)); - /* refresh string */ - g_free(str); - str = g_strdup(gtk_entry_get_text(entry)); - begin = str; - } - - if (!(c = gdk_keyval_to_unicode(val))) { - g_free(str); - return; - } - char_len = g_unichar_to_utf8(c, key); - if (char_len < 0) - return; - key[char_len] = '\0'; - if (curpos < g_utf8_strlen(str, -1)) { - gchar *stop = g_utf8_offset_to_pointer(begin, curpos); - end = g_strdup(g_utf8_offset_to_pointer(str, curpos)); - *stop = '\0'; - new = g_strdup_printf("%s%s%s", begin, key, end); - gtk_entry_set_text(entry, new); - g_free(end); - } else { - new = g_strdup_printf("%s%s", begin, key); - gtk_entry_set_text(entry, new); - } - g_free(str); - g_free(new); - gtk_editable_set_position(GTK_EDITABLE(entry), curpos+1); - -} - -static gboolean quicksearch_match_subfolder(QuickSearch *quicksearch, - FolderItem *src) +gboolean quicksearch_is_in_typing(QuickSearch *quicksearch) { - GSList *msglist = folder_item_get_msg_list(src); - GSList *cur; - gboolean result = FALSE; - gint num = 0, total = src->total_msgs; - gint interval = quicksearch_is_fast(quicksearch) ? 5000:100; - - statusbar_print_all(_("Searching in %s... \n"), - src->path ? src->path : "(null)"); - folder_item_update_freeze(); - for (cur = msglist; cur != NULL; cur = cur->next) { - MsgInfo *msg = (MsgInfo *)cur->data; - statusbar_progress_all(num++,total, interval); - if (quicksearch_match(quicksearch, msg)) { - procmsg_msginfo_free(msg); - result = TRUE; - break; - } - procmsg_msginfo_free(msg); - if (num % interval == 0) - GTK_EVENTS_FLUSH(); - if (!quicksearch_is_active(quicksearch)) - break; - } - folder_item_update_thaw(); - statusbar_progress_all(0,0,0); - statusbar_pop_all(); - - g_slist_free(msglist); - return result; + return quicksearch->in_typing; } -void quicksearch_search_subfolders(QuickSearch *quicksearch, - FolderView *folderview, - FolderItem *folder_item) +void quicksearch_set_search_strings(QuickSearch *quicksearch) { - FolderItem *cur = NULL; - GNode *node = folder_item->node->children; + GList *strings = prefs_common.summary_quicksearch_history; + gchar *newstr = NULL; + MatcherList *matcher_list = NULL; - if (!prefs_common.summary_quicksearch_recurse - || quicksearch->in_typing == TRUE) + if (!strings) return; - for (; node != NULL; node = node->next) { - cur = FOLDER_ITEM(node->data); - if (quicksearch_match_subfolder(quicksearch, cur)) { - folderview_update_search_icon(cur, TRUE); - } else { - folderview_update_search_icon(cur, FALSE); + matcher_parser_disable_warnings(TRUE); + + do { + newstr = advsearch_expand_search_string((gchar *) strings->data); + if (newstr && newstr[0] != '\0') { + if (!strchr(newstr, ' ')) { + quicksearch->normal_search_strings = + g_list_append( + quicksearch->normal_search_strings, + g_strdup(strings->data)); + } else { + matcher_list = matcher_parser_get_cond(newstr, FALSE); + + if (matcher_list) { + quicksearch->extended_search_strings = + g_list_prepend( + quicksearch->extended_search_strings, + g_strdup(strings->data)); + matcherlist_free(matcher_list); + } else + quicksearch->normal_search_strings = + g_list_prepend( + quicksearch->normal_search_strings, + g_strdup(strings->data)); + } } - if (cur->node->children) - quicksearch_search_subfolders(quicksearch, - folderview, - cur); - } - quicksearch->root_folder_item = folder_item; - if (!quicksearch_is_active(quicksearch)) - quicksearch_reset_cur_folder_item(quicksearch); -} + g_free(newstr); + + } while ((strings = g_list_next(strings)) != NULL); -static void quicksearch_reset_folder_items(QuickSearch *quicksearch, - FolderItem *folder_item) -{ - FolderItem *cur = NULL; - GNode *node = (folder_item && folder_item->node) ? - folder_item->node->children : NULL; - - for (; node != NULL; node = node->next) { - cur = FOLDER_ITEM(node->data); - folderview_update_search_icon(cur, FALSE); - if (cur->node->children) - quicksearch_reset_folder_items(quicksearch, - cur); - } -} + matcher_parser_disable_warnings(FALSE); -void quicksearch_reset_cur_folder_item(QuickSearch *quicksearch) -{ - if (quicksearch->root_folder_item) - quicksearch_reset_folder_items(quicksearch, - quicksearch->root_folder_item); + quicksearch->normal_search_strings = g_list_reverse(quicksearch->normal_search_strings); + quicksearch->extended_search_strings = g_list_reverse(quicksearch->extended_search_strings); - quicksearch->root_folder_item = NULL; + quicksearch_set_popdown_strings(quicksearch); } -gboolean quicksearch_is_in_typing(QuickSearch *quicksearch) -{ - return quicksearch->in_typing; -}