From 4cbbdedf522a6ac10df93a128bbf25f67173d66e Mon Sep 17 00:00:00 2001
From: Matthew Barnes <mbarnes@redhat.com>
Date: Fri, 18 Dec 2009 18:23:48 -0500
Subject: Refactor the EShell search API.

Move the search interface to a new widget: EShellSearchbar

The current search rule is now stored in EShellView, and the search
context in EShellViewClass similar to GalViewCollection (since it's
class-specific, not instance-specific).

Also add a couple new signals to EShellView: "clear-search" and
"custom-search" ("custom" refers to an advanced search or a saved
search -- something more complex than a quick search).

Still working out a few kinks.  The search entry is clearly trying to
be too many things.  We need a different way of indicating that you're
looking at search results.  Perhaps a search results banner similar to
Nautilus.
---
 shell/e-shell-content.c | 1368 +++++------------------------------------------
 1 file changed, 144 insertions(+), 1224 deletions(-)

(limited to 'shell/e-shell-content.c')

diff --git a/shell/e-shell-content.c b/shell/e-shell-content.c
index 6a883d5230..bc24b22222 100644
--- a/shell/e-shell-content.c
+++ b/shell/e-shell-content.c
@@ -31,6 +31,7 @@
 #include "widgets/misc/e-hinted-entry.h"
 
 #include "e-shell-backend.h"
+#include "e-shell-searchbar.h"
 #include "e-shell-view.h"
 #include "e-shell-window-actions.h"
 
@@ -38,46 +39,18 @@
 	(G_TYPE_INSTANCE_GET_PRIVATE \
 	((obj), E_TYPE_SHELL_CONTENT, EShellContentPrivate))
 
-#define STATE_KEY_SEARCH_FILTER		"SearchFilter"
-#define STATE_KEY_SEARCH_SCOPE		"SearchScope"
-#define STATE_KEY_SEARCH_TEXT		"SearchText"
-
 struct _EShellContentPrivate {
 
 	gpointer shell_view;  /* weak pointer */
 
-	ERuleContext *search_context;
-	EFilterRule *search_rule;
-	gchar *system_filename;
-	gchar *user_filename;
-
-	GtkWidget *search_bar;
+	GtkWidget *searchbar;
 
-	/* Search bar children (not referenced) */
-	GtkWidget *filter_combo_box;
-	GtkWidget *search_entry;
-	GtkWidget *scope_combo_box;
-	GtkRadioAction *search_radio; /* to be able to manage radio here */
-
-	guint filter_visible : 1;
-	guint search_visible : 1;
-	guint scope_visible  : 1;
+	/* Custom search rules. */
+	gchar *user_filename;
 };
 
 enum {
 	PROP_0,
-	PROP_FILTER_ACTION,
-	PROP_FILTER_VALUE,
-	PROP_FILTER_VISIBLE,
-	PROP_SEARCH_CONTEXT,
-	PROP_SEARCH_HINT,
-	PROP_SEARCH_RULE,
-	PROP_SEARCH_TEXT,
-	PROP_SEARCH_VISIBLE,
-	PROP_SCOPE_ACTION,
-	PROP_SCOPE_VALUE,
-	PROP_SCOPE_VISIBLE,
-	PROP_SEARCH_RADIO_ACTION,
 	PROP_SHELL_VIEW
 };
 
@@ -97,269 +70,6 @@ shell_content_dialog_rule_changed (GtkWidget *dialog,
 		GTK_DIALOG (dialog), GTK_RESPONSE_APPLY, sensitive);
 }
 
