diff options
author | Matthew Barnes <mbarnes@redhat.com> | 2009-05-21 06:09:34 +0800 |
---|---|---|
committer | Matthew Barnes <mbarnes@redhat.com> | 2009-05-21 06:09:34 +0800 |
commit | 5d12f06367a0939387381f66cea77766a873aea6 (patch) | |
tree | 221b29a45e7e52481a4638d12cdf8e8253bb9ce1 /mail | |
parent | 23f58b3f17ce7ba08a8bd3f6066f62f0f454bacf (diff) | |
download | gsoc2013-evolution-5d12f06367a0939387381f66cea77766a873aea6.tar gsoc2013-evolution-5d12f06367a0939387381f66cea77766a873aea6.tar.gz gsoc2013-evolution-5d12f06367a0939387381f66cea77766a873aea6.tar.bz2 gsoc2013-evolution-5d12f06367a0939387381f66cea77766a873aea6.tar.lz gsoc2013-evolution-5d12f06367a0939387381f66cea77766a873aea6.tar.xz gsoc2013-evolution-5d12f06367a0939387381f66cea77766a873aea6.tar.zst gsoc2013-evolution-5d12f06367a0939387381f66cea77766a873aea6.zip |
Bug 580925 – Better search bar for word searches
Make the word search bar more like Firefox and get rid of the "Current
Message" search scope in the folder search bar. Shift+Ctrl+F now
activates the word search bar.
Diffstat (limited to 'mail')
-rw-r--r-- | mail/Makefile.am | 2 | ||||
-rw-r--r-- | mail/e-mail-search-bar.c | 774 | ||||
-rw-r--r-- | mail/e-mail-search-bar.h | 85 | ||||
-rw-r--r-- | mail/e-searching-tokenizer.c | 4 | ||||
-rw-r--r-- | mail/e-searching-tokenizer.h | 2 | ||||
-rw-r--r-- | mail/em-folder-browser.c | 75 | ||||
-rw-r--r-- | mail/em-folder-view.c | 24 | ||||
-rw-r--r-- | mail/em-folder-view.h | 3 | ||||
-rw-r--r-- | mail/em-format-html-display.c | 338 | ||||
-rw-r--r-- | mail/em-format-html-display.h | 2 | ||||
-rw-r--r-- | mail/em-format.c | 38 | ||||
-rw-r--r-- | mail/em-format.h | 10 | ||||
-rw-r--r-- | mail/em-message-browser.c | 38 | ||||
-rw-r--r-- | mail/em-utils.c | 2 |
14 files changed, 997 insertions, 400 deletions
diff --git a/mail/Makefile.am b/mail/Makefile.am index 96ed893007..793d5c3a1e 100644 --- a/mail/Makefile.am +++ b/mail/Makefile.am @@ -55,6 +55,7 @@ idl_DATA = $(MAIL_IDL) mailinclude_HEADERS = \ $(MAIL_IDL_GENERATED_H) \ e-mail-attachment-bar.h \ + e-mail-search-bar.h \ em-composer-utils.h \ em-config.h \ em-event.h \ @@ -97,6 +98,7 @@ libevolution_mail_la_SOURCES = \ e-attachment-handler-mail.c \ e-attachment-handler-mail.h \ e-mail-attachment-bar.c \ + e-mail-search-bar.c \ e-searching-tokenizer.c \ e-searching-tokenizer.h \ em-account-editor.c \ diff --git a/mail/e-mail-search-bar.c b/mail/e-mail-search-bar.c new file mode 100644 index 0000000000..4d555857ca --- /dev/null +++ b/mail/e-mail-search-bar.c @@ -0,0 +1,774 @@ +/* + * e-mail-search-bar.c + * + * This program 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 of the License, or (at your option) version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include "e-mail-search-bar.h" + +#include <glib/gi18n.h> +#include <gdk/gdkkeysyms.h> +#include <gtkhtml/gtkhtml-search.h> + +#include "e-util/e-binding.h" + +#define E_MAIL_SEARCH_BAR_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_MAIL_SEARCH_BAR, EMailSearchBarPrivate)) + +struct _EMailSearchBarPrivate { + GtkHTML *html; + GtkWidget *entry; + GtkWidget *case_sensitive_button; + GtkWidget *wrapped_next_box; + GtkWidget *wrapped_prev_box; + GtkWidget *matches_label; + + ESearchingTokenizer *tokenizer; + gchar *active_search; + + guint rerun_search : 1; +}; + +enum { + PROP_0, + PROP_CASE_SENSITIVE, + PROP_HTML, + PROP_TEXT +}; + +enum { + CHANGED, + CLEAR, + LAST_SIGNAL +}; + +static gpointer parent_class; +static guint signals[LAST_SIGNAL]; + +static void +mail_search_bar_update_matches (EMailSearchBar *search_bar) +{ + ESearchingTokenizer *tokenizer; + GtkWidget *matches_label; + gint matches; + gchar *text; + + tokenizer = e_mail_search_bar_get_tokenizer (search_bar); + matches_label = search_bar->priv->matches_label; + + matches = e_searching_tokenizer_match_count (tokenizer); + text = g_strdup_printf (_("Matches: %d"), matches); + + gtk_label_set_text (GTK_LABEL (matches_label), text); + gtk_widget_show (matches_label); + + g_free (text); +} + +static void +mail_search_bar_update_tokenizer (EMailSearchBar *search_bar) +{ + ESearchingTokenizer *tokenizer; + gboolean case_sensitive; + gchar *active_search; + + tokenizer = e_mail_search_bar_get_tokenizer (search_bar); + case_sensitive = e_mail_search_bar_get_case_sensitive (search_bar); + + if (GTK_WIDGET_VISIBLE (search_bar)) + active_search = search_bar->priv->active_search; + else + active_search = NULL; + + e_searching_tokenizer_set_primary_case_sensitivity ( + tokenizer, case_sensitive); + e_searching_tokenizer_set_primary_search_string ( + tokenizer, active_search); + + e_mail_search_bar_changed (search_bar); +} + +static void +mail_search_bar_find (EMailSearchBar *search_bar, + gboolean search_forward) +{ + GtkHTML *html; + GtkWidget *widget; + gboolean case_sensitive; + gboolean new_search; + gboolean wrapped = FALSE; + gchar *text; + + html = e_mail_search_bar_get_html (search_bar); + case_sensitive = e_mail_search_bar_get_case_sensitive (search_bar); + text = e_mail_search_bar_get_text (search_bar); + + if (text == NULL || *text == '\0') + gtk_widget_hide (search_bar->priv->matches_label); + + new_search = + (search_bar->priv->active_search == NULL) || + (g_strcmp0 (text, search_bar->priv->active_search) != 0); + + /* XXX On a new search, the HTMLEngine's search state gets + * destroyed when we redraw the message with highlighted + * matches (EMHTMLStream's write() method triggers this, + * but it's really GtkHtml's fault). That's why the first + * match isn't selected automatically. It also causes + * gtk_html_engine_search_next() to return FALSE, which we + * assume to mean the search wrapped. + * + * So to avoid mistakenly thinking the search wrapped when + * it hasn't, we have to trap the first button click after a + * search and re-run the search to recreate the HTMLEngine's + * search state, so that gtk_html_engine_search_next() will + * succeed. */ + if (new_search) { + g_free (search_bar->priv->active_search); + search_bar->priv->active_search = text; + search_bar->priv->rerun_search = TRUE; + mail_search_bar_update_tokenizer (search_bar); + } else if (search_bar->priv->rerun_search) { + gtk_html_engine_search ( + html, search_bar->priv->active_search, + case_sensitive, search_forward, FALSE); + search_bar->priv->rerun_search = FALSE; + g_free (text); + } else { + gtk_html_engine_search_set_forward (html, search_forward); + if (!gtk_html_engine_search_next (html)) + wrapped = TRUE; + g_free (text); + } + + if (new_search || wrapped) + gtk_html_engine_search ( + html, search_bar->priv->active_search, + case_sensitive, search_forward, FALSE); + + /* Update wrapped label visibility. */ + + widget = search_bar->priv->wrapped_next_box; + + if (wrapped && search_forward) + gtk_widget_show (widget); + else + gtk_widget_hide (widget); + + widget = search_bar->priv->wrapped_prev_box; + + if (wrapped && !search_forward) + gtk_widget_show (widget); + else + gtk_widget_hide (widget); +} + +static void +mail_search_bar_changed_cb (EMailSearchBar *search_bar) +{ + g_object_notify (G_OBJECT (search_bar), "text"); +} + +static void +mail_search_bar_find_next_cb (EMailSearchBar *search_bar) +{ + mail_search_bar_find (search_bar, TRUE); +} + +static void +mail_search_bar_find_previous_cb (EMailSearchBar *search_bar) +{ + mail_search_bar_find (search_bar, FALSE); +} + +static void +mail_search_bar_icon_release_cb (EMailSearchBar *search_bar, + GtkEntryIconPosition icon_pos, + GdkEvent *event) +{ + g_return_if_fail (icon_pos == GTK_ENTRY_ICON_SECONDARY); + + e_mail_search_bar_clear (search_bar); + gtk_widget_grab_focus (search_bar->priv->entry); +} + +static void +mail_search_bar_toggled_cb (EMailSearchBar *search_bar) +{ + g_free (search_bar->priv->active_search); + search_bar->priv->active_search = NULL; + + g_object_notify (G_OBJECT (search_bar), "case-sensitive"); +} + +static void +mail_search_bar_set_html (EMailSearchBar *search_bar, + GtkHTML *html) +{ + ESearchingTokenizer *tokenizer; + + g_return_if_fail (search_bar->priv->html == NULL); + + search_bar->priv->html = g_object_ref (html); + + tokenizer = e_mail_search_bar_get_tokenizer (search_bar); + gtk_html_set_tokenizer (html, HTML_TOKENIZER (tokenizer)); +} + +static void +mail_search_bar_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_CASE_SENSITIVE: + e_mail_search_bar_set_case_sensitive ( + E_MAIL_SEARCH_BAR (object), + g_value_get_boolean (value)); + return; + + case PROP_HTML: + mail_search_bar_set_html ( + E_MAIL_SEARCH_BAR (object), + g_value_get_object (value)); + return; + + case PROP_TEXT: + e_mail_search_bar_set_text ( + E_MAIL_SEARCH_BAR (object), + g_value_get_string (value)); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +mail_search_bar_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_CASE_SENSITIVE: + g_value_set_boolean ( + value, e_mail_search_bar_get_case_sensitive ( + E_MAIL_SEARCH_BAR (object))); + return; + + case PROP_HTML: + g_value_set_object ( + value, e_mail_search_bar_get_html ( + E_MAIL_SEARCH_BAR (object))); + return; + + case PROP_TEXT: + g_value_take_string ( + value, e_mail_search_bar_get_text ( + E_MAIL_SEARCH_BAR (object))); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +mail_search_bar_dispose (GObject *object) +{ + EMailSearchBarPrivate *priv; + + priv = E_MAIL_SEARCH_BAR_GET_PRIVATE (object); + + if (priv->html != NULL) { + g_object_unref (priv->html); + priv->html = NULL; + } + + if (priv->entry != NULL) { + g_object_unref (priv->entry); + priv->entry = NULL; + } + + if (priv->case_sensitive_button != NULL) { + g_object_unref (priv->case_sensitive_button); + priv->case_sensitive_button = NULL; + } + + if (priv->wrapped_next_box != NULL) { + g_object_unref (priv->wrapped_next_box); + priv->wrapped_next_box = NULL; + } + + if (priv->wrapped_prev_box != NULL) { + g_object_unref (priv->wrapped_prev_box); + priv->wrapped_prev_box = NULL; + } + + if (priv->matches_label != NULL) { + g_object_unref (priv->matches_label); + priv->matches_label = NULL; + } + + if (priv->tokenizer != NULL) { + g_object_unref (priv->tokenizer); + priv->tokenizer = NULL; + } + + /* Chain up to parent's dispose() method. */ + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +mail_search_bar_finalize (GObject *object) +{ + EMailSearchBarPrivate *priv; + + priv = E_MAIL_SEARCH_BAR_GET_PRIVATE (object); + + g_free (priv->active_search); + + /* Chain up to parent's finalize() method. */ + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +mail_search_bar_constructed (GObject *object) +{ + EMailSearchBarPrivate *priv; + + priv = E_MAIL_SEARCH_BAR_GET_PRIVATE (object); + + e_mutual_binding_new ( + G_OBJECT (object), "case-sensitive", + G_OBJECT (priv->case_sensitive_button), "active"); +} + +static void +mail_search_bar_show (GtkWidget *widget) +{ + EMailSearchBar *search_bar; + + search_bar = E_MAIL_SEARCH_BAR (widget); + + /* Chain up to parent's show() method. */ + GTK_WIDGET_CLASS (parent_class)->show (widget); + + gtk_widget_grab_focus (search_bar->priv->entry); + + mail_search_bar_update_tokenizer (search_bar); +} + +static void +mail_search_bar_hide (GtkWidget *widget) +{ + EMailSearchBar *search_bar; + + search_bar = E_MAIL_SEARCH_BAR (widget); + + /* Chain up to parent's hide() method. */ + GTK_WIDGET_CLASS (parent_class)->hide (widget); + + mail_search_bar_update_tokenizer (search_bar); +} + +static gboolean +mail_search_bar_key_press_event (GtkWidget *widget, + GdkEventKey *event) +{ + if (event->keyval == GDK_Escape) { + gtk_widget_hide (widget); + return TRUE; + } + + /* Chain up to parent's key_press_event() method. */ + return GTK_WIDGET_CLASS (parent_class)-> + key_press_event (widget, event); +} + +static void +mail_search_bar_clear (EMailSearchBar *search_bar) +{ + g_free (search_bar->priv->active_search); + search_bar->priv->active_search = NULL; + + gtk_widget_hide (search_bar->priv->wrapped_next_box); + gtk_widget_hide (search_bar->priv->wrapped_prev_box); + gtk_widget_hide (search_bar->priv->matches_label); + + mail_search_bar_update_tokenizer (search_bar); +} + +static void +mail_search_bar_class_init (EMailSearchBarClass *class) +{ + GObjectClass *object_class; + GtkWidgetClass *widget_class; + + parent_class = g_type_class_peek_parent (class); + g_type_class_add_private (class, sizeof (EMailSearchBarPrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->set_property = mail_search_bar_set_property; + object_class->get_property = mail_search_bar_get_property; + object_class->dispose = mail_search_bar_dispose; + object_class->finalize = mail_search_bar_finalize; + object_class->constructed = mail_search_bar_constructed; + + widget_class = GTK_WIDGET_CLASS (class); + widget_class->show = mail_search_bar_show; + widget_class->hide = mail_search_bar_hide; + widget_class->key_press_event = mail_search_bar_key_press_event; + + class->clear = mail_search_bar_clear; + + g_object_class_install_property ( + object_class, + PROP_CASE_SENSITIVE, + g_param_spec_boolean ( + "case-sensitive", + "Case Sensitive", + NULL, + FALSE, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + object_class, + PROP_HTML, + g_param_spec_object ( + "html", + "HTML Display", + NULL, + GTK_TYPE_HTML, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY)); + + g_object_class_install_property ( + object_class, + PROP_TEXT, + g_param_spec_string ( + "text", + "Search Text", + NULL, + NULL, + G_PARAM_READWRITE)); + + signals[CHANGED] = g_signal_new ( + "changed", + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (EMailSearchBarClass, changed), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals[CLEAR] = g_signal_new ( + "clear", + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (EMailSearchBarClass, clear), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); +} + +static void +mail_search_bar_init (EMailSearchBar *search_bar) +{ + GtkWidget *label; + GtkWidget *widget; + GtkWidget *container; + + search_bar->priv = E_MAIL_SEARCH_BAR_GET_PRIVATE (search_bar); + search_bar->priv->tokenizer = e_searching_tokenizer_new (); + + g_signal_connect_swapped ( + search_bar->priv->tokenizer, "match", + G_CALLBACK (mail_search_bar_update_matches), search_bar); + + gtk_box_set_spacing (GTK_BOX (search_bar), 12); + + container = GTK_WIDGET (search_bar); + + widget = gtk_hbox_new (FALSE, 1); + gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); + gtk_widget_show (widget); + + container = widget; + + widget = gtk_button_new (); + gtk_button_set_image ( + GTK_BUTTON (widget), gtk_image_new_from_stock ( + GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU)); + gtk_button_set_relief (GTK_BUTTON (widget), GTK_RELIEF_NONE); + gtk_widget_set_tooltip_text (widget, _("Close the find bar")); + gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); + gtk_widget_show (widget); + + g_signal_connect_swapped ( + widget, "clicked", + G_CALLBACK (gtk_widget_hide), search_bar); + + widget = gtk_label_new_with_mnemonic (_("Fin_d:")); + gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 3); + gtk_widget_show (widget); + + label = widget; + + widget = gtk_entry_new (); + gtk_entry_set_icon_from_stock ( + GTK_ENTRY (widget), GTK_ENTRY_ICON_SECONDARY, + GTK_STOCK_CLEAR); + gtk_entry_set_icon_tooltip_text ( + GTK_ENTRY (widget), GTK_ENTRY_ICON_SECONDARY, + _("Clear the search")); + gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget); + gtk_widget_set_size_request (widget, 200, -1); + gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); + search_bar->priv->entry = g_object_ref (widget); + gtk_widget_show (widget); + + g_signal_connect_swapped ( + widget, "activate", + G_CALLBACK (mail_search_bar_find_next_cb), search_bar); + + g_signal_connect_swapped ( + widget, "changed", + G_CALLBACK (mail_search_bar_changed_cb), search_bar); + + g_signal_connect_swapped ( + widget, "icon-release", + G_CALLBACK (mail_search_bar_icon_release_cb), search_bar); + + widget = gtk_button_new_with_mnemonic (_("_Previous")); + gtk_button_set_image ( + GTK_BUTTON (widget), gtk_image_new_from_stock ( + GTK_STOCK_GO_BACK, GTK_ICON_SIZE_MENU)); + gtk_button_set_relief (GTK_BUTTON (widget), GTK_RELIEF_NONE); + gtk_widget_set_tooltip_text ( + widget, _("Find the previous occurrence of the phrase")); + gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); + gtk_widget_show (widget); + + g_signal_connect_swapped ( + widget, "clicked", + G_CALLBACK (mail_search_bar_find_previous_cb), search_bar); + + widget = gtk_button_new_with_mnemonic (_("_Next")); + gtk_button_set_image ( + GTK_BUTTON (widget), gtk_image_new_from_stock ( + GTK_STOCK_GO_FORWARD, GTK_ICON_SIZE_MENU)); + gtk_button_set_relief (GTK_BUTTON (widget), GTK_RELIEF_NONE); + gtk_widget_set_tooltip_text ( + widget, _("Find the next occurrence of the phrase")); + gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); + gtk_widget_show (widget); + + g_signal_connect_swapped ( + widget, "clicked", + G_CALLBACK (mail_search_bar_find_next_cb), search_bar); + + widget = gtk_check_button_new_with_mnemonic (_("Mat_ch case")); + gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); + search_bar->priv->case_sensitive_button = g_object_ref (widget); + gtk_widget_show (widget); + + g_signal_connect_swapped ( + widget, "toggled", + G_CALLBACK (mail_search_bar_toggled_cb), search_bar); + + g_signal_connect_swapped ( + widget, "toggled", + G_CALLBACK (mail_search_bar_find_next_cb), search_bar); + + container = GTK_WIDGET (search_bar); + + widget = gtk_hbox_new (FALSE, 6); + gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0); + search_bar->priv->wrapped_next_box = g_object_ref (widget); + gtk_widget_hide (widget); + + container = widget; + + widget = gtk_image_new_from_icon_name ( + "wrapped", GTK_ICON_SIZE_MENU); + gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); + gtk_widget_show (widget); + + widget = gtk_label_new ( + _("Reached bottom of page, continued from top")); + gtk_label_set_ellipsize ( + GTK_LABEL (widget), PANGO_ELLIPSIZE_END); + gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5); + gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0); + gtk_widget_show (widget); + + container = GTK_WIDGET (search_bar); + + widget = gtk_hbox_new (FALSE, 6); + gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0); + search_bar->priv->wrapped_prev_box = g_object_ref (widget); + gtk_widget_hide (widget); + + container = widget; + + widget = gtk_image_new_from_icon_name ( + "wrapped", GTK_ICON_SIZE_MENU); + gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); + gtk_widget_show (widget); + + widget = gtk_label_new ( + _("Reached top of page, continued from bottom")); + gtk_label_set_ellipsize ( + GTK_LABEL (widget), PANGO_ELLIPSIZE_END); + gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5); + gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0); + gtk_widget_show (widget); + + container = GTK_WIDGET (search_bar); + + widget = gtk_label_new (NULL); + gtk_box_pack_end (GTK_BOX (container), widget, FALSE, FALSE, 12); + search_bar->priv->matches_label = g_object_ref (widget); + gtk_widget_show (widget); +} + +GType +e_mail_search_bar_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) { + static const GTypeInfo type_info = { + sizeof (EMailSearchBarClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) mail_search_bar_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (EMailSearchBar), + 0, /* n_preallocs */ + (GInstanceInitFunc) mail_search_bar_init, + NULL /* value_table */ + }; + + type = g_type_register_static ( + GTK_TYPE_HBOX, "EMailSearchBar", &type_info, 0); + } + + return type; +} + +GtkWidget * +e_mail_search_bar_new (GtkHTML *html) +{ + g_return_val_if_fail (GTK_IS_HTML (html), NULL); + + return g_object_new (E_TYPE_MAIL_SEARCH_BAR, "html", html, NULL); +} + +void +e_mail_search_bar_clear (EMailSearchBar *search_bar) +{ + g_return_if_fail (E_IS_MAIL_SEARCH_BAR (search_bar)); + + g_signal_emit (search_bar, signals[CLEAR], 0); +} + +void +e_mail_search_bar_changed (EMailSearchBar *search_bar) +{ + g_return_if_fail (E_IS_MAIL_SEARCH_BAR (search_bar)); + + g_signal_emit (search_bar, signals[CHANGED], 0); +} + +GtkHTML * +e_mail_search_bar_get_html (EMailSearchBar *search_bar) +{ + g_return_val_if_fail (E_IS_MAIL_SEARCH_BAR (search_bar), NULL); + + return search_bar->priv->html; +} + +ESearchingTokenizer * +e_mail_search_bar_get_tokenizer (EMailSearchBar *search_bar) +{ + g_return_val_if_fail (E_IS_MAIL_SEARCH_BAR (search_bar), NULL); + + return search_bar->priv->tokenizer; +} + +gboolean +e_mail_search_bar_get_case_sensitive (EMailSearchBar *search_bar) +{ + GtkToggleButton *button; + + g_return_val_if_fail (E_IS_MAIL_SEARCH_BAR (search_bar), FALSE); + + button = GTK_TOGGLE_BUTTON (search_bar->priv->case_sensitive_button); + + return gtk_toggle_button_get_active (button); +} + +void +e_mail_search_bar_set_case_sensitive (EMailSearchBar *search_bar, + gboolean case_sensitive) +{ + GtkToggleButton *button; + + g_return_if_fail (E_IS_MAIL_SEARCH_BAR (search_bar)); + + button = GTK_TOGGLE_BUTTON (search_bar->priv->case_sensitive_button); + + gtk_toggle_button_set_active (button, case_sensitive); + + g_object_notify (G_OBJECT (search_bar), "case-sensitive"); +} + +gchar * +e_mail_search_bar_get_text (EMailSearchBar *search_bar) +{ + GtkEntry *entry; + const gchar *text; + + g_return_val_if_fail (E_IS_MAIL_SEARCH_BAR (search_bar), NULL); + + entry = GTK_ENTRY (search_bar->priv->entry); + text = gtk_entry_get_text (entry); + + return g_strstrip (g_strdup (text)); +} + +void +e_mail_search_bar_set_text (EMailSearchBar *search_bar, + const gchar *text) +{ + GtkEntry *entry; + + g_return_if_fail (E_IS_MAIL_SEARCH_BAR (search_bar)); + + entry = GTK_ENTRY (search_bar->priv->entry); + + if (text == NULL) + text = ""; + + /* This will trigger a "notify::text" signal. */ + gtk_entry_set_text (entry, text); +} diff --git a/mail/e-mail-search-bar.h b/mail/e-mail-search-bar.h new file mode 100644 index 0000000000..7f19e176b7 --- /dev/null +++ b/mail/e-mail-search-bar.h @@ -0,0 +1,85 @@ +/* + * e-mail-search-bar.h + * + * This program 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 of the License, or (at your option) version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef E_MAIL_SEARCH_BAR_H +#define E_MAIL_SEARCH_BAR_H + +#include <gtk/gtk.h> +#include <gtkhtml/gtkhtml.h> +#include <mail/e-searching-tokenizer.h> + +/* Standard GObject macros */ +#define E_TYPE_MAIL_SEARCH_BAR \ + (e_mail_search_bar_get_type ()) +#define E_MAIL_SEARCH_BAR(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_MAIL_SEARCH_BAR, EMailSearchBar)) +#define E_MAIL_SEARCH_BAR_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_MAIL_SEARCH_BAR, EMailSearchBarClass)) +#define E_IS_MAIL_SEARCH_BAR(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_MAIL_SEARCH_BAR)) +#define E_IS_MAIL_SEARCH_BAR_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_MAIL_SEARCH_BAR)) +#define E_MAIL_SEARCH_BAR_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_MAIL_SEARCH_BAR, EMailSearchBarClass)) + +G_BEGIN_DECLS + +typedef struct _EMailSearchBar EMailSearchBar; +typedef struct _EMailSearchBarClass EMailSearchBarClass; +typedef struct _EMailSearchBarPrivate EMailSearchBarPrivate; + +struct _EMailSearchBar { + GtkHBox parent; + EMailSearchBarPrivate *priv; +}; + +struct _EMailSearchBarClass { + GtkHBoxClass parent_class; + + /* Signals */ + void (*changed) (EMailSearchBar *search_bar); + void (*clear) (EMailSearchBar *search_bar); +}; + +GType e_mail_search_bar_get_type (void); +GtkWidget * e_mail_search_bar_new (GtkHTML *html); +void e_mail_search_bar_clear (EMailSearchBar *search_bar); +void e_mail_search_bar_changed (EMailSearchBar *search_bar); +GtkHTML * e_mail_search_bar_get_html (EMailSearchBar *search_bar); +ESearchingTokenizer * + e_mail_search_bar_get_tokenizer (EMailSearchBar *search_bar); +gboolean e_mail_search_bar_get_case_sensitive + (EMailSearchBar *search_bar); +void e_mail_search_bar_set_case_sensitive + (EMailSearchBar *search_bar, + gboolean case_sensitive); +gchar * e_mail_search_bar_get_text (EMailSearchBar *search_bar); +void e_mail_search_bar_set_text (EMailSearchBar *search_bar, + const gchar *text); + +G_END_DECLS + +#endif /* E_MAIL_SEARCH_BAR_H */ diff --git a/mail/e-searching-tokenizer.c b/mail/e-searching-tokenizer.c index 9704ebb96d..3d98cdeb4f 100644 --- a/mail/e-searching-tokenizer.c +++ b/mail/e-searching-tokenizer.c @@ -1052,10 +1052,10 @@ e_searching_tokenizer_get_type (void) return type; } -HTMLTokenizer * +ESearchingTokenizer * e_searching_tokenizer_new (void) { - return (HTMLTokenizer *) g_object_new (E_TYPE_SEARCHING_TOKENIZER, NULL); + return g_object_new (E_TYPE_SEARCHING_TOKENIZER, NULL); } /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **/ diff --git a/mail/e-searching-tokenizer.h b/mail/e-searching-tokenizer.h index ecc914dab7..37a0048c0c 100644 --- a/mail/e-searching-tokenizer.h +++ b/mail/e-searching-tokenizer.h @@ -52,7 +52,7 @@ struct _ESearchingTokenizerClass { GType e_searching_tokenizer_get_type (void); -HTMLTokenizer *e_searching_tokenizer_new (void); +ESearchingTokenizer *e_searching_tokenizer_new (void); /* For now, just a simple API */ diff --git a/mail/em-folder-browser.c b/mail/em-folder-browser.c index 9a80a0c254..0aba4c1045 100644 --- a/mail/em-folder-browser.c +++ b/mail/em-folder-browser.c @@ -79,6 +79,7 @@ #include "e-util/e-error.h" #include "e-util/e-util-private.h" #include "e-util/e-util-labels.h" +#include "e-mail-search-bar.h" #include "em-utils.h" #include "em-composer-utils.h" #include "em-format-html-display.h" @@ -106,6 +107,7 @@ CamelStore *vfolder_store; /* the 1 static vfolder store */ struct _EMFolderBrowserPrivate { GtkWidget *preview; /* container for message display */ GtkWidget *scroll; + GtkWidget *search_bar; GtkWidget *subscribe_editor; @@ -239,7 +241,6 @@ static ESearchBarItem emfb_search_scope_items[] = { E_FILTERBAR_CURRENT_FOLDER, E_FILTERBAR_CURRENT_ACCOUNT, E_FILTERBAR_ALL_ACCOUNTS, - E_FILTERBAR_CURRENT_MESSAGE, { NULL, -1, 0 } }; @@ -485,6 +486,7 @@ emfb_init(GObject *o) EMFolderBrowser *emfb = (EMFolderBrowser *)o; RuleContext *search_context = mail_component_peek_search_context (mail_component_peek ()); struct _EMFolderBrowserPrivate *p; + GtkWidget *html; EMEvent *eme; EMEventTargetFolderBrowser *target; @@ -527,7 +529,6 @@ emfb_init(GObject *o) efb->account_search_cancel = NULL; e_search_bar_set_menu ((ESearchBar *)emfb->search, emfb_search_items); e_search_bar_set_scopeoption ((ESearchBar *)emfb->search, emfb_search_scope_items); - e_search_bar_scope_enable ((ESearchBar *)emfb->search, E_FILTERBAR_CURRENT_MESSAGE_ID, FALSE); emfb->priv->scope_restricted = TRUE; g_signal_connect(emfb, "realize", G_CALLBACK(emfb_realize), NULL); gtk_widget_show((GtkWidget *)emfb->search); @@ -561,14 +562,21 @@ emfb_init(GObject *o) gtk_scrolled_window_set_shadow_type((GtkScrolledWindow *)p->scroll, GTK_SHADOW_IN); gtk_widget_show(p->scroll); - p->preview = gtk_vbox_new (FALSE, 6); - gtk_container_add((GtkContainer *)p->scroll, (GtkWidget *)emfb->view.preview->formathtml.html); - gtk_widget_show((GtkWidget *)emfb->view.preview->formathtml.html); + html = GTK_WIDGET (emfb->view.preview->formathtml.html); + + p->preview = gtk_vbox_new (FALSE, 1); + p->search_bar = e_mail_search_bar_new (GTK_HTML (html)); + gtk_container_add((GtkContainer *)p->scroll, html); + gtk_widget_show(html); gtk_box_pack_start ((GtkBox *)p->preview, p->scroll, TRUE, TRUE, 0); - gtk_box_pack_start ((GtkBox *)p->preview, em_format_html_get_search_dialog (emfb->view.preview), FALSE, FALSE, 0); + gtk_box_pack_start ((GtkBox *)p->preview, p->search_bar, FALSE, FALSE, 0); gtk_paned_pack2 (GTK_PANED (emfb->vpane), p->preview, TRUE, FALSE); gtk_widget_show(p->preview); + g_signal_connect_swapped ( + p->search_bar, "changed", + G_CALLBACK (em_format_redraw), emfb->view.preview); + /** @HookPoint-EMFolderBrower: Folder Browser * @Id: emfb.created * @Class: org.gnome.evolution.mail.events:1.0 @@ -638,6 +646,14 @@ emfb_destroy(GtkObject *o) } static void +emfb_show_search_bar (EMFolderView *folder_view) +{ + EMFolderBrowser *browser = (EMFolderBrowser *) folder_view; + + gtk_widget_show (browser->priv->search_bar); +} + +static void emfb_class_init(GObjectClass *klass) { klass->finalize = emfb_finalise; @@ -666,6 +682,7 @@ emfb_class_init(GObjectClass *klass) ((GtkObjectClass *)klass)->destroy = emfb_destroy; ((EMFolderViewClass *)klass)->set_folder = emfb_set_folder; ((EMFolderViewClass *)klass)->activate = emfb_activate; + ((EMFolderViewClass *)klass)->show_search_bar = emfb_show_search_bar; } GType @@ -711,7 +728,6 @@ void em_folder_browser_show_preview(EMFolderBrowser *emfb, gboolean state) if ((emfb->view.preview_active ^ state) == 0 || emfb->view.list == NULL) { if (state && emfb->priv->scope_restricted && emfb->view.list->cursor_uid && *(emfb->view.list->cursor_uid)) { - e_search_bar_scope_enable ((ESearchBar *)emfb->search, E_FILTERBAR_CURRENT_MESSAGE_ID, TRUE); emfb->priv->scope_restricted = FALSE; } @@ -733,7 +749,6 @@ void em_folder_browser_show_preview(EMFolderBrowser *emfb, gboolean state) if (emfb->view.list->cursor_uid) { char *uid = g_alloca(strlen(emfb->view.list->cursor_uid)+1); - e_search_bar_scope_enable ((ESearchBar *)emfb->search, E_FILTERBAR_CURRENT_MESSAGE_ID, TRUE); emfb->priv->scope_restricted = FALSE; strcpy(uid, emfb->view.list->cursor_uid); em_folder_view_set_message(&emfb->view, uid, FALSE); @@ -749,7 +764,6 @@ void em_folder_browser_show_preview(EMFolderBrowser *emfb, gboolean state) emfb->view.displayed_uid = NULL; gtk_widget_hide(emfb->priv->preview); - e_search_bar_scope_enable ((ESearchBar *)emfb->search, E_FILTERBAR_CURRENT_MESSAGE_ID, FALSE); emfb->priv->scope_restricted = TRUE; /* mail_display_set_message (emfb->mail_display, NULL, NULL, NULL); @@ -841,6 +855,8 @@ static void emfb_search_config_search(EFilterBar *efb, FilterRule *rule, int id, const char *query, void *data) { EMFolderBrowser *emfb = data; + EMailSearchBar *search_bar; + ESearchingTokenizer *tokenizer; GList *partl; struct _camel_search_words *words; int i; @@ -877,15 +893,26 @@ emfb_search_config_search(EFilterBar *efb, FilterRule *rule, int id, const char partl = partl->next; } - em_format_html_display_set_search(emfb->view.preview, - EM_FORMAT_HTML_DISPLAY_SEARCH_SECONDARY|EM_FORMAT_HTML_DISPLAY_SEARCH_ICASE, - strings); - while (strings) { - GSList *n = strings->next; - g_free(strings->data); - g_slist_free_1(strings); - strings = n; + search_bar = E_MAIL_SEARCH_BAR (emfb->priv->search_bar); + + /* XXX This is a hack, but this code is on its way out anyway. + * Function is called once before the search bar is created. */ + if (!E_IS_MAIL_SEARCH_BAR (search_bar)) + return; + + tokenizer = e_mail_search_bar_get_tokenizer (search_bar); + + e_searching_tokenizer_set_secondary_case_sensitivity (tokenizer, FALSE); + e_searching_tokenizer_set_secondary_search_string (tokenizer, NULL); + + while (strings != NULL) { + e_searching_tokenizer_add_secondary_search_string ( + tokenizer, strings->data); + g_free (strings->data); + strings = g_slist_delete_link (strings, strings); } + + e_mail_search_bar_changed (search_bar); } static char * @@ -1125,18 +1152,6 @@ emfb_search_search_activated(ESearchBar *esb, EMFolderBrowser *emfb) id = e_search_bar_get_search_scope (esb); switch (id) { - case E_FILTERBAR_CURRENT_MESSAGE_ID: - word = e_search_bar_get_text (esb); - if ( word && *word ) { - gtk_widget_set_sensitive (esb->option_button, FALSE); - em_format_html_display_search_with (emfb->view.preview, word); - } else { - em_format_html_display_search_close (emfb->view.preview); - } - g_free (word); - return; - break; - case E_FILTERBAR_CURRENT_FOLDER_ID: g_object_get (esb, "query", &search_word, NULL); break; @@ -1386,10 +1401,8 @@ emfb_list_message_selected (MessageList *ml, const char *uid, EMFolderBrowser *e return; if (uid && *uid && emfb->priv->scope_restricted && emfb->view.preview_active) { - e_search_bar_scope_enable ((ESearchBar *)emfb->search, E_FILTERBAR_CURRENT_MESSAGE_ID, TRUE); emfb->priv->scope_restricted = FALSE; } else if ( !(uid && *uid) && !emfb->priv->scope_restricted) { - e_search_bar_scope_enable ((ESearchBar *)emfb->search, E_FILTERBAR_CURRENT_MESSAGE_ID, FALSE); emfb->priv->scope_restricted = TRUE; } diff --git a/mail/em-folder-view.c b/mail/em-folder-view.c index e31d8d727c..62bab8a48f 100644 --- a/mail/em-folder-view.c +++ b/mail/em-folder-view.c @@ -956,7 +956,7 @@ emfv_popup_flag_completed(EPopup *ep, EPopupItem *pitem, void *data) em_utils_flag_for_followup_completed((GtkWidget *)emfv, emfv->folder, uids); if (emfv->preview) - em_format_redraw (emfv->preview); + em_format_redraw (EM_FORMAT (emfv->preview)); } static void @@ -968,7 +968,7 @@ emfv_popup_flag_clear(EPopup *ep, EPopupItem *pitem, void *data) em_utils_flag_for_followup_clear((GtkWidget *)emfv, emfv->folder, uids); if (emfv->preview) - em_format_redraw (emfv->preview); + em_format_redraw (EM_FORMAT (emfv->preview)); } static void @@ -1808,13 +1808,7 @@ emfv_message_search(BonoboUIComponent *uic, void *data, const char *path) { EMFolderView *emfv = data; - if (!emfv->list_active) /* We are in new mail window */ - em_format_html_display_search(emfv->preview); - else { - /* We are in top level. Just grab focus to Search Bar */ - gtk_widget_grab_focus (((ESearchBar *)((EMFolderBrowser *) emfv)->search)->entry); - gtk_option_menu_set_history (GTK_OPTION_MENU (((ESearchBar *)((EMFolderBrowser *) emfv)->search)->scopeoption), 3); - } + em_folder_view_show_search_bar (emfv); } static void @@ -3271,3 +3265,15 @@ emfv_on_html_button_released_cb (GtkHTML *html, GdkEventButton *button, EMFolder return FALSE; } +void +em_folder_view_show_search_bar (EMFolderView *emfv) +{ + EMFolderViewClass *class; + + g_return_if_fail (EM_IS_FOLDER_VIEW (emfv)); + + class = EM_FOLDER_VIEW_GET_CLASS (emfv); + g_return_if_fail (class->show_search_bar != NULL); + + class->show_search_bar (emfv); +} diff --git a/mail/em-folder-view.h b/mail/em-folder-view.h index 4af4760cac..b69a4a1a05 100644 --- a/mail/em-folder-view.h +++ b/mail/em-folder-view.h @@ -124,6 +124,8 @@ struct _EMFolderViewClass { void (*set_folder)(EMFolderView *emfv, struct _CamelFolder *folder, const char *uri); void (*set_message)(EMFolderView *emfv, const char *uid, int nomarkseen); + void (*show_search_bar)(EMFolderView *emfv); + /* Signals */ void (*on_url)(EMFolderView *emfv, const char *uri, const char *nice_uri); @@ -153,6 +155,7 @@ guint32 em_folder_view_disable_mask(EMFolderView *emfv); void em_folder_view_set_statusbar(EMFolderView *emfv, gboolean statusbar); void em_folder_view_set_hide_deleted(EMFolderView *emfv, gboolean status); void em_folder_view_setup_view_instance (EMFolderView *emfv); +void em_folder_view_show_search_bar (EMFolderView *emfv); G_END_DECLS diff --git a/mail/em-format-html-display.c b/mail/em-format-html-display.c index aba9c64069..cf1626ecd0 100644 --- a/mail/em-format-html-display.c +++ b/mail/em-format-html-display.c @@ -40,7 +40,6 @@ #include <gtkhtml/gtkhtml.h> #include <gtkhtml/gtkhtml-embedded.h> -#include <gtkhtml/gtkhtml-search.h> #include <glade/glade.h> @@ -76,7 +75,6 @@ #include "e-mail-attachment-bar.h" #include "em-format-html-display.h" -#include "e-searching-tokenizer.h" #include "em-icon-stream.h" #include "em-utils.h" #include "em-popup.h" @@ -97,17 +95,6 @@ #define d(x) struct _EMFormatHTMLDisplayPrivate { - /* For the interactive search dialogue */ - /* TODO: Should this be more subtle, like the mozilla one? */ - GtkHBox *search_dialog; - GtkWidget *search_entry; - GtkWidget *search_entry_box; - GtkWidget *search_matches_label; - GtkWidget *search_case_check; - char *search_text; - int search_wrap; /* are we doing a wrap search */ - gboolean search_active; /* if the search is active */ - GtkWidget *attachment_view; /* weak reference */ }; @@ -167,7 +154,6 @@ static void efhd_format_source(EMFormat *, CamelStream *, CamelMimePart *); static void efhd_format_attachment(EMFormat *, CamelStream *, CamelMimePart *, const char *, const EMFormatHandler *); static void efhd_format_optional(EMFormat *, CamelStream *, CamelMimePart *, CamelStream *); static void efhd_format_secure(EMFormat *emf, CamelStream *stream, CamelMimePart *part, CamelCipherValidity *valid); -static void efhd_complete(EMFormat *); static void efhd_builtin_init(EMFormatHTMLDisplayClass *efhc); @@ -246,9 +232,6 @@ efhd_init(GObject *o) efhd->priv = g_malloc0(sizeof(*efhd->priv)); - efhd->search_tok = (ESearchingTokenizer *)e_searching_tokenizer_new(); - gtk_html_set_tokenizer (efh->html, (HTMLTokenizer *)efhd->search_tok); - g_signal_connect(efh->html, "realize", G_CALLBACK(efhd_gtkhtml_realise), o); g_signal_connect(efh->html, "style-set", G_CALLBACK(efhd_gtkhtml_style_set), o); /* we want to convert url's etc */ @@ -265,7 +248,6 @@ efhd_finalise(GObject *o) /* check pending stuff */ - g_free(efhd->priv->search_text); g_free(efhd->priv); ((GObjectClass *)efhd_parent)->finalize(o); @@ -291,7 +273,6 @@ efhd_class_init(GObjectClass *klass) ((EMFormatClass *)klass)->format_attachment = efhd_format_attachment; ((EMFormatClass *)klass)->format_optional = efhd_format_optional; ((EMFormatClass *)klass)->format_secure = efhd_format_secure; - ((EMFormatClass *)klass)->complete = efhd_complete; klass->finalize = efhd_finalise; @@ -401,316 +382,6 @@ void em_format_html_display_set_caret_mode(EMFormatHTMLDisplay *efhd, gboolean s } void -em_format_html_display_set_search(EMFormatHTMLDisplay *efhd, int type, GSList *strings) -{ - switch(type&3) { - case EM_FORMAT_HTML_DISPLAY_SEARCH_PRIMARY: - e_searching_tokenizer_set_primary_case_sensitivity(efhd->search_tok, (type&EM_FORMAT_HTML_DISPLAY_SEARCH_ICASE) == 0); - e_searching_tokenizer_set_primary_search_string(efhd->search_tok, NULL); - while (strings) { - e_searching_tokenizer_add_primary_search_string(efhd->search_tok, strings->data); - strings = strings->next; - } - break; - case EM_FORMAT_HTML_DISPLAY_SEARCH_SECONDARY: - default: - e_searching_tokenizer_set_secondary_case_sensitivity(efhd->search_tok, (type&EM_FORMAT_HTML_DISPLAY_SEARCH_ICASE) == 0); - e_searching_tokenizer_set_secondary_search_string(efhd->search_tok, NULL); - while (strings) { - e_searching_tokenizer_add_secondary_search_string(efhd->search_tok, strings->data); - strings = strings->next; - } - break; - } - - d(printf("redrawing with search\n")); - em_format_redraw((EMFormat *)efhd); -} - -static void -efhd_update_matches(EMFormatHTMLDisplay *efhd) -{ - struct _EMFormatHTMLDisplayPrivate *p = efhd->priv; - char *str; - /* message-search popup match count string */ - char *fmt = _("Matches: %d"); - - if (p->search_dialog) { - str = alloca(strlen(fmt)+32); - sprintf(str, fmt, e_searching_tokenizer_match_count(efhd->search_tok)); - gtk_label_set_text((GtkLabel *)p->search_matches_label, str); - } - gtk_widget_show((GtkWidget *)p->search_matches_label); - -} - -static void -efhd_update_search(EMFormatHTMLDisplay *efhd) -{ - struct _EMFormatHTMLDisplayPrivate *p = efhd->priv; - GSList *words = NULL; - int flags = 0; - - if (!gtk_toggle_button_get_active((GtkToggleButton *)p->search_case_check)) - flags = EM_FORMAT_HTML_DISPLAY_SEARCH_ICASE | EM_FORMAT_HTML_DISPLAY_SEARCH_PRIMARY; - else - flags = EM_FORMAT_HTML_DISPLAY_SEARCH_PRIMARY; - - if (p->search_text) - words = g_slist_append(words, p->search_text); - - em_format_html_display_set_search(efhd, flags, words); - g_slist_free(words); -} - -static void -efhd_search_response(GtkWidget *w, EMFormatHTMLDisplay *efhd) -{ - struct _EMFormatHTMLDisplayPrivate *p = efhd->priv; - - char *txt = g_strdup(gtk_entry_get_text((GtkEntry *)p->search_entry)); - - g_strstrip(txt); - if (p->search_text && strcmp(p->search_text, txt) == 0 && !p->search_wrap) { - gtk_html_engine_search_set_forward (((EMFormatHTML *)efhd)->html, TRUE); - if (!gtk_html_engine_search_next(((EMFormatHTML *)efhd)->html)) - p->search_wrap = TRUE; - g_free(txt); - } else { - g_free(p->search_text); - p->search_text = txt; - if (!p->search_wrap) - efhd_update_search(efhd); - p->search_wrap = FALSE; - gtk_html_engine_search(((EMFormatHTML *)efhd)->html, txt, - gtk_toggle_button_get_active((GtkToggleButton *)p->search_case_check), - TRUE, FALSE); - } -} - - -static void -efhd_search_response_back (GtkWidget *w, EMFormatHTMLDisplay *efhd) -{ - struct _EMFormatHTMLDisplayPrivate *p = efhd->priv; - - char *txt = g_strdup(gtk_entry_get_text((GtkEntry *)p->search_entry)); - - g_strstrip(txt); - if (p->search_text && strcmp(p->search_text, txt) == 0 && !p->search_wrap) { - gtk_html_engine_search_set_forward (((EMFormatHTML *)efhd)->html, FALSE); - if (!gtk_html_engine_search_next(((EMFormatHTML *)efhd)->html)) - p->search_wrap = TRUE; - g_free(txt); - } else { - g_free(p->search_text); - p->search_text = txt; - if (!p->search_wrap) - efhd_update_search(efhd); - p->search_wrap = FALSE; - gtk_html_engine_search(((EMFormatHTML *)efhd)->html, txt, - gtk_toggle_button_get_active((GtkToggleButton *)p->search_case_check), - FALSE, FALSE); - } -} - - -static void -efhd_search_destroy(GtkWidget *w, EMFormatHTMLDisplay *efhd) -{ - struct _EMFormatHTMLDisplayPrivate *p = efhd->priv; - g_free(p->search_text); - p->search_text = NULL; - gtk_widget_hide((GtkWidget *)p->search_dialog); - em_format_html_display_set_search(efhd, EM_FORMAT_HTML_DISPLAY_SEARCH_PRIMARY, NULL); - p->search_active = FALSE; -} - -static void -efhd_search_case_toggled(GtkWidget *w, EMFormatHTMLDisplay *efhd) -{ - struct _EMFormatHTMLDisplayPrivate *p = efhd->priv; - - g_free(p->search_text); - p->search_text = NULL; - efhd_search_response(w, efhd); -} - -static gboolean -efhd_key_pressed (GtkWidget *w, GdkEventKey *event, EMFormatHTMLDisplay *efhd) -{ - if (event->keyval == GDK_Escape){ - efhd_search_destroy (w, efhd); - return TRUE; - } - return FALSE; -} - -static void -clear_button_clicked_cb (GtkWidget *widget, gpointer dummy, EMFormatHTMLDisplay *efhd) -{ - struct _EMFormatHTMLDisplayPrivate *p = efhd->priv; - - gtk_entry_set_text (GTK_ENTRY (p->search_entry), ""); - - g_signal_emit_by_name (p->search_entry, "activate", efhd); -} - -/* Controlls the visibility of icon_entry's visibility */ -static void -icon_entry_changed_cb (GtkWidget *widget, GtkWidget *clear_button) -{ - const char *text = gtk_entry_get_text (GTK_ENTRY (widget)); - - if (text && *text) - gtk_widget_show (clear_button); - else - gtk_widget_hide (clear_button); -} - -GtkWidget * -em_format_html_get_search_dialog (EMFormatHTMLDisplay *efhd) -{ - struct _EMFormatHTMLDisplayPrivate *p = efhd->priv; - GtkWidget *hbox2, *button3, *button2, *label1; - GtkWidget *icon_entry, *clear_button; - - p->search_entry_box = gtk_hbox_new (FALSE, 0); - - label1 = gtk_label_new_with_mnemonic (_("Fin_d:")); - gtk_widget_show (label1); - gtk_box_pack_start ((GtkBox *)(p->search_entry_box), label1, FALSE, FALSE, 5); - - /* Icon entry */ - icon_entry = e_icon_entry_new (); - p->search_entry = e_icon_entry_get_entry (E_ICON_ENTRY (icon_entry)); - gtk_label_set_mnemonic_widget (GTK_LABEL (label1), p->search_entry); - gtk_widget_show (p->search_entry); - clear_button = e_icon_entry_create_button ("gtk-clear"); - e_icon_entry_pack_widget (E_ICON_ENTRY (icon_entry), clear_button, FALSE); - gtk_widget_show_all (icon_entry); - gtk_widget_hide (clear_button); - - g_signal_connect (G_OBJECT (clear_button), "button-press-event", (GCallback) clear_button_clicked_cb, efhd); - g_signal_connect (G_OBJECT (p->search_entry), "changed", (GCallback) icon_entry_changed_cb, clear_button); - - gtk_box_pack_start ((GtkBox *)(p->search_entry_box), icon_entry, FALSE, FALSE, 0); - /* gtk_box_pack_start ((GtkBox *)(p->search_entry_box), icon_entry, TRUE, TRUE, 0); */ - - hbox2 = gtk_hbox_new (FALSE, 0); - gtk_box_pack_start ((GtkBox *)(hbox2), p->search_entry_box, FALSE, FALSE, 5); - /* gtk_box_pack_start ((GtkBox *)(hbox2), p->search_entry_box, TRUE, TRUE, 5); */ - - button3 = gtk_button_new_with_mnemonic (_("_Previous")); - gtk_button_set_image (GTK_BUTTON (button3), GTK_WIDGET(gtk_image_new_from_stock(GTK_STOCK_GO_BACK, GTK_ICON_SIZE_BUTTON))); - gtk_widget_show (button3); - gtk_box_pack_start (GTK_BOX (hbox2), button3, FALSE, FALSE, 5); - - button2 = gtk_button_new_with_mnemonic (_("_Next")); - gtk_button_set_image (GTK_BUTTON (button2), gtk_image_new_from_stock(GTK_STOCK_GO_FORWARD, GTK_ICON_SIZE_BUTTON)); - gtk_widget_show (button2); - gtk_box_pack_start (GTK_BOX (hbox2), button2, FALSE, FALSE, 5); - - p->search_case_check = gtk_check_button_new_with_mnemonic (_("M_atch case")); - gtk_widget_show (p->search_case_check); - gtk_box_pack_start (GTK_BOX (hbox2), p->search_case_check, FALSE, FALSE, 0); - - p->search_matches_label = gtk_label_new (""); - gtk_widget_show (p->search_matches_label); - gtk_box_pack_start (GTK_BOX (hbox2), p->search_matches_label, TRUE, TRUE, 0); - p->search_dialog = GTK_HBOX (hbox2); - - p->search_wrap = FALSE; - - g_signal_connect (p->search_entry, "activate", G_CALLBACK(efhd_search_response), efhd); - g_signal_connect (p->search_entry, "key-press-event", G_CALLBACK(efhd_key_pressed), efhd); - g_signal_connect (p->search_case_check, "toggled", G_CALLBACK(efhd_search_case_toggled), efhd); - g_signal_connect (button2, "clicked", G_CALLBACK(efhd_search_response), efhd); - g_signal_connect (button3, "clicked", G_CALLBACK(efhd_search_response_back), efhd); - - p->search_active = FALSE; - - efhd_update_matches(efhd); - - return (GtkWidget *)p->search_dialog; - -} - -static void -set_focus_cb (GtkWidget *window, GtkWidget *widget, EMFormatHTMLDisplay *efhd) -{ - struct _EMFormatHTMLDisplayPrivate *p = efhd->priv; - GtkWidget *sbar = GTK_WIDGET (p->search_dialog); - - while (widget != NULL && widget != sbar) { - widget = widget->parent; - } - - if (widget != sbar) - efhd_search_destroy(widget, efhd); -} - -/** - * em_format_html_display_search: - * @efhd: - * - * Run an interactive search dialogue. - **/ -void -em_format_html_display_search(EMFormatHTMLDisplay *efhd) -{ - struct _EMFormatHTMLDisplayPrivate *p = efhd->priv; - - if (p->search_dialog){ - GtkWidget *toplevel; - - gtk_widget_show (GTK_WIDGET (p->search_dialog)); - gtk_widget_grab_focus (p->search_entry); - gtk_widget_show (p->search_entry_box); - - p->search_active = TRUE; - - toplevel = gtk_widget_get_toplevel (GTK_WIDGET (p->search_dialog)); - - g_signal_connect (toplevel, "set-focus", - G_CALLBACK (set_focus_cb), efhd); - } - -} -/** - * em_format_html_display_search_with: - * @efhd: - * - * Run an interactive search dialogue. - **/ -void -em_format_html_display_search_with (EMFormatHTMLDisplay *efhd, char *word) -{ - struct _EMFormatHTMLDisplayPrivate *p = efhd->priv; - - if (p->search_dialog){ - gtk_widget_show (GTK_WIDGET (p->search_dialog)); - p->search_active = TRUE; - - /* Set the query */ - gtk_entry_set_text (GTK_ENTRY (p->search_entry), word); - gtk_widget_hide (p->search_entry_box); - - /* Trigger the search */ - g_signal_emit_by_name (p->search_entry, "activate", efhd); - } -} - -void -em_format_html_display_search_close (EMFormatHTMLDisplay *efhd) -{ - struct _EMFormatHTMLDisplayPrivate *p = efhd->priv; - - if (p->search_dialog && p->search_active) - efhd_search_destroy(GTK_WIDGET (p->search_dialog), efhd); -} - -void em_format_html_display_cut (EMFormatHTMLDisplay *efhd) { gtk_html_cut (((EMFormatHTML *) efhd)->html); @@ -889,15 +560,6 @@ efhd_html_on_url (GtkHTML *html, const char *url, EMFormatHTMLDisplay *efhd) g_signal_emit((GObject *)efhd, efhd_signals[EFHD_ON_URL], 0, url); } -static void -efhd_complete(EMFormat *emf) -{ - EMFormatHTMLDisplay *efhd = (EMFormatHTMLDisplay *)emf; - - if (efhd->priv->search_dialog && efhd->priv->search_active) - efhd_update_matches(efhd); -} - /* ********************************************************************** */ /* TODO: move the dialogue elsehwere */ diff --git a/mail/em-format-html-display.h b/mail/em-format-html-display.h index 10a379d7f6..99234e9c1e 100644 --- a/mail/em-format-html-display.h +++ b/mail/em-format-html-display.h @@ -105,8 +105,6 @@ void em_format_html_display_search_with void em_format_html_display_search_close (EMFormatHTMLDisplay *efhd); -GtkWidget * em_format_html_get_search_dialog(EMFormatHTMLDisplay *efhd); - void em_format_html_display_cut (EMFormatHTMLDisplay *efhd); void em_format_html_display_copy (EMFormatHTMLDisplay *efhd); void em_format_html_display_paste (EMFormatHTMLDisplay *efhd); diff --git a/mail/em-format.c b/mail/em-format.c index 1d5570be96..826ef11b63 100644 --- a/mail/em-format.c +++ b/mail/em-format.c @@ -772,7 +772,43 @@ emf_busy(EMFormat *emf) * a display refresh, or it can be used to generate an identical layout, * e.g. to print what the user has shown inline. **/ -/* e_format_format_clone is a macro */ +void +em_format_format_clone (EMFormat *emf, + CamelFolder *folder, + const gchar *uid, + CamelMimeMessage *message, + EMFormat *source) +{ + EMFormatClass *class; + + g_return_if_fail (EM_IS_FORMAT (emf)); + g_return_if_fail (folder == NULL || CAMEL_IS_FOLDER (folder)); + g_return_if_fail (message == NULL || CAMEL_IS_MIME_MESSAGE (message)); + g_return_if_fail (source == NULL || EM_IS_FORMAT (source)); + + class = EM_FORMAT_GET_CLASS (emf); + g_return_if_fail (class->format_clone != NULL); + class->format_clone (emf, folder, uid, message, source); +} + +void +em_format_format (EMFormat *emf, + CamelFolder *folder, + const gchar *uid, + CamelMimeMessage *message) +{ + /* em_format_format_clone() will check the arguments. */ + em_format_format_clone (emf, folder, uid, message, NULL); +} + +void +em_format_redraw (EMFormat *emf) +{ + g_return_if_fail (EM_IS_FORMAT (emf)); + + em_format_format_clone ( + emf, emf->folder, emf->uid, emf->message, emf); +} /** * em_format_set_session: diff --git a/mail/em-format.h b/mail/em-format.h index 92c6b3dddf..f11e73937a 100644 --- a/mail/em-format.h +++ b/mail/em-format.h @@ -324,14 +324,10 @@ void em_format_push_level(EMFormat *emf); void em_format_pull_level(EMFormat *emf); /* clones inline state/view and format, or use to redraw */ -#define em_format_format_clone(emf, folder, uid, msg, src) ((EMFormatClass *)G_OBJECT_GET_CLASS(emf))->format_clone((emf), (folder), (uid), (msg), (src)) +void em_format_format_clone (EMFormat *emf, CamelFolder *folder, const gchar *uid, CamelMimeMessage *message, EMFormat *source); /* formats a new message */ -#define em_format_format(emf, folder, uid, msg) ((EMFormatClass *)G_OBJECT_GET_CLASS(emf))->format_clone((emf), (folder), (uid), (msg), NULL) -#define em_format_redraw(emf) ((EMFormatClass *)G_OBJECT_GET_CLASS(emf))->format_clone((EMFormat *)(emf), \ - ((EMFormat *)(emf))->folder, \ - ((EMFormat *)(emf))->uid, \ - ((EMFormat *)(emf))->message, \ - (EMFormat *)(emf)) +void em_format_format(EMFormat *emf, CamelFolder *folder, const gchar *uid, CamelMimeMessage *message); +void em_format_redraw(EMFormat *emf); void em_format_format_error(EMFormat *emf, CamelStream *stream, const char *fmt, ...); #define em_format_format_attachment(emf, stream, msg, type, info) ((EMFormatClass *)G_OBJECT_GET_CLASS(emf))->format_attachment((emf), (stream), (msg), (type), (info)) #define em_format_format_source(emf, stream, msg) ((EMFormatClass *)G_OBJECT_GET_CLASS(emf))->format_source((emf), (stream), (msg)) diff --git a/mail/em-message-browser.c b/mail/em-message-browser.c index 728b27ec43..973708bc2b 100644 --- a/mail/em-message-browser.c +++ b/mail/em-message-browser.c @@ -48,6 +48,7 @@ #include "e-util/e-util-private.h" +#include "e-mail-search-bar.h" #include "em-format-html-display.h" #include "em-message-browser.h" #include "em-menu.h" @@ -63,6 +64,7 @@ struct _EMMessageBrowserPrivate { GtkWidget *preview; /* container for message display */ + GtkWidget *search_bar; }; static gpointer parent_class; @@ -225,6 +227,14 @@ emmb_destroy (GtkObject *gtk_object) } static void +emmb_show_search_bar (EMFolderView *folder_view) +{ + EMMessageBrowser *browser = EM_MESSAGE_BROWSER (folder_view); + + gtk_widget_show (browser->priv->search_bar); +} + +static void emmb_class_init (EMMessageBrowserClass *class) { GtkObjectClass *gtk_object_class; @@ -240,12 +250,14 @@ emmb_class_init (EMMessageBrowserClass *class) folder_view_class->update_message_style = FALSE; folder_view_class->set_message = emmb_set_message; folder_view_class->activate = emmb_activate; + folder_view_class->show_search_bar = emmb_show_search_bar; } static void emmb_init (EMMessageBrowser *emmb) { EMFolderView *emfv = EM_FOLDER_VIEW (emmb); + GtkWidget *container; GtkWidget *widget; gchar *filename; @@ -265,25 +277,35 @@ emmb_init (EMMessageBrowser *emmb) EVOLUTION_UIDIR, "evolution-mail-message.xml", NULL); emfv->ui_files = g_slist_append (emfv->ui_files, filename); + gtk_box_set_spacing (GTK_BOX (emmb), 1); + + container = GTK_WIDGET (emmb); + widget = gtk_scrolled_window_new (NULL, NULL); gtk_scrolled_window_set_policy ( GTK_SCROLLED_WINDOW (widget), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_shadow_type ( GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN); - gtk_widget_show (widget); + gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0); emmb->priv->preview = widget; + gtk_widget_show (widget); + + widget = e_mail_search_bar_new (emfv->preview->formathtml.html); + gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); + emmb->priv->search_bar = widget; + gtk_widget_hide (widget); + + g_signal_connect_swapped ( + widget, "changed", + G_CALLBACK (em_format_redraw), emfv->preview); + + container = emmb->priv->preview; widget = GTK_WIDGET (emfv->preview->formathtml.html); - gtk_container_add (GTK_CONTAINER (emmb->priv->preview), widget); + gtk_container_add (GTK_CONTAINER (container), widget); gtk_widget_show (widget); - gtk_box_pack_start ( - GTK_BOX (emmb), emmb->priv->preview, TRUE, TRUE, 0); - gtk_box_pack_start( - GTK_BOX (emmb), em_format_html_get_search_dialog ( - emfv->preview), FALSE, FALSE, 0); - /** @HookPoint-EMMenu: Standalone Message View Menu * @Id: org.gnome.evolution.mail.messagebrowser * @Class: org.gnome.evolution.mail.bonobomenu:1.0 diff --git a/mail/em-utils.c b/mail/em-utils.c index 7685e76845..958864647d 100644 --- a/mail/em-utils.c +++ b/mail/em-utils.c @@ -804,7 +804,7 @@ tag_editor_response (GtkWidget *dialog, int button, struct ted_t *ted) camel_tag_list_free (&tags); if (ted->emfv->preview) - em_format_redraw(ted->emfv->preview); + em_format_redraw (EM_FORMAT (ted->emfv->preview)); } gtk_widget_destroy (dialog); |