-static void
-shell_content_update_search_widgets (EShellContent *shell_content)
-{
-	EShellView *shell_view;
-	EShellWindow *shell_window;
-	GtkAction *action;
-	GtkWidget *widget;
-	const gchar *search_text;
-	gboolean sensitive;
-
-	g_return_if_fail (shell_content != NULL);
-
-	shell_view = e_shell_content_get_shell_view (shell_content);
-	g_return_if_fail (shell_view != NULL);
-
-	/* EShellView subclasses are responsible for actually
-	 * executing the search.  This is all cosmetic stuff. */
-
-	widget = shell_content->priv->search_entry;
-	shell_window = e_shell_view_get_shell_window (shell_view);
-	search_text = e_shell_content_get_search_text (shell_content);
-
-	sensitive =
-		(search_text != NULL && *search_text != '\0') ||
-		(e_shell_content_get_search_rule (shell_content) != NULL);
-
-	if (sensitive) {
-		GtkStyle *style;
-		const GdkColor *fg_color, *bg_color;
-
-		style = gtk_widget_get_style (widget);
-		fg_color = &style->text[(search_text != NULL && *search_text != '\0') ? GTK_STATE_SELECTED : GTK_STATE_INSENSITIVE];
-		bg_color = &style->mid[GTK_STATE_SELECTED];
-
-		if (gdk_color_equal (fg_color, bg_color))
-			bg_color = &style->base[GTK_STATE_SELECTED];
-
-		gtk_widget_modify_base (widget, GTK_STATE_NORMAL, bg_color);
-		gtk_widget_modify_text (widget, GTK_STATE_NORMAL, fg_color);
-	} else {
-		/* Text color will be updated when we move the focus. */
-		gtk_widget_modify_base (widget, GTK_STATE_NORMAL, NULL);
-	}
-
-	action = E_SHELL_WINDOW_ACTION_SEARCH_CLEAR (shell_window);
-	gtk_action_set_sensitive (action, sensitive);
-
-	action = E_SHELL_WINDOW_ACTION_SEARCH_SAVE (shell_window);
-	gtk_action_set_sensitive (action, sensitive);
-}
-
-static void
-shell_content_execute_search_cb (EShellView *shell_view,
-                                 EShellContent *shell_content)
-{
-	GtkWidget *widget;
-
-	shell_content_update_search_widgets (shell_content);
-
-	if (!e_shell_view_is_active (shell_view))
-		return;
-
-	/* Direct the focus away from the search entry, so that a
-	 * focus-in event is required before the text can be changed.
-	 * This will reset the entry to the appropriate visual state. */
-	widget = gtk_bin_get_child (GTK_BIN (shell_content));
-	if (GTK_IS_PANED (widget))
-		widget = gtk_paned_get_child1 (GTK_PANED (widget));
-	gtk_widget_grab_focus (widget);
-}
-
-static void
-shell_content_entry_activate_cb (EShellContent *shell_content,
-                                 GtkEntry *entry)
-{
-	EShellView *shell_view;
-	EShellWindow *shell_window;
-	GtkAction *action;
-	const gchar *text;
-
-	shell_view = e_shell_content_get_shell_view (shell_content);
-	shell_window = e_shell_view_get_shell_window (shell_view);
-
-	text = gtk_entry_get_text (entry);
-	if (text && *text)
-		action = E_SHELL_WINDOW_ACTION_SEARCH_QUICK (shell_window);
-	else
-		action = E_SHELL_WINDOW_ACTION_SEARCH_CLEAR (shell_window);
-
-	gtk_action_activate (action);
-}
-
-static void
-shell_content_entry_changed_cb (EShellContent *shell_content,
-                                GtkEntry *entry)
-{
-	EShellView *shell_view;
-	EShellWindow *shell_window;
-	GtkAction *action;
-	const gchar *text;
-	gboolean sensitive;
-
-	shell_view = e_shell_content_get_shell_view (shell_content);
-	shell_window = e_shell_view_get_shell_window (shell_view);
-
-	text = gtk_entry_get_text (entry);
-	sensitive = (text != NULL && *text != '\0' && !e_hinted_entry_get_hint_shown (E_HINTED_ENTRY (entry)));
-
-	action = E_SHELL_WINDOW_ACTION_SEARCH_QUICK (shell_window);
-	gtk_action_set_sensitive (action, sensitive);
-}
-
-static void
-shell_content_entry_icon_press_cb (EShellContent *shell_content,
-                                   GtkEntryIconPosition icon_pos,
-                                   GdkEvent *event)
-{
-	EShellView *shell_view;
-	EShellWindow *shell_window;
-	GtkAction *action;
-
-	/* Show the search options menu when the icon is pressed. */
-
-	if (icon_pos != GTK_ENTRY_ICON_PRIMARY)
-		return;
-
-	shell_view = e_shell_content_get_shell_view (shell_content);
-	shell_window = e_shell_view_get_shell_window (shell_view);
-
-	action = E_SHELL_WINDOW_ACTION_SEARCH_OPTIONS (shell_window);
-	gtk_action_activate (action);
-}
-
-static void
-shell_content_entry_icon_release_cb (EShellContent *shell_content,
-                                     GtkEntryIconPosition icon_pos,
-                                     GdkEvent *event)
-{
-	EShellView *shell_view;
-	EShellWindow *shell_window;
-	GtkAction *action;
-
-	/* Clear the search when the icon is pressed and released. */
-
-	if (icon_pos != GTK_ENTRY_ICON_SECONDARY)
-		return;
-
-	shell_view = e_shell_content_get_shell_view (shell_content);
-	shell_window = e_shell_view_get_shell_window (shell_view);
-
-	action = E_SHELL_WINDOW_ACTION_SEARCH_CLEAR (shell_window);
-	gtk_action_activate (action);
-}
-
-static gboolean
-shell_content_entry_key_press_cb (EShellContent *shell_content,
-                                  GdkEventKey *key_event,
-                                  GtkWidget *entry)
-{
-	EShellView *shell_view;
-	EShellWindow *shell_window;
-	GtkAction *action;
-	guint mask;
-
-	mask = gtk_accelerator_get_default_mod_mask ();
-	if ((key_event->state & mask) != GDK_MOD1_MASK)
-		return FALSE;
-
-	if (key_event->keyval != GDK_Down)
-		return FALSE;
-
-	shell_view = e_shell_content_get_shell_view (shell_content);
-	shell_window = e_shell_view_get_shell_window (shell_view);
-
-	action = E_SHELL_WINDOW_ACTION_SEARCH_OPTIONS (shell_window);
-	gtk_action_activate (action);
-
-	return TRUE;
-}
-
-static void
-shell_content_init_search_context (EShellContent *shell_content)
-{
-	EShellContentClass *shell_content_class;
-	EShellView *shell_view;
-	EShellViewClass *shell_view_class;
-	EShellBackend *shell_backend;
-	ERuleContext *context;
-	EFilterRule *rule;
-	EFilterPart *part;
-	gchar *system_filename;
-	gchar *user_filename;
-
-	shell_view = e_shell_content_get_shell_view (shell_content);
-	shell_backend = e_shell_view_get_shell_backend (shell_view);
-	shell_view_class = E_SHELL_VIEW_GET_CLASS (shell_view);
-	g_return_if_fail (shell_view_class->search_rules != NULL);
-
-	shell_content_class = E_SHELL_CONTENT_GET_CLASS (shell_content);
-	g_return_if_fail (shell_content_class->new_search_context != NULL);
-
-	/* The basename for built-in searches is specified in the
-	 * shell view class.  All built-in search rules live in the
-	 * same directory. */
-	system_filename = g_build_filename (
-		EVOLUTION_RULEDIR, shell_view_class->search_rules, NULL);
-
-	/* The filename for custom saved searches is always of
-	 * the form "$(shell_backend_data_dir)/searches.xml". */
-	user_filename = g_build_filename (
-		e_shell_backend_get_data_dir (shell_backend),
-		"searches.xml", NULL);
-
-	context = shell_content_class->new_search_context ();
-	e_rule_context_add_part_set (
-		context, "partset", E_TYPE_FILTER_PART,
-		e_rule_context_add_part, e_rule_context_next_part);
-	e_rule_context_add_rule_set (
-		context, "ruleset", E_TYPE_FILTER_RULE,
-		e_rule_context_add_rule, e_rule_context_next_rule);
-	e_rule_context_load (context, system_filename, user_filename);
-
-	/* XXX Not sure why this is necessary. */
-	g_object_set_data_full (
-		G_OBJECT (context), "system",
-		g_strdup (system_filename), g_free);
-	g_object_set_data_full (
-		G_OBJECT (context), "user",
-		g_strdup (user_filename), g_free);
-
-	rule = e_filter_rule_new ();
-	part = e_rule_context_next_part (context, NULL);
-	if (part == NULL)
-		g_warning (
-			"Could not load %s search: no parts",
-			e_shell_view_get_name (shell_view));
-	else
-		e_filter_rule_add_part (rule, e_filter_part_clone (part));
-
-	shell_content->priv->search_context = context;
-	shell_content->priv->system_filename = system_filename;
-	shell_content->priv->user_filename = user_filename;
-}
-
-static void
-shell_content_activate_advanced_search (EShellContent *shell_content)
-{
-	GtkRadioAction *radio_action;
-	const gchar *search_text;
-
-	g_return_if_fail (shell_content != NULL);
-	g_return_if_fail (shell_content->priv->search_entry != NULL);
-
-	/* cannot mix text search with an Advanced Search, thus unsetting search text */
-	search_text = e_shell_content_get_search_text (shell_content);
-	if (search_text)
-		e_shell_content_set_search_text (shell_content, NULL);
-
-	radio_action = e_shell_content_get_search_radio_action (shell_content);
-	if (radio_action)
-		g_object_set (G_OBJECT (radio_action), "current-value", -1, NULL);
-}
-
 static void
 shell_content_set_shell_view (EShellContent *shell_content,
                               EShellView *shell_view)
@@ -380,72 +90,6 @@ shell_content_set_property (GObject *object,
                             GParamSpec *pspec)
 {
 	switch (property_id) {
-		case PROP_FILTER_ACTION:
-			e_shell_content_set_filter_action (
-				E_SHELL_CONTENT (object),
-				g_value_get_object (value));
-			return;
-
-		case PROP_FILTER_VALUE:
-			e_shell_content_set_filter_value (
-				E_SHELL_CONTENT (object),
-				g_value_get_int (value));
-			return;
-
-		case PROP_FILTER_VISIBLE:
-			e_shell_content_set_filter_visible (
-				E_SHELL_CONTENT (object),
-				g_value_get_boolean (value));
-			return;
-
-		case PROP_SEARCH_HINT:
-			e_shell_content_set_search_hint (
-				E_SHELL_CONTENT (object),
-				g_value_get_string (value));
-			return;
-
-		case PROP_SEARCH_RULE:
-			e_shell_content_set_search_rule (
-				E_SHELL_CONTENT (object),
-				g_value_get_object (value));
-			return;
-
-		case PROP_SEARCH_TEXT:
-			e_shell_content_set_search_text (
-				E_SHELL_CONTENT (object),
-				g_value_get_string (value));
-			return;
-
-		case PROP_SEARCH_VISIBLE:
-			e_shell_content_set_search_visible (
-				E_SHELL_CONTENT (object),
-				g_value_get_boolean (value));
-			return;
-
-		case PROP_SCOPE_ACTION:
-			e_shell_content_set_scope_action (
-				E_SHELL_CONTENT (object),
-				g_value_get_object (value));
-			return;
-
-		case PROP_SCOPE_VALUE:
-			e_shell_content_set_scope_value (
-				E_SHELL_CONTENT (object),
-				g_value_get_int (value));
-			return;
-
-		case PROP_SCOPE_VISIBLE:
-			e_shell_content_set_scope_visible (
-				E_SHELL_CONTENT (object),
-				g_value_get_boolean (value));
-			return;
-
-		case PROP_SEARCH_RADIO_ACTION:
-			e_shell_content_set_search_radio_action (
-				E_SHELL_CONTENT (object),
-				g_value_get_object (value));
-			return;
-
 		case PROP_SHELL_VIEW:
 			shell_content_set_shell_view (
 				E_SHELL_CONTENT (object),
@@ -463,78 +107,6 @@ shell_content_get_property (GObject *object,
                             GParamSpec *pspec)
 {
 	switch (property_id) {
-		case PROP_FILTER_ACTION:
-			g_value_set_object (
-				value, e_shell_content_get_filter_action (
-				E_SHELL_CONTENT (object)));
-			return;
-
-		case PROP_FILTER_VALUE:
-			g_value_set_int (
-				value, e_shell_content_get_filter_value (
-				E_SHELL_CONTENT (object)));
-			return;
-
-		case PROP_FILTER_VISIBLE:
-			g_value_set_boolean (
-				value, e_shell_content_get_filter_visible (
-				E_SHELL_CONTENT (object)));
-			return;
-
-		case PROP_SEARCH_CONTEXT:
-			g_value_set_object (
-				value, e_shell_content_get_search_context (
-				E_SHELL_CONTENT (object)));
-			return;
-
-		case PROP_SEARCH_HINT:
-			g_value_set_string (
-				value, e_shell_content_get_search_hint (
-				E_SHELL_CONTENT (object)));
-			return;
-
-		case PROP_SEARCH_RULE:
-			g_value_set_object (
-				value, e_shell_content_get_search_rule (
-				E_SHELL_CONTENT (object)));
-			return;
-
-		case PROP_SEARCH_TEXT:
-			g_value_set_string (
-				value, e_shell_content_get_search_text (
-				E_SHELL_CONTENT (object)));
-			return;
-
-		case PROP_SEARCH_VISIBLE:
-			g_value_set_boolean (
-				value, e_shell_content_get_search_visible (
-				E_SHELL_CONTENT (object)));
-			return;
-
-		case PROP_SCOPE_ACTION:
-			g_value_set_object (
-				value, e_shell_content_get_scope_action (
-				E_SHELL_CONTENT (object)));
-			return;
-
-		case PROP_SCOPE_VALUE:
-			g_value_set_int (
-				value, e_shell_content_get_scope_value (
-				E_SHELL_CONTENT (object)));
-			return;
-
-		case PROP_SCOPE_VISIBLE:
-			g_value_set_boolean (
-				value, e_shell_content_get_scope_visible (
-				E_SHELL_CONTENT (object)));
-			return;
-
-		case PROP_SEARCH_RADIO_ACTION:
-			g_value_set_object (
-				value, e_shell_content_get_search_radio_action (
-				E_SHELL_CONTENT (object)));
-			return;
-
 		case PROP_SHELL_VIEW:
 			g_value_set_object (
 				value, e_shell_content_get_shell_view (
@@ -558,85 +130,42 @@ shell_content_dispose (GObject *object)
 		priv->shell_view = NULL;
 	}
 
-	if (priv->search_context != NULL) {
-		g_object_unref (priv->search_context);
-		priv->search_context = NULL;
-	}
-
-	if (priv->search_radio) {
-		g_signal_handlers_disconnect_matched (
-			priv->search_radio, G_SIGNAL_MATCH_DATA,
-			0, 0, NULL, NULL, object);
-		g_object_unref (priv->search_radio);
-		priv->search_radio = NULL;
-	}
-
 	/* Chain up to parent's dispose() method. */
 	G_OBJECT_CLASS (parent_class)->dispose (object);
 }
 
-static void
-shell_content_finalize (GObject *object)
-{
-	EShellContentPrivate *priv;
-
-	priv = E_SHELL_CONTENT_GET_PRIVATE (object);
-
-	g_free (priv->system_filename);
-	g_free (priv->user_filename);
-
-	/* Chain up to parent's finalize() method. */
-	G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
 static void
 shell_content_constructed (GObject *object)
 {
-	EShellView *shell_view;
-	EShellWindow *shell_window;
+	EShellContentClass *class;
 	EShellContent *shell_content;
-	GtkSizeGroup *size_group;
-	GtkAction *action;
+	EShellBackend *shell_backend;
+	EShellView *shell_view;
 	GtkWidget *widget;
+	const gchar *data_dir;
 
 	shell_content = E_SHELL_CONTENT (object);
 	shell_view = e_shell_content_get_shell_view (shell_content);
-	shell_window = e_shell_view_get_shell_window (shell_view);
-	size_group = e_shell_view_get_size_group (shell_view);
-
-	g_signal_connect_after (
-		shell_view, "execute-search",
-		G_CALLBACK (shell_content_execute_search_cb),
-		shell_content);
-
-	widget = shell_content->priv->search_entry;
-
-	action = E_SHELL_WINDOW_ACTION_SEARCH_CLEAR (shell_window);
-	e_binding_new (
-		action, "sensitive",
-		widget, "secondary-icon-sensitive");
-	e_binding_new (
-		action, "stock-id",
-		widget, "secondary-icon-stock");
-	e_binding_new (
-		action, "tooltip",
-		widget, "secondary-icon-tooltip-text");
-
-	action = E_SHELL_WINDOW_ACTION_SEARCH_OPTIONS (shell_window);
-	e_binding_new (
-		action, "sensitive",
-		widget, "primary-icon-sensitive");
-	e_binding_new (
-		action, "stock-id",
-		widget, "primary-icon-stock");
-	e_binding_new (
-		action, "tooltip",
-		widget, "primary-icon-tooltip-text");
-
-	widget = shell_content->priv->search_bar;
-	gtk_size_group_add_widget (size_group, widget);
-
-	shell_content_init_search_context (shell_content);
+	shell_backend = e_shell_view_get_shell_backend (shell_view);
+
+	/* XXX Regenerate the filename for custom saved search as done
+	 *     in shell_view_init_search_context().  ERuleContext ought
+	 *     to remember the filename when loading rules so you don't
+	 *     have to keep passing it in when saving rules. */
+	data_dir = e_shell_backend_get_data_dir (shell_backend);
+	shell_content->priv->user_filename =
+		g_build_filename (data_dir, "searches.xml", NULL);
+
+	class = E_SHELL_CONTENT_GET_CLASS (shell_content);
+	if (class->construct_searchbar != NULL)
+		widget = class->construct_searchbar (shell_content);
+	else
+		widget = NULL;
+	if (widget != NULL) {
+		gtk_widget_set_parent (widget, GTK_WIDGET (shell_content));
+		shell_content->priv->searchbar = g_object_ref (widget);
+		gtk_widget_show (widget);
+	}
 }
 
 static void
@@ -649,11 +178,11 @@ shell_content_destroy (GtkObject *gtk_object)
 	/* Unparent the widget before destroying it to avoid
 	 * writing a custom GtkContainer::remove() method. */
 
-	if (priv->search_bar != NULL) {
-		gtk_widget_unparent (priv->search_bar);
-		gtk_widget_destroy (priv->search_bar);
-		g_object_unref (priv->search_bar);
-		priv->search_bar = NULL;
+	if (priv->searchbar != NULL) {
+		gtk_widget_unparent (priv->searchbar);
+		gtk_widget_destroy (priv->searchbar);
+		g_object_unref (priv->searchbar);
+		priv->searchbar = NULL;
 	}
 
 	/* Chain up to parent's destroy() method. */
@@ -676,8 +205,10 @@ shell_content_size_request (GtkWidget *widget,
 	child = gtk_bin_get_child (GTK_BIN (widget));
 	gtk_widget_size_request (child, requisition);
 
-	child = priv->search_bar;
-	gtk_widget_size_request (child, &child_requisition);
+	if (priv->searchbar == NULL)
+		return;
+
+	gtk_widget_size_request (priv->searchbar, &child_requisition);
 	requisition->width = MAX (requisition->width, child_requisition.width);
 	requisition->height += child_requisition.height;
 }
@@ -695,15 +226,20 @@ shell_content_size_allocate (GtkWidget *widget,
 
 	widget->allocation = *allocation;
 
-	child = priv->search_bar;
-	gtk_widget_size_request (child, &child_requisition);
+	child = priv->searchbar;
+
+	if (child == NULL)
+		child_requisition.height = 0;
+	else
+		gtk_widget_size_request (child, &child_requisition);
 
 	child_allocation.x = allocation->x;
 	child_allocation.y = allocation->y;
 	child_allocation.width = allocation->width;
 	child_allocation.height = child_requisition.height;
 
-	gtk_widget_size_allocate (child, &child_allocation);
+	if (child != NULL)
+		gtk_widget_size_allocate (child, &child_allocation);
 
 	child_allocation.y += child_requisition.height;
 	child_allocation.height =
@@ -724,14 +260,46 @@ shell_content_forall (GtkContainer *container,
 
 	priv = E_SHELL_CONTENT_GET_PRIVATE (container);
 
-	if (include_internals)
-		callback (priv->search_bar, callback_data);
+	if (include_internals && priv->searchbar != NULL)
+		callback (priv->searchbar, callback_data);
 
 	/* Chain up to parent's forall() method. */
 	GTK_CONTAINER_CLASS (parent_class)->forall (
 		container, include_internals, callback, callback_data);
 }
 
+static gchar *
+shell_content_get_search_name (EShellContent *shell_content)
+{
+	EShellSearchbar *searchbar;
+	EShellView *shell_view;
+	EFilterRule *rule;
+	const gchar *search_text;
+
+	shell_view = e_shell_content_get_shell_view (shell_content);
+
+	rule = e_shell_view_get_search_rule (shell_view);
+	g_return_val_if_fail (E_IS_FILTER_RULE (rule), NULL);
+
+	searchbar = E_SHELL_SEARCHBAR (shell_content->priv->searchbar);
+	search_text = e_shell_searchbar_get_search_text (searchbar);
+
+	if (search_text == NULL || *search_text == '\0')
+		search_text = "''";
+
+	return g_strdup_printf ("%s %s", rule->name, search_text);
+}
+
+static GtkWidget *
+shell_content_construct_searchbar (EShellContent *shell_content)
+{
+	EShellView *shell_view;
+
+	shell_view = e_shell_content_get_shell_view (shell_content);
+
+	return e_shell_searchbar_new (shell_view);
+}
+
 static void
 shell_content_class_init (EShellContentClass *class)
 {
@@ -747,7 +315,6 @@ shell_content_class_init (EShellContentClass *class)
 	object_class->set_property = shell_content_set_property;
 	object_class->get_property = shell_content_get_property;
 	object_class->dispose = shell_content_dispose;
-	object_class->finalize = shell_content_finalize;
 	object_class->constructed = shell_content_constructed;
 
 	gtk_object_class = GTK_OBJECT_CLASS (class);
@@ -760,277 +327,32 @@ shell_content_class_init (EShellContentClass *class)
 	container_class = GTK_CONTAINER_CLASS (class);
 	container_class->forall = shell_content_forall;
 
-	class->new_search_context = e_rule_context_new;
-
-	g_object_class_install_property (
-		object_class,
-		PROP_FILTER_ACTION,
-		g_param_spec_object (
-			"filter-action",
-			NULL,
-			NULL,
-			GTK_TYPE_RADIO_ACTION,
-			G_PARAM_READWRITE));
-
-	g_object_class_install_property (
-		object_class,
-		PROP_FILTER_VALUE,
-		g_param_spec_int (
-			"filter-value",
-			NULL,
-			NULL,
-			G_MININT,
-			G_MAXINT,
-			0,
-			G_PARAM_READWRITE));
-
-	g_object_class_install_property (
-		object_class,
-		PROP_FILTER_VISIBLE,
-		g_param_spec_boolean (
-			"filter-visible",
-			NULL,
-			NULL,
-			TRUE,
-			G_PARAM_READWRITE |
-			G_PARAM_CONSTRUCT));
-
-	g_object_class_install_property (
-		object_class,
-		PROP_SEARCH_CONTEXT,
-		g_param_spec_object (
-			"search-context",
-			NULL,
-			NULL,
-			E_TYPE_RULE_CONTEXT,
-			G_PARAM_READABLE));
-
-	g_object_class_install_property (
-		object_class,
-		PROP_SEARCH_HINT,
-		g_param_spec_string (
-			"search-hint",
-			NULL,
-			NULL,
-			NULL,
-			G_PARAM_READWRITE));
-
-	g_object_class_install_property (
-		object_class,
-		PROP_SEARCH_RULE,
-		g_param_spec_object (
-			"search-rule",
-			NULL,
-			NULL,
-			E_TYPE_FILTER_RULE,
-			G_PARAM_READWRITE));
-
-	g_object_class_install_property (
-		object_class,
-		PROP_SEARCH_TEXT,
-		g_param_spec_string (
-			"search-text",
-			NULL,
-			NULL,
-			NULL,
-			G_PARAM_READWRITE));
-
-	g_object_class_install_property (
-		object_class,
-		PROP_SEARCH_VISIBLE,
-		g_param_spec_boolean (
-			"search-visible",
-			NULL,
-			NULL,
-			TRUE,
-			G_PARAM_READWRITE |
-			G_PARAM_CONSTRUCT));
-
-	g_object_class_install_property (
-		object_class,
-		PROP_SCOPE_ACTION,
-		g_param_spec_object (
-			"scope-action",
-			NULL,
-			NULL,
-			GTK_TYPE_RADIO_ACTION,
-			G_PARAM_READWRITE));
-
-	g_object_class_install_property (
-		object_class,
-		PROP_SCOPE_VALUE,
-		g_param_spec_int (
-			"scope-value",
-			NULL,
-			NULL,
-			G_MININT,
-			G_MAXINT,
-			0,
-			G_PARAM_READWRITE));
-
-	g_object_class_install_property (
-		object_class,
-		PROP_SCOPE_VISIBLE,
-		g_param_spec_boolean (
-			"scope-visible",
-			NULL,
-			NULL,
-			FALSE,
-			G_PARAM_READWRITE |
-			G_PARAM_CONSTRUCT));
-
-	g_object_class_install_property (
-		object_class,
-		PROP_SEARCH_RADIO_ACTION,
-		g_param_spec_object (
-			"search-radio-action",
-			NULL,
-			NULL,
-			GTK_TYPE_RADIO_ACTION,
-			G_PARAM_READWRITE));
+	class->get_search_name = shell_content_get_search_name;
+	class->construct_searchbar = shell_content_construct_searchbar;
 
 	/**
 	 * EShellContent:shell-view
 	 *
 	 * The #EShellView to which the content widget belongs.
-	 **/
-	g_object_class_install_property (
-		object_class,
-		PROP_SHELL_VIEW,
-		g_param_spec_object (
-			"shell-view",
-			NULL,
-			NULL,
-			E_TYPE_SHELL_VIEW,
-			G_PARAM_READWRITE |
-			G_PARAM_CONSTRUCT_ONLY));
-}
-
-static void
-shell_content_init (EShellContent *shell_content)
-{
-	GtkBox *box;
-	GtkLabel *label;
-	GtkWidget *widget;
-
-	shell_content->priv = E_SHELL_CONTENT_GET_PRIVATE (shell_content);
-
-	GTK_WIDGET_SET_FLAGS (shell_content, GTK_NO_WINDOW);
-
-	/*** Build the Search Bar ***/
-
-	widget = gtk_hbox_new (FALSE, 24);
-	gtk_widget_set_parent (widget, GTK_WIDGET (shell_content));
-	shell_content->priv->search_bar = g_object_ref (widget);
-	gtk_widget_show (widget);
-
-	/* Filter Combo Widgets */
-
-	box = GTK_BOX (shell_content->priv->search_bar);
-
-	widget = gtk_hbox_new (FALSE, 3);
-	gtk_box_pack_start (box, widget, FALSE, FALSE, 0);
-
-	e_binding_new (
-		shell_content, "filter-visible",
-		widget, "visible");
-
-	box = GTK_BOX (widget);
-
-	/* Translators: The "Show:" label precedes a combo box that
-	 * allows the user to filter the current view.  Examples of
-	 * items that appear in the combo box are "Unread Messages",
-	 * "Important Messages", or "Active Appointments". */
-	widget = gtk_label_new_with_mnemonic (_("Sho_w:"));
-	gtk_box_pack_start (box, widget, FALSE, FALSE, 0);
-	gtk_widget_show (widget);
-
-	label = GTK_LABEL (widget);
-
-	widget = e_action_combo_box_new ();
-	gtk_label_set_mnemonic_widget (label, widget);
-	gtk_box_pack_start (box, widget, FALSE, FALSE, 0);
-	shell_content->priv->filter_combo_box = widget;
-	gtk_widget_show (widget);
-
-	/* Search Entry Widgets */
-
-	box = GTK_BOX (shell_content->priv->search_bar);
-
-	widget = gtk_hbox_new (FALSE, 3);
-	gtk_box_pack_start (box, widget, TRUE, TRUE, 0);
-
-	e_binding_new (
-		shell_content, "search-visible",
-		widget, "visible");
-
-	box = GTK_BOX (widget);
-
-	/* Translators: This is part of the quick search interface.
-	 * example: Search: [_______________] in [ Current Folder ] */
-	widget = gtk_label_new_with_mnemonic (_("Sear_ch:"));
-	gtk_box_pack_start (box, widget, FALSE, FALSE, 0);
-	gtk_widget_show (widget);
-
-	label = GTK_LABEL (widget);
-
-	widget = e_hinted_entry_new ();
-	gtk_label_set_mnemonic_widget (label, widget);
-	gtk_box_pack_start (box, widget, TRUE, TRUE, 0);
-	shell_content->priv->search_entry = widget;
-	gtk_widget_show (widget);
-
-	g_signal_connect_swapped (
-		widget, "activate",
-		G_CALLBACK (shell_content_entry_activate_cb),
-		shell_content);
-
-	g_signal_connect_swapped (
-		widget, "changed",
-		G_CALLBACK (shell_content_entry_changed_cb),
-		shell_content);
-
-	g_signal_connect_swapped (
-		widget, "icon-press",
-		G_CALLBACK (shell_content_entry_icon_press_cb),
-		shell_content);
-
-	g_signal_connect_swapped (
-		widget, "icon-release",
-		G_CALLBACK (shell_content_entry_icon_release_cb),
-		shell_content);
-
-	g_signal_connect_swapped (
-		widget, "key-press-event",
-		G_CALLBACK (shell_content_entry_key_press_cb),
-		shell_content);
-
-	/* Scope Combo Widgets */
-
-	box = GTK_BOX (shell_content->priv->search_bar);
-
-	widget = gtk_hbox_new (FALSE, 3);
-	gtk_box_pack_start (box, widget, FALSE, FALSE, 0);
-
-	e_binding_new (
-		shell_content, "scope-visible",
-		widget, "visible");
-
-	box = GTK_BOX (widget);
-
-	/* Translators: This is part of the quick search interface.
-	 * example: Search: [_______________] in [ Current Folder ] */
-	widget = gtk_label_new_with_mnemonic (_("i_n"));
-	gtk_box_pack_start (box, widget, FALSE, FALSE, 0);
-	gtk_widget_show (widget);
+	 **/
+	g_object_class_install_property (
+		object_class,
+		PROP_SHELL_VIEW,
+		g_param_spec_object (
+			"shell-view",
+			NULL,
+			NULL,
+			E_TYPE_SHELL_VIEW,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT_ONLY));
+}
 
-	label = GTK_LABEL (widget);
+static void
+shell_content_init (EShellContent *shell_content)
+{
+	shell_content->priv = E_SHELL_CONTENT_GET_PRIVATE (shell_content);
 
-	widget = e_action_combo_box_new ();
-	gtk_label_set_mnemonic_widget (label, widget);
-	gtk_box_pack_start (box, widget, FALSE, FALSE, 0);
-	shell_content->priv->scope_combo_box = widget;
-	gtk_widget_show (widget);
+	GTK_WIDGET_SET_FLAGS (shell_content, GTK_NO_WINDOW);
 }
 
 GType
@@ -1076,6 +398,24 @@ e_shell_content_new (EShellView *shell_view)
 		E_TYPE_SHELL_CONTENT, "shell-view", shell_view, NULL);
 }
 
+/**
+ * e_shell_content_get_searchbar:
+ * @shell_view: an #EShellView
+ *
+ * Returns the search bar widget returned by the
+ * <structfield>construct_searchbar</structfield> method in
+ * #EShellContentClass.
+ *
+ * Returns: the search bar widget
+ **/
+GtkWidget *
+e_shell_content_get_searchbar (EShellContent *shell_content)
+{
+	g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), NULL);
+
+	return shell_content->priv->searchbar;
+}
+
 /**
  * e_shell_content_check_state:
  * @shell_content: an #EShellContent
@@ -1118,371 +458,27 @@ e_shell_content_get_shell_view (EShellContent *shell_content)
 	return E_SHELL_VIEW (shell_content->priv->shell_view);
 }
 
-GtkRadioAction *
-e_shell_content_get_filter_action (EShellContent *shell_content)
-{
-	EActionComboBox *combo_box;
-
-	g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), NULL);
-
-	combo_box = E_ACTION_COMBO_BOX (shell_content->priv->filter_combo_box);
-
-	return e_action_combo_box_get_action (combo_box);
-}
-
-void
-e_shell_content_set_filter_action (EShellContent *shell_content,
-                                   GtkRadioAction *filter_action)
-{
-	EActionComboBox *combo_box;
-
-	g_return_if_fail (E_IS_SHELL_CONTENT (shell_content));
-
-	combo_box = E_ACTION_COMBO_BOX (shell_content->priv->filter_combo_box);
-
-	e_action_combo_box_set_action (combo_box, filter_action);
-
-	g_object_notify (G_OBJECT (shell_content), "filter-action");
-}
-
-gint
-e_shell_content_get_filter_value (EShellContent *shell_content)
-{
-	EActionComboBox *combo_box;
-
-	g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), 0);
-
-	combo_box = E_ACTION_COMBO_BOX (shell_content->priv->filter_combo_box);
-
-	return e_action_combo_box_get_current_value (combo_box);
-}
-
-void
-e_shell_content_set_filter_value (EShellContent *shell_content,
-                                  gint filter_value)
-{
-	EActionComboBox *combo_box;
-
-	g_return_if_fail (E_IS_SHELL_CONTENT (shell_content));
-
-	combo_box = E_ACTION_COMBO_BOX (shell_content->priv->filter_combo_box);
-
-	e_action_combo_box_set_current_value (combo_box, filter_value);
-
-	g_object_notify (G_OBJECT (shell_content), "filter-value");
-}
-
-gboolean
-e_shell_content_get_filter_visible (EShellContent *shell_content)
-{
-	g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), FALSE);
-
-	return shell_content->priv->filter_visible;
-}
-
-void
-e_shell_content_set_filter_visible (EShellContent *shell_content,
-                                    gboolean filter_visible)
-{
-	g_return_if_fail (E_IS_SHELL_CONTENT (shell_content));
-
-	shell_content->priv->filter_visible = filter_visible;
-
-	g_object_notify (G_OBJECT (shell_content), "filter-visible");
-}
-
-void
-e_shell_content_add_filter_separator_before (EShellContent *shell_content,
-                                             gint action_value)
-{
-	EActionComboBox *combo_box;
-
-	g_return_if_fail (E_IS_SHELL_CONTENT (shell_content));
-
-	combo_box = E_ACTION_COMBO_BOX (shell_content->priv->filter_combo_box);
-
-	e_action_combo_box_add_separator_before (combo_box, action_value);
-}
-
-void
-e_shell_content_add_filter_separator_after (EShellContent *shell_content,
-                                            gint action_value)
-{
-	EActionComboBox *combo_box;
-
-	g_return_if_fail (E_IS_SHELL_CONTENT (shell_content));
-
-	combo_box = E_ACTION_COMBO_BOX (shell_content->priv->filter_combo_box);
-
-	e_action_combo_box_add_separator_after (combo_box, action_value);
-}
-
-ERuleContext *
-e_shell_content_get_search_context (EShellContent *shell_content)
-{
-	g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), NULL);
-
-	return shell_content->priv->search_context;
-}
-
-const gchar *
-e_shell_content_get_search_hint (EShellContent *shell_content)
-{
-	EHintedEntry *entry;
-
-	g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), NULL);
-
-	entry = E_HINTED_ENTRY (shell_content->priv->search_entry);
-
-	return e_hinted_entry_get_hint (entry);
-}
-
-void
-e_shell_content_set_search_hint (EShellContent *shell_content,
-                                 const gchar *search_hint)
-{
-	EHintedEntry *entry;
-
-	g_return_if_fail (E_IS_SHELL_CONTENT (shell_content));
-
-	entry = E_HINTED_ENTRY (shell_content->priv->search_entry);
-
-	e_hinted_entry_set_hint (entry, search_hint);
-
-	g_object_notify (G_OBJECT (shell_content), "search-hint");
-}
-
-EFilterRule *
-e_shell_content_get_search_rule (EShellContent *shell_content)
-{
-	g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), NULL);
-
-	return shell_content->priv->search_rule;
-}
-
-void
-e_shell_content_set_search_rule (EShellContent *shell_content,
-                                 EFilterRule *search_rule)
-{
-	g_return_if_fail (E_IS_SHELL_CONTENT (shell_content));
-
-	if (search_rule != NULL) {
-		g_return_if_fail (E_IS_FILTER_RULE (search_rule));
-		g_object_ref (search_rule);
-	}
-
-	if (shell_content->priv->search_rule != NULL)
-		g_object_unref (shell_content->priv->search_rule);
-
-	shell_content->priv->search_rule = search_rule;
-
-	shell_content_update_search_widgets (shell_content);
-	g_object_notify (G_OBJECT (shell_content), "search-rule");
-}
-
-/* free returned string with g_free */
+/**
+ * e_shell_content_get_search_name:
+ * @shell_content: an #EShellContent
+ *
+ * Returns a newly-allocated string containing a suitable name for the
+ * current search criteria.  This is used as the suggested name in the
+ * Save Search dialog.  Free the returned string with g_free().
+ *
+ * Returns: a name for the current search criteria
+ **/
 gchar *
-e_shell_content_get_search_rule_as_string (EShellContent *shell_content)
+e_shell_content_get_search_name (EShellContent *shell_content)
 {
-	EFilterRule *rule;
-	GString *str;
-
-	g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), NULL);
-
-	rule = e_shell_content_get_search_rule (shell_content);
-
-	if (!rule)
-		return NULL;
-
-	str = g_string_new ("");
-	e_filter_rule_build_code (rule, str);
-
-	return g_string_free (str, FALSE);
-}
-
-const gchar *
-e_shell_content_get_search_text (EShellContent *shell_content)
-{
-	EHintedEntry *entry;
-
-	g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), NULL);
-
-	entry = E_HINTED_ENTRY (shell_content->priv->search_entry);
-
-	return e_hinted_entry_get_text (entry);
-}
-
-void
-e_shell_content_set_search_text (EShellContent *shell_content,
-                                 const gchar *search_text)
-{
-	EHintedEntry *entry;
-
-	g_return_if_fail (E_IS_SHELL_CONTENT (shell_content));
-
-	entry = E_HINTED_ENTRY (shell_content->priv->search_entry);
-
-	e_hinted_entry_set_text (entry, search_text);
-
-	shell_content_update_search_widgets (shell_content);
-	g_object_notify (G_OBJECT (shell_content), "search-text");
-}
-
-gboolean
-e_shell_content_get_search_visible (EShellContent *shell_content)
-{
-	g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), FALSE);
-
-	return shell_content->priv->search_visible;
-}
-
-void
-e_shell_content_set_search_visible (EShellContent *shell_content,
-                                    gboolean search_visible)
-{
-	g_return_if_fail (E_IS_SHELL_CONTENT (shell_content));
-
-	shell_content->priv->search_visible = search_visible;
-
-	g_object_notify (G_OBJECT (shell_content), "search-visible");
-}
-
-GtkRadioAction *
-e_shell_content_get_scope_action (EShellContent *shell_content)
-{
-	EActionComboBox *combo_box;
+	EShellContentClass *class;
 
 	g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), NULL);
 
-	combo_box = E_ACTION_COMBO_BOX (shell_content->priv->scope_combo_box);
-
-	return e_action_combo_box_get_action (combo_box);
-}
-
-void
-e_shell_content_set_scope_action (EShellContent *shell_content,
-                                  GtkRadioAction *scope_action)
-{
-	EActionComboBox *combo_box;
-
-	g_return_if_fail (E_IS_SHELL_CONTENT (shell_content));
-
-	combo_box = E_ACTION_COMBO_BOX (shell_content->priv->scope_combo_box);
-
-	e_action_combo_box_set_action (combo_box, scope_action);
-
-	g_object_notify (G_OBJECT (shell_content), "scope-action");
-}
-
-gint
-e_shell_content_get_scope_value (EShellContent *shell_content)
-{
-	EActionComboBox *combo_box;
-
-	g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), 0);
-
-	combo_box = E_ACTION_COMBO_BOX (shell_content->priv->scope_combo_box);
-
-	return e_action_combo_box_get_current_value (combo_box);
-}
-
-void
-e_shell_content_set_scope_value (EShellContent *shell_content,
-                                 gint scope_value)
-{
-	EActionComboBox *combo_box;
-
-	g_return_if_fail (E_IS_SHELL_CONTENT (shell_content));
-
-	combo_box = E_ACTION_COMBO_BOX (shell_content->priv->scope_combo_box);
-
-	e_action_combo_box_set_current_value (combo_box, scope_value);
-
-	g_object_notify (G_OBJECT (shell_content), "scope-value");
-}
-
-gboolean
-e_shell_content_get_scope_visible (EShellContent *shell_content)
-{
-	g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), FALSE);
-
-	return shell_content->priv->scope_visible;
-}
-
-void
-e_shell_content_set_scope_visible (EShellContent *shell_content,
-                                   gboolean scope_visible)
-{
-	g_return_if_fail (E_IS_SHELL_CONTENT (shell_content));
-
-	shell_content->priv->scope_visible = scope_visible;
-
-	g_object_notify (G_OBJECT (shell_content), "scope-visible");
-}
-
-static void
-search_radio_changed_cb (GtkRadioAction *action,
-                         GtkRadioAction *current,
-                         EShellContent *shell_content)
-{
-	EShellView *shell_view;
-	const gchar *search_text;
-	const gchar *label;
-	gint current_value;
-
-	shell_view = e_shell_content_get_shell_view (shell_content);
-
-	label = gtk_action_get_label (GTK_ACTION (current));
-	e_shell_content_set_search_hint (shell_content, label);
-
-	current_value = gtk_radio_action_get_current_value (current);
-	search_text = e_shell_content_get_search_text (shell_content);
-
-	if (current_value != -1) {
-		e_shell_content_set_search_rule (shell_content, NULL);
-		e_shell_content_set_search_text (shell_content, search_text);
-		if (search_text != NULL && *search_text != '\0')
-			e_shell_view_execute_search (shell_view);
-	} else if (search_text != NULL) {
-		e_shell_content_set_search_text (shell_content, NULL);
-	}
-}
-
-void
-e_shell_content_set_search_radio_action (EShellContent *shell_content,
-                                         GtkRadioAction *search_action)
-{
-	g_return_if_fail (E_IS_SHELL_CONTENT (shell_content));
-
-	if (search_action != NULL) {
-		g_return_if_fail (GTK_IS_RADIO_ACTION (search_action));
-		g_object_ref (search_action);
-	}
-
-	if (shell_content->priv->search_radio) {
-		g_signal_handlers_disconnect_matched (
-			shell_content->priv->search_radio,
-			G_SIGNAL_MATCH_DATA, 0, 0, NULL,
-			search_radio_changed_cb, shell_content);
-		g_object_unref (shell_content->priv->search_radio);
-	}
-
-	shell_content->priv->search_radio = search_action;
+	class = E_SHELL_CONTENT_GET_CLASS (shell_content);
+	g_return_val_if_fail (class->get_search_name != NULL, NULL);
 
-	if (shell_content->priv->search_radio != NULL)
-		g_signal_connect (
-			shell_content->priv->search_radio, "changed",
-			G_CALLBACK (search_radio_changed_cb), shell_content);
-
-	g_object_notify (G_OBJECT (shell_content), "search-radio-action");
-}
-
-GtkRadioAction *
-e_shell_content_get_search_radio_action (EShellContent *shell_content)
-{
-	g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), NULL);
-
-	return shell_content->priv->search_radio;
+	return class->get_search_name (shell_content);
 }
 
 void
@@ -1504,14 +500,14 @@ e_shell_content_run_advanced_search_dialog (EShellContent *shell_content)
 	shell_window = e_shell_view_get_shell_window (shell_view);
 	user_filename = shell_content->priv->user_filename;
 
-	rule = e_shell_content_get_search_rule (shell_content);
+	rule = e_shell_view_get_search_rule (shell_view);
 
 	if (rule == NULL)
 		rule = e_filter_rule_new ();
 	else
 		rule = e_filter_rule_clone (rule);
 
-	context = e_shell_content_get_search_context (shell_content);
+	context = E_SHELL_VIEW_GET_CLASS (shell_view)->search_context;
 	widget = e_filter_rule_get_widget (rule, context);
 	e_filter_rule_set_source (rule, E_FILTER_SOURCE_INCOMING);
 
@@ -1548,10 +544,7 @@ run:
 		goto run;
 	}
 
-	e_shell_content_set_search_rule (shell_content, rule);
-
-	shell_content_activate_advanced_search (shell_content);
-	e_shell_view_execute_search (shell_view);
+	e_shell_view_custom_search (shell_view, rule);
 
 	if (response == GTK_RESPONSE_APPLY) {
 		if (!e_rule_context_find_rule (context, rule->name, rule->source))
@@ -1568,13 +561,15 @@ exit:
 void
 e_shell_content_run_edit_searches_dialog (EShellContent *shell_content)
 {
+	EShellView *shell_view;
 	ERuleContext *context;
 	ERuleEditor *editor;
 	const gchar *user_filename;
 
 	g_return_if_fail (E_IS_SHELL_CONTENT (shell_content));
 
-	context = e_shell_content_get_search_context (shell_content);
+	shell_view = e_shell_content_get_shell_view (shell_content);
+	context = E_SHELL_VIEW_GET_CLASS (shell_view)->search_context;
 	user_filename = shell_content->priv->user_filename;
 
 	editor = e_rule_editor_new (
@@ -1596,7 +591,6 @@ e_shell_content_run_save_search_dialog (EShellContent *shell_content)
 	GtkWidget *widget;
 	EFilterRule *rule;
 	ERuleContext *context;
-	const gchar *search_text;
 	const gchar *user_filename;
 	gchar *search_name;
 	gint response;
@@ -1608,19 +602,15 @@ e_shell_content_run_save_search_dialog (EShellContent *shell_content)
 	shell_window = e_shell_view_get_shell_window (shell_view);
 	user_filename = shell_content->priv->user_filename;
 
-	rule = e_shell_content_get_search_rule (shell_content);
+	rule = e_shell_view_get_search_rule (shell_view);
 	g_return_if_fail (E_IS_FILTER_RULE (rule));
 	rule = e_filter_rule_clone (rule);
 
-	search_text = e_shell_content_get_search_text (shell_content);
-	if (search_text == NULL || *search_text == '\0')
-		search_text = "''";
-
-	search_name = g_strdup_printf ("%s %s", rule->name, search_text);
+	search_name = e_shell_content_get_search_name (shell_content);
 	e_filter_rule_set_name (rule, search_name);
 	g_free (search_name);
 
-	context = e_shell_content_get_search_context (shell_content);
+	context = E_SHELL_VIEW_GET_CLASS (shell_view)->search_context;
 	widget = e_filter_rule_get_widget (rule, context);
 	e_filter_rule_set_source (rule, E_FILTER_SOURCE_INCOMING);
 
@@ -1656,83 +646,13 @@ run:
 		goto run;
 	}
 
-	e_rule_context_add_rule (context, rule);
+	/* XXX This function steals the rule reference, so
+	 *     counteract that by referencing it again. */
+	e_rule_context_add_rule (context, g_object_ref (rule));
+
 	e_rule_context_save (context, user_filename);
 
 exit:
 	g_object_unref (rule);
 	gtk_widget_destroy (dialog);
 }
-
-void
-e_shell_content_restore_state (EShellContent *shell_content,
-                               const gchar *group_name)
-{
-	EShellView *shell_view;
-	EShellWindow *shell_window;
-	GKeyFile *key_file;
-	GtkAction *action;
-	GtkWidget *widget;
-	const gchar *search_text;
-	const gchar *key;
-	gchar *string;
-
-	g_return_if_fail (E_IS_SHELL_CONTENT (shell_content));
-	g_return_if_fail (group_name != NULL);
-
-	shell_view = e_shell_content_get_shell_view (shell_content);
-	shell_window = e_shell_view_get_shell_window (shell_view);
-	key_file = e_shell_view_get_state_key_file (shell_view);
-
-	/* Changing the combo boxes triggers searches, so block
-	 * the search action until the state is fully restored. */
-	action = E_SHELL_WINDOW_ACTION_SEARCH_QUICK (shell_window);
-	gtk_action_block_activate (action);
-	e_shell_view_block_execute_search (shell_view);
-
-	key = STATE_KEY_SEARCH_FILTER;
-	string = g_key_file_get_string (key_file, group_name, key, NULL);
-	if (string != NULL && *string != '\0')
-		action = e_shell_window_get_action (shell_window, string);
-	else
-		action = NULL;
-	if (action != NULL)
-		gtk_action_activate (action);
-	else {
-		/* Pick the first combo box item. */
-		widget = shell_content->priv->filter_combo_box;
-		gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 0);
-	}
-	g_free (string);
-
-	key = STATE_KEY_SEARCH_SCOPE;
-	string = g_key_file_get_string (key_file, group_name, key, NULL);
-	if (string != NULL && *string != '\0')
-		action = e_shell_window_get_action (shell_window, string);
-	else
-		action = NULL;
-	if (action != NULL)
-		gtk_action_activate (action);
-	else {
-		/* Pick the first combo box item. */
-		widget = shell_content->priv->scope_combo_box;
-		gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 0);
-	}
-	g_free (string);
-
-	key = STATE_KEY_SEARCH_TEXT;
-	string = g_key_file_get_string (key_file, group_name, key, NULL);
-	search_text = e_shell_content_get_search_text (shell_content);
-	if (search_text != NULL && *search_text == '\0')
-		search_text = NULL;
-	if (g_strcmp0 (string, search_text) != 0)
-		e_shell_content_set_search_text (shell_content, string);
-	g_free (string);
-
-	action = E_SHELL_WINDOW_ACTION_SEARCH_QUICK (shell_window);
-	gtk_action_unblock_activate (action);
-	e_shell_view_unblock_execute_search (shell_view);
-
-	/* Now execute the search. */
-	e_shell_view_execute_search (shell_view);
-}
-- 
cgit