evolution r36427 - in branches/kill-bonobo: addressbook/gui/component doc/reference/shell/tmpl e-util shell ui widgets/misc



Author: mbarnes
Date: Mon Sep 22 21:03:28 2008
New Revision: 36427
URL: http://svn.gnome.org/viewvc/evolution?rev=36427&view=rev

Log:
Search UI is kinda sorta working.  Still some outstanding issues.


Modified:
   branches/kill-bonobo/addressbook/gui/component/addressbook-component.c
   branches/kill-bonobo/addressbook/gui/component/e-book-shell-module.c
   branches/kill-bonobo/addressbook/gui/component/e-book-shell-view-actions.c
   branches/kill-bonobo/addressbook/gui/component/e-book-shell-view-actions.h
   branches/kill-bonobo/addressbook/gui/component/e-book-shell-view-private.c
   branches/kill-bonobo/addressbook/gui/component/e-book-shell-view-private.h
   branches/kill-bonobo/addressbook/gui/component/e-book-shell-view.c
   branches/kill-bonobo/doc/reference/shell/tmpl/e-shell-content.sgml
   branches/kill-bonobo/doc/reference/shell/tmpl/eshell-unused.sgml
   branches/kill-bonobo/e-util/e-util.c
   branches/kill-bonobo/e-util/e-util.h
   branches/kill-bonobo/shell/Makefile.am
   branches/kill-bonobo/shell/e-shell-content.c
   branches/kill-bonobo/shell/e-shell-content.h
   branches/kill-bonobo/shell/e-shell-sidebar.h
   branches/kill-bonobo/shell/e-shell-switcher.h
   branches/kill-bonobo/shell/e-shell-view.h
   branches/kill-bonobo/shell/e-shell-window-actions.c
   branches/kill-bonobo/shell/e-shell-window-actions.h
   branches/kill-bonobo/shell/e-shell-window-private.c
   branches/kill-bonobo/shell/e-shell-window-private.h
   branches/kill-bonobo/ui/evolution-contacts.ui
   branches/kill-bonobo/ui/evolution-shell.ui
   branches/kill-bonobo/widgets/misc/e-icon-entry.c
   branches/kill-bonobo/widgets/misc/e-icon-entry.h

Modified: branches/kill-bonobo/addressbook/gui/component/addressbook-component.c
==============================================================================
--- branches/kill-bonobo/addressbook/gui/component/addressbook-component.c	(original)
+++ branches/kill-bonobo/addressbook/gui/component/addressbook-component.c	Mon Sep 22 21:03:28 2008
@@ -92,25 +92,7 @@
 static void
 addressbook_component_init (AddressbookComponent *component)
 {
-	static int first = TRUE;
-
 #ifdef ENABLE_SMIME
 	smime_component_init ();
 #endif
-
-	if (first) {
-		EImportClass *klass;
-
-		first = FALSE;
-		e_plugin_hook_register_type(eab_popup_hook_get_type());
-		e_plugin_hook_register_type(eab_menu_hook_get_type());
-		e_plugin_hook_register_type(eab_config_hook_get_type());
-
-		klass = g_type_class_ref(e_import_get_type());
-		e_import_class_add_importer(klass, evolution_ldif_importer_peek(), NULL, NULL);
-		e_import_class_add_importer(klass, evolution_vcard_importer_peek(), NULL, NULL);
-		e_import_class_add_importer(klass, evolution_csv_outlook_importer_peek(), NULL, NULL);
-		e_import_class_add_importer(klass, evolution_csv_mozilla_importer_peek(), NULL, NULL);
-		e_import_class_add_importer(klass, evolution_csv_evolution_importer_peek(), NULL, NULL);
-	}
 }

Modified: branches/kill-bonobo/addressbook/gui/component/e-book-shell-module.c
==============================================================================
--- branches/kill-bonobo/addressbook/gui/component/e-book-shell-module.c	(original)
+++ branches/kill-bonobo/addressbook/gui/component/e-book-shell-module.c	Mon Sep 22 21:03:28 2008
@@ -30,6 +30,10 @@
 #include <e-shell-module.h>
 #include <e-shell-window.h>
 
+#include <e-util/e-import.h>
+#include <addressbook/importers/evolution-addressbook-importers.h>
+
+#include <eab-config.h>
 #include <eab-gui-util.h>
 #include <e-book-shell-view.h>
 #include <addressbook-config.h>
@@ -178,6 +182,30 @@
 }
 
 static void
+book_module_init_importers (void)
+{
+	EImportClass *import_class;
+	EImportImporter *importer;
+
+	import_class = g_type_class_ref (e_import_get_type ());
+
+	importer = evolution_ldif_importer_peek ();
+	e_import_class_add_importer (import_class, importer, NULL, NULL);
+
+	importer = evolution_vcard_importer_peek ();
+	e_import_class_add_importer (import_class, importer, NULL, NULL);
+
+	importer = evolution_csv_outlook_importer_peek ();
+	e_import_class_add_importer (import_class, importer, NULL, NULL);
+
+	importer = evolution_csv_mozilla_importer_peek ();
+	e_import_class_add_importer (import_class, importer, NULL, NULL);
+
+	importer = evolution_csv_evolution_importer_peek ();
+	e_import_class_add_importer (import_class, importer, NULL, NULL);
+}
+
+static void
 book_module_book_loaded_cb (EBook *book,
                             EBookStatus status,
                             gpointer user_data)
@@ -401,8 +429,11 @@
 
 	e_shell_module_set_info (shell_module, &module_info);
 
+	book_module_init_importers ();
 	book_module_ensure_sources (shell_module);
 
+	e_plugin_hook_register_type (eab_config_get_type ());
+
 	g_signal_connect_swapped (
 		shell, "handle-uri",
 		G_CALLBACK (book_module_handle_uri), shell_module);

Modified: branches/kill-bonobo/addressbook/gui/component/e-book-shell-view-actions.c
==============================================================================
--- branches/kill-bonobo/addressbook/gui/component/e-book-shell-view-actions.c	(original)
+++ branches/kill-bonobo/addressbook/gui/component/e-book-shell-view-actions.c	Mon Sep 22 21:03:28 2008
@@ -22,7 +22,7 @@
 
 #include <e-util/e-error.h>
 #include <e-util/e-util.h>
-#include <e-util/gconf-bridge.h>
+#include <filter/filter-rule.h>
 
 #include <addressbook-config.h>
 
@@ -333,12 +333,14 @@
 action_contact_preview_cb (GtkToggleAction *action,
                            EBookShellView *book_shell_view)
 {
-	GtkWidget *widget;
+	GtkWidget *child;
+	GtkWidget *paned;
 	gboolean visible;
 
-	widget = book_shell_view->priv->preview;
+	paned = book_shell_view->priv->paned;
+	child = gtk_paned_get_child2 (GTK_PANED (paned));
 	visible = gtk_toggle_action_get_active (action);
-	g_object_set (widget, "visible", visible, NULL);
+	g_object_set (child, "visible", visible, NULL);
 }
 
 static void
@@ -426,10 +428,12 @@
 	EShellContent *shell_content;
 	GString *string;
 	EAddressbookView *view;
+	EAddressbookModel *model;
 	EABContactDisplay *display;
-	const gchar *search_format;
-	const gchar *search_text;
-	gchar *search_query;
+	FilterRule *rule;
+	const gchar *format;
+	const gchar *text;
+	gchar *query;
 	gint value;
 
 	shell_view = E_SHELL_VIEW (book_shell_view);
@@ -437,41 +441,40 @@
 		return;
 
 	shell_content = e_shell_view_get_shell_content (shell_view);
-	search_text = e_shell_content_get_search_text (shell_content);
+	text = e_shell_content_get_search_text (shell_content);
 
 	shell_window = e_shell_view_get_shell_window (shell_view);
 	action = ACTION (CONTACT_SEARCH_ANY_FIELD_CONTAINS);
 	value = gtk_radio_action_get_current_value (
 		GTK_RADIO_ACTION (action));
 
-	if (search_text == NULL || *search_text == '\0') {
-		search_text = "\"\"";
+	if (text == NULL || *text == '\0') {
+		text = "";
 		value = CONTACT_SEARCH_ANY_FIELD_CONTAINS;
 	}
 
 	switch (value) {
 		case CONTACT_SEARCH_NAME_CONTAINS:
-			search_format = "(contains \"full_name\" %s)";
+			format = "(contains \"full_name\" %s)";
 			break;
 
 		case CONTACT_SEARCH_EMAIL_BEGINS_WITH:
-			search_format = "(beginswith \"email\" %s)";
+			format = "(beginswith \"email\" %s)";
 			break;
 
 		default:
-			search_text = "\"\"";
+			text = "";
 			/* fall through */
 
 		case CONTACT_SEARCH_ANY_FIELD_CONTAINS:
-			search_format =
-				"(contains \"x-evolution-any-field\" %s)";
+			format = "(contains \"x-evolution-any-field\" %s)";
 			break;
 	}
 
 	/* Build the query. */
 	string = g_string_new ("");
-	e_sexp_encode_string (string, search_text);
-	search_query = g_strdup_printf (search_format, string->str);
+	e_sexp_encode_string (string, text);
+	query = g_strdup_printf (format, string->str);
 	g_string_free (string, TRUE);
 
 	/* Filter by category. */
@@ -487,15 +490,23 @@
 
 		temp = g_strdup_printf (
 			"(and (is \"category_list\" \"%s\") %s)",
-			category_name, search_query);
-		g_free (search_query);
-		search_query = temp;
+			category_name, query);
+		g_free (query);
+		query = temp;
 	}
 
+	/* XXX This is wrong.  We need to programmatically construct a
+	 *     FilterRule, tell it to build code, and pass the resulting
+	 *     expression string to EAddressbookModel. */
+	rule = filter_rule_new ();
+	e_shell_content_set_search_rule (shell_content, rule);
+	g_object_unref (rule);
+
 	/* Submit the query. */
 	view = e_book_shell_view_get_current_view (book_shell_view);
-	g_object_set (view, "query", search_query, NULL);
-	g_free (search_query);
+	model = e_addressbook_view_get_model (view);
+	e_addressbook_model_set_query (model, query);
+	g_free (query);
 
 	display = EAB_CONTACT_DISPLAY (book_shell_view->priv->preview);
 	eab_contact_display_set_contact (display, NULL);
@@ -731,7 +742,7 @@
 	EShellView *shell_view;
 	EShellWindow *shell_window;
 	GtkActionGroup *action_group;
-	GtkUIManager *manager;
+	GtkUIManager *ui_manager;
 	GConfBridge *bridge;
 	GtkAction *action;
 	GObject *object;
@@ -740,11 +751,12 @@
 
 	shell_view = E_SHELL_VIEW (book_shell_view);
 	shell_window = e_shell_view_get_shell_window (shell_view);
-	manager = e_shell_window_get_ui_manager (shell_window);
+	ui_manager = e_shell_window_get_ui_manager (shell_window);
 	domain = GETTEXT_PACKAGE;
 
-	e_load_ui_definition (manager, "evolution-contacts.ui");
+	e_load_ui_definition (ui_manager, "evolution-contacts.ui");
 
+	/* Contact Actions */
 	action_group = book_shell_view->priv->contact_actions;
 	gtk_action_group_set_translation_domain (action_group, domain);
 	gtk_action_group_add_actions (
@@ -758,7 +770,12 @@
 		G_N_ELEMENTS (contact_search_entries),
 		CONTACT_SEARCH_NAME_CONTAINS,
 		NULL, NULL);
-	gtk_ui_manager_insert_action_group (manager, action_group, 0);
+	gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
+
+	/* Filter Actions (empty) */
+	action_group = book_shell_view->priv->filter_actions;
+	gtk_action_group_set_translation_domain (action_group, domain);
+	gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
 
 	/* Bind GObject properties to GConf keys. */
 
@@ -894,3 +911,60 @@
 		sensitive = FALSE;
 	gtk_action_set_sensitive (action, sensitive);
 }
+
+void
+e_book_shell_view_update_search_filter (EBookShellView *book_shell_view)
+{
+	EShellContent *shell_content;
+	EShellView *shell_view;
+	GtkActionGroup *action_group;
+	GtkRadioAction *action;
+	GList *list, *iter;
+	GSList *group = NULL;
+	gint ii;
+
+	shell_view = E_SHELL_VIEW (book_shell_view);
+	shell_content = e_shell_view_get_shell_content (shell_view);
+	action_group = book_shell_view->priv->filter_actions;
+
+	/* XXX Annoying that GTK+ doesn't provide a function for this.
+	 *     http://bugzilla.gnome.org/show_bug.cgi?id=550485 */
+	list = gtk_action_group_list_actions (action_group);
+	for (iter = list; iter != NULL; iter = iter->next)
+		gtk_action_group_remove_action (action_group, iter->data);
+	g_list_free (list);
+
+	action = gtk_radio_action_new (
+		"category-any", _("Any Category"), NULL, NULL, -1);
+
+	/* Activating the action executes a new search. */
+	g_signal_connect (
+		action, "activate",
+		G_CALLBACK (action_search_execute_cb), book_shell_view);
+
+	gtk_radio_action_set_group (action, group);
+	group = gtk_radio_action_get_group (action);
+
+	list = e_categories_get_list ();
+	for (iter = list, ii = 0; iter != NULL; iter = iter->next, ii++) {
+		const gchar *category_name = iter->data;
+		gchar *action_name;
+
+		action_name = g_strdup_printf ("category-%d", ii);
+		action = gtk_radio_action_new (
+			action_name, category_name, NULL, NULL, ii);
+		g_free (action_name);
+
+		/* Activating the action executes a new search. */
+		g_signal_connect (
+			action, "activate", G_CALLBACK (
+			action_search_execute_cb), book_shell_view);
+
+		gtk_radio_action_set_group (action, group);
+		group = gtk_radio_action_get_group (action);
+	}
+	g_list_free (list);
+
+	/* Use any action in the group; doesn't matter which. */
+	e_shell_content_set_filter_action (shell_content, action);
+}

Modified: branches/kill-bonobo/addressbook/gui/component/e-book-shell-view-actions.h
==============================================================================
--- branches/kill-bonobo/addressbook/gui/component/e-book-shell-view-actions.h	(original)
+++ branches/kill-bonobo/addressbook/gui/component/e-book-shell-view-actions.h	Mon Sep 22 21:03:28 2008
@@ -84,5 +84,7 @@
 /* Action Groups */
 #define E_SHELL_WINDOW_ACTION_GROUP_CONTACTS(window) \
 	E_SHELL_WINDOW_ACTION_GROUP ((window), "contacts")
+#define E_SHELL_WINDOW_ACTION_GROUP_CONTACTS_FILTER(window) \
+	E_SHELL_WINDOW_ACTION_GROUP ((window), "contacts-filter")
 
 #endif /* E_BOOK_SHELL_VIEW_ACTIONS_H */

Modified: branches/kill-bonobo/addressbook/gui/component/e-book-shell-view-private.c
==============================================================================
--- branches/kill-bonobo/addressbook/gui/component/e-book-shell-view-private.c	(original)
+++ branches/kill-bonobo/addressbook/gui/component/e-book-shell-view-private.c	Mon Sep 22 21:03:28 2008
@@ -262,12 +262,6 @@
 	return TRUE;
 }
 
-static void
-book_shell_view_categories_changed_cb (EBookShellView *book_shell_view)
-{
-	e_book_shell_view_update_search_filter (book_shell_view);
-}
-
 static gboolean
 book_shell_view_selector_button_press_event_cb (EShellView *shell_view,
                                                 GdkEventButton *event)
@@ -384,6 +378,7 @@
 
 	priv->source_list = g_object_ref (source_list);
 	priv->contact_actions = gtk_action_group_new ("contacts");
+	priv->filter_actions = gtk_action_group_new ("contacts-filter");
 	priv->uid_to_view = uid_to_view;
 	priv->uid_to_editor = uid_to_editor;
 
@@ -476,7 +471,7 @@
 		book_shell_view);
 
 	e_categories_register_change_listener (
-		G_CALLBACK (book_shell_view_categories_changed_cb),
+		G_CALLBACK (e_book_shell_view_update_search_filter),
 		book_shell_view);
 
 	e_book_shell_view_actions_init (book_shell_view);
@@ -500,6 +495,7 @@
 	DISPOSE (priv->source_list);
 
 	DISPOSE (priv->contact_actions);
+	DISPOSE (priv->filter_actions);
 
 	DISPOSE (priv->paned);
 	DISPOSE (priv->notebook);
@@ -543,41 +539,3 @@
 	hash_table = closure->view->priv->uid_to_editor;
 	g_hash_table_remove (hash_table, closure->uid);
 }
-
-void
-e_book_shell_view_update_search_filter (EBookShellView *book_shell_view)
-{
-	EShellContent *shell_content;
-	EShellView *shell_view;
-	GtkRadioAction *action;
-	GList *list, *iter;
-	GSList *group = NULL;
-	gint ii;
-
-	shell_view = E_SHELL_VIEW (book_shell_view);
-	shell_content = e_shell_view_get_shell_content (shell_view);
-
-	action = gtk_radio_action_new (
-		"category-any", _("Any Category"), NULL, NULL, -1);
-
-	gtk_radio_action_set_group (action, group);
-	group = gtk_radio_action_get_group (action);
-
-	list = e_categories_get_list ();
-	for (iter = list, ii = 0; iter != NULL; iter = iter->next, ii++) {
-		const gchar *category_name = iter->data;
-		gchar *action_name;
-
-		action_name = g_strdup_printf ("category-%d", ii);
-		action = gtk_radio_action_new (
-			action_name, category_name, NULL, NULL, ii);
-		g_free (action_name);
-
-		gtk_radio_action_set_group (action, group);
-		group = gtk_radio_action_get_group (action);
-	}
-	g_list_free (list);
-
-	/* Use any action in the group; doesn't matter which. */
-	e_shell_content_set_filter_action (shell_content, action);
-}

Modified: branches/kill-bonobo/addressbook/gui/component/e-book-shell-view-private.h
==============================================================================
--- branches/kill-bonobo/addressbook/gui/component/e-book-shell-view-private.h	(original)
+++ branches/kill-bonobo/addressbook/gui/component/e-book-shell-view-private.h	Mon Sep 22 21:03:28 2008
@@ -86,6 +86,7 @@
 	/*** UI Management ***/
 
 	GtkActionGroup *contact_actions;
+	GtkActionGroup *filter_actions;
 
 	/*** Other Stuff ***/
 

Modified: branches/kill-bonobo/addressbook/gui/component/e-book-shell-view.c
==============================================================================
--- branches/kill-bonobo/addressbook/gui/component/e-book-shell-view.c	(original)
+++ branches/kill-bonobo/addressbook/gui/component/e-book-shell-view.c	Mon Sep 22 21:03:28 2008
@@ -20,6 +20,8 @@
 
 #include "e-book-shell-view-private.h"
 
+#define SEARCH_OPTIONS_PATH	"/contact-search-options"
+
 enum {
 	PROP_0,
 	PROP_SOURCE_LIST
@@ -166,6 +168,7 @@
 	shell_view_class->icon_name = "x-office-address-book";
 	shell_view_class->type_module = type_module;
 	shell_view_class->changed = book_shell_view_changed;
+	shell_view_class->search_options_path = SEARCH_OPTIONS_PATH;
 	shell_view_class->new_shell_sidebar = e_book_shell_sidebar_new;
 
 	g_object_class_install_property (

Modified: branches/kill-bonobo/doc/reference/shell/tmpl/e-shell-content.sgml
==============================================================================
--- branches/kill-bonobo/doc/reference/shell/tmpl/e-shell-content.sgml	(original)
+++ branches/kill-bonobo/doc/reference/shell/tmpl/e-shell-content.sgml	Mon Sep 22 21:03:28 2008
@@ -53,12 +53,12 @@
 
 </para>
 
-<!-- ##### ARG EShellContent:search-action ##### -->
+<!-- ##### ARG EShellContent:search-context ##### -->
 <para>
 
 </para>
 
-<!-- ##### ARG EShellContent:search-context ##### -->
+<!-- ##### ARG EShellContent:search-rule ##### -->
 <para>
 
 </para>

Modified: branches/kill-bonobo/doc/reference/shell/tmpl/eshell-unused.sgml
==============================================================================
--- branches/kill-bonobo/doc/reference/shell/tmpl/eshell-unused.sgml	(original)
+++ branches/kill-bonobo/doc/reference/shell/tmpl/eshell-unused.sgml	Mon Sep 22 21:03:28 2008
@@ -406,6 +406,12 @@
 @minor: 
 @revision: 
 
+<!-- ##### ARG EShellContent:search-action ##### -->
+<para>
+
+</para>
+
+
 <!-- ##### STRUCT EShellContentPrivate ##### -->
 <para>
 

Modified: branches/kill-bonobo/e-util/e-util.c
==============================================================================
--- branches/kill-bonobo/e-util/e-util.c	(original)
+++ branches/kill-bonobo/e-util/e-util.c	Mon Sep 22 21:03:28 2008
@@ -107,10 +107,10 @@
 
 /**
  * e_load_ui_definition:
- * @manager: a #GtkUIManager
+ * @ui_manager: a #GtkUIManager
  * @basename: basename of the UI definition file
  *
- * Loads a UI definition into @manager from Evolution's UI directory.
+ * Loads a UI definition into @ui_manager from Evolution's UI directory.
  * Failure here is fatal, since the application can't function without
  * its UI definitions.
  *
@@ -118,18 +118,19 @@
  *          unmerge the UI with gtk_ui_manager_remove_ui().
  **/
 guint
-e_load_ui_definition (GtkUIManager *manager,
+e_load_ui_definition (GtkUIManager *ui_manager,
                       const gchar *basename)
 {
 	gchar *filename;
 	guint merge_id;
 	GError *error = NULL;
 
-	g_return_val_if_fail (GTK_IS_UI_MANAGER (manager), 0);
+	g_return_val_if_fail (GTK_IS_UI_MANAGER (ui_manager), 0);
 	g_return_val_if_fail (basename != NULL, 0);
 
 	filename = g_build_filename (EVOLUTION_UIDIR, basename, NULL);
-	merge_id = gtk_ui_manager_add_ui_from_file (manager, filename, &error);
+	merge_id = gtk_ui_manager_add_ui_from_file (
+		ui_manager, filename, &error);
 	g_free (filename);
 
 	if (error != NULL)

Modified: branches/kill-bonobo/e-util/e-util.h
==============================================================================
--- branches/kill-bonobo/e-util/e-util.h	(original)
+++ branches/kill-bonobo/e-util/e-util.h	Mon Sep 22 21:03:28 2008
@@ -44,7 +44,7 @@
 const gchar *	e_get_user_data_dir		(void);
 void		e_display_help			(GtkWindow *parent,
 						 const gchar *link_id);
-guint		e_load_ui_definition		(GtkUIManager *manager,
+guint		e_load_ui_definition		(GtkUIManager *ui_manager,
 						 const gchar *basename);
 
 char *		e_str_without_underscores	(const char *s);

Modified: branches/kill-bonobo/shell/Makefile.am
==============================================================================
--- branches/kill-bonobo/shell/Makefile.am	(original)
+++ branches/kill-bonobo/shell/Makefile.am	Mon Sep 22 21:03:28 2008
@@ -17,7 +17,7 @@
 	-DEVOLUTION_GLADEDIR=\""$(gladedir)"\"			\
 	-DEVOLUTION_HELPDIR=\""$(evolutionhelpdir)"\"		\
 	-DEVOLUTION_MODULEDIR=\""$(moduledir)"\"		\
-	-DEVOLUTION_RULEDIR=\""$(ruledir)"\"			\
+	-DEVOLUTION_RULEDIR=\""$(privdatadir)"\"		\
 	-DEVOLUTION_UIDIR=\""$(evolutionuidir)"\"		\
 	-DEVOLUTION_TOOLSDIR=\""$(privlibexecdir)"\"		\
 	-DPREFIX=\""$(prefix)"\"				\

Modified: branches/kill-bonobo/shell/e-shell-content.c
==============================================================================
--- branches/kill-bonobo/shell/e-shell-content.c	(original)
+++ branches/kill-bonobo/shell/e-shell-content.c	Mon Sep 22 21:03:28 2008
@@ -22,6 +22,7 @@
 
 #include <glib/gi18n.h>
 
+#include <filter/rule-editor.h>
 #include <widgets/misc/e-action-combo-box.h>
 #include <widgets/misc/e-icon-entry.h>
 
@@ -38,7 +39,9 @@
 	gpointer shell_view;  /* weak pointer */
 
 	RuleContext *search_context;
-	FilterRule *current_query;
+	FilterRule *search_rule;
+	gchar *system_filename;
+	gchar *user_filename;
 
 	/* Container for the following widgets */
 	GtkWidget *search_bar;
@@ -52,9 +55,6 @@
 	GtkWidget *scope_combo_box;
 
 	GtkStateType search_state;
-
-	GtkRadioAction *search_action;
-	GtkWidget *search_popup_menu;
 };
 
 enum {
@@ -62,8 +62,8 @@
 	PROP_FILTER_ACTION,
 	PROP_FILTER_VALUE,
 	PROP_FILTER_VISIBLE,
-	PROP_SEARCH_ACTION,
 	PROP_SEARCH_CONTEXT,
+	PROP_SEARCH_RULE,
 	PROP_SEARCH_TEXT,
 	PROP_SEARCH_VALUE,
 	PROP_SEARCH_VISIBLE,
@@ -76,42 +76,68 @@
 static gpointer parent_class;
 
 static void
-shell_content_entry_activated_cb (EShellContent *shell_content,
-                                  GtkWidget *entry)
+shell_content_dialog_rule_changed (GtkWidget *dialog,
+                                            FilterRule *rule)
+{
+	gboolean sensitive;
+
+	sensitive = (rule != NULL) && (rule->parts != NULL);
+
+	gtk_dialog_set_response_sensitive (
+		GTK_DIALOG (dialog), GTK_RESPONSE_OK, sensitive);
+	gtk_dialog_set_response_sensitive (
+		GTK_DIALOG (dialog), GTK_RESPONSE_APPLY, sensitive);
+}
+
+static void
+action_search_execute_cb (GtkAction *action,
+                          EShellContent *shell_content)
 {
-	EShellWindow *shell_window;
 	EShellView *shell_view;
-	GtkAction *action;
+	EShellWindow *shell_window;
+	EIconEntry *icon_entry;
+	GtkWidget *child;
+	GtkStateType visual_state;
+	const gchar *search_text;
+
+	/* EShellView subclasses are responsible for actually
+	 * executing the search.  This is all cosmetic stuff. */
 
 	shell_view = e_shell_content_get_shell_view (shell_content);
 	shell_window = e_shell_view_get_shell_window (shell_view);
 
-	/* Verify the shell view is active before proceeding. */
 	if (!e_shell_view_is_active (shell_view))
 		return;
 
-	action = E_SHELL_WINDOW_ACTION_SEARCH_EXECUTE (shell_window);
-	gtk_action_activate (action);
+	icon_entry = E_ICON_ENTRY (shell_content->priv->search_entry);
+	search_text = e_shell_content_get_search_text (shell_content);
+
+	if (search_text != NULL && *search_text != '\0')
+		visual_state = GTK_STATE_SELECTED;
+	else
+		visual_state = GTK_STATE_NORMAL;
+
+	e_icon_entry_set_visual_state (icon_entry, visual_state);
+
+	action = E_SHELL_WINDOW_ACTION_SEARCH_CLEAR (shell_window);
+	gtk_action_set_sensitive (action, TRUE);
+
+	action = E_SHELL_WINDOW_ACTION_SEARCH_SAVE (shell_window);
+	gtk_action_set_sensitive (action, TRUE);
+
+	/* 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. */
+	gtk_widget_grab_focus (gtk_bin_get_child (GTK_BIN (shell_content)));
 }
 
 static void
-shell_content_entry_changed_cb (EShellContent *shell_content,
-                                GtkWidget *entry)
+shell_content_entry_activated_cb (EShellContent *shell_content,
+                                  GtkWidget *entry)
 {
 	EShellWindow *shell_window;
 	EShellView *shell_view;
-	GtkStateType state;
 	GtkAction *action;
-	gboolean sensitive;
-	const gchar *text;
-
-	text = gtk_entry_get_text (GTK_ENTRY (entry));
-	state = shell_content->priv->search_state;
-
-	if (text != NULL && *text != '\0')
-		sensitive = (state != GTK_STATE_INSENSITIVE);
-	else
-		sensitive = (state == GTK_STATE_SELECTED);
 
 	shell_view = e_shell_content_get_shell_view (shell_content);
 	shell_window = e_shell_view_get_shell_window (shell_view);
@@ -120,8 +146,8 @@
 	if (!e_shell_view_is_active (shell_view))
 		return;
 
-	action = E_SHELL_WINDOW_ACTION_SEARCH_CLEAR (shell_window);
-	gtk_action_set_sensitive (action, sensitive);
+	action = E_SHELL_WINDOW_ACTION_SEARCH_EXECUTE (shell_window);
+	gtk_action_activate (action);
 }
 
 static gboolean
@@ -129,11 +155,16 @@
                                  GdkEventFocus *focus_event,
                                  GtkWidget *entry)
 {
-	if (shell_content->priv->search_state == GTK_STATE_INSENSITIVE) {
+	EIconEntry *icon_entry;
+	GtkStateType visual_state;
+
+	icon_entry = E_ICON_ENTRY (shell_content->priv->search_entry);
+	visual_state = e_icon_entry_get_visual_state (icon_entry);
+
+	if (visual_state == GTK_STATE_INSENSITIVE)
 		gtk_entry_set_text (GTK_ENTRY (entry), "");
-		gtk_widget_modify_text (entry, GTK_STATE_NORMAL, NULL);
-		shell_content->priv->search_state = GTK_STATE_NORMAL;
-	}
+
+	e_icon_entry_set_visual_state (icon_entry, GTK_STATE_NORMAL);
 
 	return FALSE;
 }
@@ -152,8 +183,25 @@
                                   GdkEventKey *key_event,
                                   GtkWidget *entry)
 {
-	/* FIXME */
-	return FALSE;
+	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
@@ -194,14 +242,14 @@
 		rule_context_add_rule, rule_context_next_rule);
 	rule_context_load (context, system_filename, user_filename);
 
-	/* Ownership of the strings is passed to the rule context.
-	 * XXX Not sure why this is necessary. */
+	/* XXX Not sure why this is necessary. */
 	g_object_set_data_full (
-		G_OBJECT (context), "system", system_filename, g_free);
+		G_OBJECT (context), "system",
+		g_strdup (system_filename), g_free);
 	g_object_set_data_full (
-		G_OBJECT (context), "user", user_filename, g_free);
+		G_OBJECT (context), "user",
+		g_strdup (user_filename), g_free);
 
-	/* XXX I don't really understand what this does. */
 	rule = filter_rule_new ();
 	part = rule_context_next_part (context, NULL);
 	if (part == NULL)
@@ -212,6 +260,8 @@
 		filter_rule_add_part (rule, 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
@@ -252,8 +302,8 @@
 				g_value_get_boolean (value));
 			return;
 
-		case PROP_SEARCH_ACTION:
-			e_shell_content_set_search_action (
+		case PROP_SEARCH_RULE:
+			e_shell_content_set_search_rule (
 				E_SHELL_CONTENT (object),
 				g_value_get_object (value));
 			return;
@@ -329,15 +379,15 @@
 				E_SHELL_CONTENT (object)));
 			return;
 
-		case PROP_SEARCH_ACTION:
+		case PROP_SEARCH_CONTEXT:
 			g_value_set_object (
-				value, e_shell_content_get_search_action (
+				value, e_shell_content_get_search_context (
 				E_SHELL_CONTENT (object)));
 			return;
 
-		case PROP_SEARCH_CONTEXT:
+		case PROP_SEARCH_RULE:
 			g_value_set_object (
-				value, e_shell_content_get_search_context (
+				value, e_shell_content_get_search_rule (
 				E_SHELL_CONTENT (object)));
 			return;
 
@@ -435,16 +485,51 @@
                 priv->scope_combo_box = NULL;
         }
 
-        if (priv->search_action != NULL) {
-                g_object_unref (priv->search_action);
-                priv->search_action = 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;
+	EShellContent *shell_content;
+	EIconEntry *icon_entry;
+	GtkAction *action;
+
+	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);
+	icon_entry = E_ICON_ENTRY (shell_content->priv->search_entry);
+
+	action = E_SHELL_WINDOW_ACTION_SEARCH_CLEAR (shell_window);
+	e_icon_entry_add_action_end (icon_entry, action);
+
+	action = E_SHELL_WINDOW_ACTION_SEARCH_EXECUTE (shell_window);
+	g_signal_connect (
+		action, "activate",
+		G_CALLBACK (action_search_execute_cb), shell_content);
+
+	action = E_SHELL_WINDOW_ACTION_SEARCH_OPTIONS (shell_window);
+	e_icon_entry_add_action_start (icon_entry, action);
+}
+
+static void
 shell_content_realize (GtkWidget *widget)
 {
 	EShellContent *shell_content;
@@ -569,6 +654,8 @@
 	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;
 
 	widget_class = GTK_WIDGET_CLASS (class);
 	widget_class->realize = shell_content_realize;
@@ -614,23 +701,23 @@
 
 	g_object_class_install_property (
 		object_class,
-		PROP_SEARCH_ACTION,
+		PROP_SEARCH_CONTEXT,
 		g_param_spec_object (
-			"search-action",
+			"search-context",
 			NULL,
 			NULL,
-			GTK_TYPE_RADIO_ACTION,
-			G_PARAM_READWRITE));
+			RULE_TYPE_CONTEXT,
+			G_PARAM_READABLE));
 
 	g_object_class_install_property (
 		object_class,
-		PROP_SEARCH_CONTEXT,
+		PROP_SEARCH_RULE,
 		g_param_spec_object (
-			"search-context",
+			"search-rule",
 			NULL,
 			NULL,
-			RULE_TYPE_CONTEXT,
-			G_PARAM_READABLE));
+			FILTER_TYPE_RULE,
+			G_PARAM_READWRITE));
 
 	g_object_class_install_property (
 		object_class,
@@ -793,9 +880,6 @@
 		widget, "activate",
 		G_CALLBACK (shell_content_entry_activated_cb), shell_content);
 	g_signal_connect_swapped (
-		widget, "changed",
-		G_CALLBACK (shell_content_entry_changed_cb), shell_content);
-	g_signal_connect_swapped (
 		widget, "focus-in-event",
 		G_CALLBACK (shell_content_entry_focus_in_cb), shell_content);
 	g_signal_connect_swapped (
@@ -924,35 +1008,38 @@
 	}
 }
 
-GtkRadioAction *
-e_shell_content_get_search_action (EShellContent *shell_content)
+RuleContext *
+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_action;
+	return shell_content->priv->search_context;
+}
+
+FilterRule *
+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_action (EShellContent *shell_content,
-                                   GtkRadioAction *search_action)
+e_shell_content_set_search_rule (EShellContent *shell_content,
+                                 FilterRule *search_rule)
 {
 	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 (search_rule != NULL) {
+		g_return_if_fail (IS_FILTER_RULE (search_rule));
+		g_object_ref (search_rule);
 	}
 
-	shell_content->priv->search_action = search_action;
-	g_object_notify (G_OBJECT (shell_content), "search-action");
-}
-
-RuleContext *
-e_shell_content_get_search_context (EShellContent *shell_content)
-{
-	g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), NULL);
+	if (shell_content->priv->search_rule != NULL)
+		g_object_unref (shell_content->priv->search_rule);
 
-	return shell_content->priv->search_context;
+	shell_content->priv->search_rule = search_rule;
+	g_object_notify (G_OBJECT (shell_content), "search-rule");
 }
 
 const gchar *
@@ -1108,3 +1195,173 @@
 
 	g_object_notify (G_OBJECT (shell_content), "scope-visible");
 }
+
+void
+e_shell_content_run_advanced_search_dialog (EShellContent *shell_content)
+{
+	EShellView *shell_view;
+	EShellWindow *shell_window;
+	GtkAction *action;
+	GtkWidget *dialog;
+	GtkWidget *widget;
+	FilterRule *rule;
+	RuleContext *context;
+	const gchar *user_filename;
+	gint response;
+
+	g_return_if_fail (E_IS_SHELL_CONTENT (shell_content));
+
+	shell_view = e_shell_content_get_shell_view (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);
+
+	if (rule == NULL)
+		rule = filter_rule_new ();
+	else
+		rule = filter_rule_clone (rule);
+
+	context = e_shell_content_get_search_context (shell_content);
+	widget = filter_rule_get_widget (rule, context);
+	filter_rule_set_source (rule, FILTER_SOURCE_INCOMING);
+
+	dialog = gtk_dialog_new_with_buttons (
+		_("Advanced Search"), GTK_WINDOW (shell_window),
+		GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
+		GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+		GTK_STOCK_SAVE, GTK_RESPONSE_APPLY,
+		GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
+
+	gtk_container_set_border_width (GTK_CONTAINER (dialog), 7);
+	gtk_container_set_border_width (GTK_CONTAINER (widget), 3);
+	gtk_window_set_default_size (GTK_WINDOW (dialog), 600, 300);
+
+	gtk_box_pack_start (
+		GTK_BOX (GTK_DIALOG (dialog)->vbox), widget, TRUE, TRUE, 0);
+
+	g_signal_connect_swapped (
+		rule, "changed", G_CALLBACK (
+		shell_content_dialog_rule_changed), dialog);
+
+	shell_content_dialog_rule_changed (dialog, rule);
+
+run:
+	response = gtk_dialog_run (GTK_DIALOG (dialog));
+
+	if (response != GTK_RESPONSE_OK && response != GTK_RESPONSE_APPLY)
+		goto exit;
+
+	if (!filter_rule_validate (rule))
+		goto run;
+
+	e_shell_content_set_search_rule (shell_content, rule);
+
+	action = E_SHELL_WINDOW_ACTION_SEARCH_EXECUTE (shell_window);
+	gtk_action_activate (action);
+
+	if (response == GTK_RESPONSE_APPLY) {
+		if (!rule_context_find_rule (context, rule->name, rule->source))
+			rule_context_add_rule (context, rule);
+		rule_context_save (context, user_filename);
+		goto run;
+	}
+
+exit:
+	g_object_unref (rule);
+	gtk_widget_destroy (dialog);
+}
+
+void
+e_shell_content_run_edit_searches_dialog (EShellContent *shell_content)
+{
+	RuleContext *context;
+	RuleEditor *editor;
+	const gchar *user_filename;
+
+	g_return_if_fail (E_IS_SHELL_CONTENT (shell_content));
+
+	context = e_shell_content_get_search_context (shell_content);
+	user_filename = shell_content->priv->user_filename;
+
+	editor = rule_editor_new (
+		context, FILTER_SOURCE_INCOMING, _("Searches"));
+	gtk_window_set_title (GTK_WINDOW (editor), _("Searches"));
+
+	if (gtk_dialog_run (GTK_DIALOG (editor)) == GTK_RESPONSE_OK)
+		rule_context_save (context, user_filename);
+
+	gtk_widget_destroy (GTK_WIDGET (editor));
+}
+
+void
+e_shell_content_run_save_search_dialog (EShellContent *shell_content)
+{
+	EShellView *shell_view;
+	EShellWindow *shell_window;
+	GtkWidget *dialog;
+	GtkWidget *widget;
+	FilterRule *rule;
+	RuleContext *context;
+	const gchar *search_text;
+	const gchar *user_filename;
+	gchar *search_name;
+	gint response;
+
+	g_return_if_fail (E_IS_SHELL_CONTENT (shell_content));
+
+	shell_view = e_shell_content_get_shell_view (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);
+	g_return_if_fail (IS_FILTER_RULE (rule));
+	rule = 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);
+	filter_rule_set_name (rule, search_name);
+	g_free (search_name);
+
+	context = e_shell_content_get_search_context (shell_content);
+	widget = filter_rule_get_widget (rule, context);
+	filter_rule_set_source (rule, FILTER_SOURCE_INCOMING);
+
+	dialog = gtk_dialog_new_with_buttons (
+		_("Save Search"), GTK_WINDOW (shell_window),
+		GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
+		GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+		GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
+
+	gtk_container_set_border_width (GTK_CONTAINER (dialog), 7);
+	gtk_container_set_border_width (GTK_CONTAINER (widget), 3);
+	gtk_window_set_default_size (GTK_WINDOW (dialog), 500, 300);
+
+	gtk_box_pack_start (
+		GTK_BOX (GTK_DIALOG (dialog)->vbox), widget, TRUE, TRUE, 0);
+
+	g_signal_connect_swapped (
+		rule, "changed", G_CALLBACK (
+		shell_content_dialog_rule_changed), dialog);
+
+	shell_content_dialog_rule_changed (dialog, rule);
+
+run:
+	response = gtk_dialog_run (GTK_DIALOG (dialog));
+
+	if (response != GTK_RESPONSE_OK)
+		goto exit;
+
+	if (!filter_rule_validate (rule))
+		goto run;
+
+	rule_context_add_rule (context, rule);
+	rule_context_save (context, user_filename);
+
+exit:
+	g_object_unref (rule);
+	gtk_widget_destroy (dialog);
+}

Modified: branches/kill-bonobo/shell/e-shell-content.h
==============================================================================
--- branches/kill-bonobo/shell/e-shell-content.h	(original)
+++ branches/kill-bonobo/shell/e-shell-content.h	Mon Sep 22 21:03:28 2008
@@ -21,7 +21,8 @@
 #ifndef E_SHELL_CONTENT_H
 #define E_SHELL_CONTENT_H
 
-#include <gtk/gtk.h>
+#include <e-shell-common.h>
+#include <filter/filter-rule.h>
 #include <filter/rule-context.h>
 
 /* Standard GObject macros */
@@ -81,13 +82,11 @@
 void		e_shell_content_set_filter_visible
 						(EShellContent *shell_content,
 						 gboolean filter_visible);
-GtkRadioAction *e_shell_content_get_search_action
-						(EShellContent *shell_content);
-void		e_shell_content_set_search_action
-						(EShellContent *shell_content,
-						 GtkRadioAction *search_action);
 RuleContext *	e_shell_content_get_search_context
 						(EShellContent *shell_content);
+FilterRule *	e_shell_content_get_search_rule	(EShellContent *shell_content);
+void		e_shell_content_set_search_rule (EShellContent *shell_content,
+						 FilterRule *search_rule);
 const gchar *	e_shell_content_get_search_text	(EShellContent *shell_content);
 void		e_shell_content_set_search_text	(EShellContent *shell_content,
 						 const gchar *search_text);
@@ -116,6 +115,12 @@
 const gchar *	e_shell_content_get_view_id	(EShellContent *shell_content);
 void		e_shell_content_set_view_id	(EShellContent *shell_content,
 						 const gchar *view_id);
+void		e_shell_content_run_advanced_search_dialog
+						(EShellContent *shell_content);
+void		e_shell_content_run_edit_searches_dialog
+						(EShellContent *shell_content);
+void		e_shell_content_run_save_search_dialog
+						(EShellContent *shell_content);
 
 G_END_DECLS
 

Modified: branches/kill-bonobo/shell/e-shell-sidebar.h
==============================================================================
--- branches/kill-bonobo/shell/e-shell-sidebar.h	(original)
+++ branches/kill-bonobo/shell/e-shell-sidebar.h	Mon Sep 22 21:03:28 2008
@@ -21,7 +21,7 @@
 #ifndef E_SHELL_SIDEBAR_H
 #define E_SHELL_SIDEBAR_H
 
-#include <gtk/gtk.h>
+#include <e-shell-common.h>
 
 /* Standard GObject macros */
 #define E_TYPE_SHELL_SIDEBAR \

Modified: branches/kill-bonobo/shell/e-shell-switcher.h
==============================================================================
--- branches/kill-bonobo/shell/e-shell-switcher.h	(original)
+++ branches/kill-bonobo/shell/e-shell-switcher.h	Mon Sep 22 21:03:28 2008
@@ -21,7 +21,7 @@
 #ifndef E_SHELL_SWITCHER_H
 #define E_SHELL_SWITCHER_H
 
-#include <gtk/gtk.h>
+#include <e-shell-common.h>
 
 /* Standard GObject macros */
 #define E_TYPE_SHELL_SWITCHER \

Modified: branches/kill-bonobo/shell/e-shell-view.h
==============================================================================
--- branches/kill-bonobo/shell/e-shell-view.h	(original)
+++ branches/kill-bonobo/shell/e-shell-view.h	Mon Sep 22 21:03:28 2008
@@ -72,6 +72,9 @@
 	/* A unique instance is created for each subclass. */
 	GalViewCollection *view_collection;
 
+	/* Path to the search entry popup menu. */
+	const gchar *search_options_path;
+
 	/* Factory Methods */
 	GtkWidget *	(*new_shell_content)	(EShellView *shell_view);
 	GtkWidget *	(*new_shell_sidebar)	(EShellView *shell_view);

Modified: branches/kill-bonobo/shell/e-shell-window-actions.c
==============================================================================
--- branches/kill-bonobo/shell/e-shell-window-actions.c	(original)
+++ branches/kill-bonobo/shell/e-shell-window-actions.c	Mon Sep 22 21:03:28 2008
@@ -674,6 +674,29 @@
 }
 
 static void
+action_custom_rule_cb (GtkAction *action,
+                       EShellWindow *shell_window)
+{
+	FilterRule *rule;
+	EShellView *shell_view;
+	EShellContent *shell_content;
+	const gchar *view_name;
+
+	rule = g_object_get_data (G_OBJECT (action), "rule");
+	g_return_if_fail (rule != NULL);
+
+	view_name = e_shell_window_get_active_view (shell_window);
+	shell_view = e_shell_window_get_view (shell_window, view_name);
+	shell_content = e_shell_view_get_shell_content (shell_view);
+
+	rule = g_object_get_data (G_OBJECT (action), "rule");
+	g_return_if_fail (IS_FILTER_RULE (rule));
+
+	e_shell_content_set_search_rule (shell_content, rule);
+	gtk_action_activate (ACTION (SEARCH_EXECUTE));
+}
+
+static void
 action_faq_cb (GtkAction *action,
                EShellWindow *shell_window)
 {
@@ -841,65 +864,85 @@
 action_search_advanced_cb (GtkAction *action,
                            EShellWindow *shell_window)
 {
+	EShellView *shell_view;
+	EShellContent *shell_content;
+	const gchar *view_name;
+
+	view_name = e_shell_window_get_active_view (shell_window);
+	shell_view = e_shell_window_get_view (shell_window, view_name);
+	shell_content = e_shell_view_get_shell_content (shell_view);
+
+	e_shell_content_run_advanced_search_dialog (shell_content);
+	e_shell_window_update_search_menu (shell_window);
 }
 
 static void
 action_search_clear_cb (GtkAction *action,
                         EShellWindow *shell_window)
 {
-	EShellContent *shell_content;
 	EShellView *shell_view;
+	EShellContent *shell_content;
 	const gchar *view_name;
 
 	view_name = e_shell_window_get_active_view (shell_window);
 	shell_view = e_shell_window_get_view (shell_window, view_name);
 	shell_content = e_shell_view_get_shell_content (shell_view);
-	e_shell_content_set_search_text (shell_content, "");
+
+	e_shell_content_set_search_rule (shell_content, NULL);
+	e_shell_content_set_search_text (shell_content, NULL);
+
+	gtk_action_activate (ACTION (SEARCH_EXECUTE));
+
+	e_shell_window_update_search_menu (shell_window);
 }
 
 static void
 action_search_edit_cb (GtkAction *action,
                        EShellWindow *shell_window)
 {
-	EShellContent *shell_content;
 	EShellView *shell_view;
-	RuleContext *context;
-	RuleEditor *editor;
-	const gchar *filename;
+	EShellContent *shell_content;
 	const gchar *view_name;
 
 	view_name = e_shell_window_get_active_view (shell_window);
 	shell_view = e_shell_window_get_view (shell_window, view_name);
 	shell_content = e_shell_view_get_shell_content (shell_view);
-	context = e_shell_content_get_search_context (shell_content);
-	g_return_if_fail (context != NULL);
-
-	/* XXX I don't know why the RuleContext can't just store
-	 *     system and user file names properly.  Fix this? */
-	filename = g_object_get_data (G_OBJECT (context), "user");
-	g_return_if_fail (filename != NULL);
 
-	editor = rule_editor_new (
-		context, FILTER_SOURCE_INCOMING, _("Searches"));
-	gtk_window_set_title (GTK_WINDOW (editor), _("Searches"));
-
-	if (gtk_dialog_run (GTK_DIALOG (editor)) == GTK_RESPONSE_OK)
-		rule_context_save (context, filename);
-
-	gtk_widget_destroy (GTK_WIDGET (editor));
+	e_shell_content_run_edit_searches_dialog (shell_content);
+	e_shell_window_update_search_menu (shell_window);
 }
 
 static void
-action_search_execute_cb (GtkAction *action,
+action_search_options_cb (GtkAction *action,
                           EShellWindow *shell_window)
 {
-	gtk_action_set_sensitive (action, FALSE);
+	EShellView *shell_view;
+	EShellViewClass *shell_view_class;
+	const gchar *view_name;
+	const gchar *widget_path;
+
+	view_name = e_shell_window_get_active_view (shell_window);
+	shell_view = e_shell_window_get_view (shell_window, view_name);
+	shell_view_class = E_SHELL_VIEW_GET_CLASS (shell_view);
+
+	widget_path = shell_view_class->search_options_path;
+	e_shell_window_show_popup_menu (shell_window, widget_path, NULL);
 }
 
 static void
 action_search_save_cb (GtkAction *action,
                        EShellWindow *shell_window)
 {
+	EShellView *shell_view;
+	EShellContent *shell_content;
+	const gchar *view_name;
+
+	view_name = e_shell_window_get_active_view (shell_window);
+	shell_view = e_shell_window_get_view (shell_window, view_name);
+	shell_content = e_shell_view_get_shell_content (shell_view);
+
+	e_shell_content_run_save_search_dialog (shell_content);
+	e_shell_window_update_search_menu (shell_window);
 }
 
 static void
@@ -1172,7 +1215,14 @@
 	  N_("_Find Now"),
 	  NULL,
 	  N_("Execute the current search parameters"),
-	  G_CALLBACK (action_search_execute_cb) },
+	  NULL },  /* Handled by EShellContent and subclasses. */
+
+	{ "search-options",
+	  GTK_STOCK_FIND,
+	  NULL,
+	  NULL,
+	  N_("Click here to change the search type"),
+	  G_CALLBACK (action_search_options_cb) },
 
 	{ "search-save",
 	  NULL,
@@ -1507,6 +1557,11 @@
 	gtk_action_group_set_translation_domain (action_group, domain);
 	gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
 
+	/* Custom Rule Actions (empty) */
+	action_group = shell_window->priv->custom_rule_actions;
+	gtk_action_group_set_translation_domain (action_group, domain);
+	gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
+
 	/* Switcher Actions (empty) */
 	action_group = shell_window->priv->switcher_actions;
 	gtk_action_group_set_translation_domain (action_group, domain);
@@ -1805,3 +1860,93 @@
 	action = ACTION (GAL_SAVE_CUSTOM_VIEW);
 	gtk_action_set_visible (action, visible);
 }
+
+void
+e_shell_window_update_search_menu (EShellWindow *shell_window)
+{
+	EShellContent *shell_content;
+	EShellView *shell_view;
+	EShellViewClass *shell_view_class;
+	RuleContext *context;
+	FilterRule *rule;
+	GtkUIManager *ui_manager;
+	GtkActionGroup *action_group;
+	GList *list, *iter;
+	const gchar *source;
+	const gchar *view_name;
+	gboolean sensitive;
+	guint merge_id;
+	gint ii = 0;
+
+	ui_manager = e_shell_window_get_ui_manager (shell_window);
+	view_name = e_shell_window_get_active_view (shell_window);
+	shell_view = e_shell_window_get_view (shell_window, view_name);
+	shell_content = e_shell_view_get_shell_content (shell_view);
+	context = e_shell_content_get_search_context (shell_content);
+	shell_view_class = E_SHELL_VIEW_GET_CLASS (shell_view);
+	source = FILTER_SOURCE_INCOMING;
+
+	/* Update sensitivity of search actions. */
+
+	sensitive = (e_shell_content_get_search_rule (shell_content) != NULL);
+	gtk_action_set_sensitive (ACTION (SEARCH_CLEAR), sensitive);
+	gtk_action_set_sensitive (ACTION (SEARCH_SAVE), sensitive);
+
+	sensitive = (shell_view_class->search_options_path != NULL);
+	gtk_action_set_sensitive (ACTION (SEARCH_OPTIONS), sensitive);
+
+	/* Add custom rules to the Search menu. */
+
+	action_group = shell_window->priv->custom_rule_actions;
+	merge_id = shell_window->priv->custom_rule_merge_id;
+
+	/* Unmerge the previous menu. */
+	gtk_ui_manager_remove_ui (ui_manager, merge_id);
+
+	/* XXX Annoying that GTK+ doesn't provide a function for this.
+	 *     http://bugzilla.gnome.org/show_bug.cgi?id=550485 */
+	list = gtk_action_group_list_actions (action_group);
+	for (iter = list; iter != NULL; iter = iter->next)
+		gtk_action_group_remove_action (action_group, iter->data);
+	g_list_free (list);
+
+	rule = rule_context_next_rule (context, NULL, source);
+	while (rule != NULL) {
+		GtkAction *action;
+		gchar *action_name;
+		gchar *action_label;
+
+		action_name = g_strdup_printf ("custom-rule-%d", ii++);
+		if (ii < 10)
+			action_label = g_strdup_printf (
+				"_%d. %s", ii, rule->name);
+		else
+			action_label = g_strdup (rule->name);
+
+		action = gtk_action_new (
+			action_name, action_label,
+			_("Execute these search parameters"), NULL);
+
+		g_object_set_data_full (
+			G_OBJECT (action),
+			"rule", g_object_ref (rule),
+			(GDestroyNotify) g_object_unref);
+
+		g_signal_connect (
+			action, "activate",
+			G_CALLBACK (action_custom_rule_cb), shell_window);
+
+		gtk_action_group_add_action (action_group, action);
+
+		gtk_ui_manager_add_ui (
+			ui_manager, merge_id,
+			"/main-menu/search-menu/custom-rules",
+			action_name, action_name,
+			GTK_UI_MANAGER_AUTO, FALSE);
+
+		g_free (action_name);
+		g_free (action_label);
+
+		rule = rule_context_next_rule (context, rule, source);
+	}
+}

Modified: branches/kill-bonobo/shell/e-shell-window-actions.h
==============================================================================
--- branches/kill-bonobo/shell/e-shell-window-actions.h	(original)
+++ branches/kill-bonobo/shell/e-shell-window-actions.h	Mon Sep 22 21:03:28 2008
@@ -64,6 +64,8 @@
 	E_SHELL_WINDOW_ACTION ((window), "search-edit")
 #define E_SHELL_WINDOW_ACTION_SEARCH_EXECUTE(window) \
 	E_SHELL_WINDOW_ACTION ((window), "search-execute")
+#define E_SHELL_WINDOW_ACTION_SEARCH_OPTIONS(window) \
+	E_SHELL_WINDOW_ACTION ((window), "search-options")
 #define E_SHELL_WINDOW_ACTION_SEARCH_SAVE(window) \
 	E_SHELL_WINDOW_ACTION ((window), "search-save")
 #define E_SHELL_WINDOW_ACTION_SEND_RECEIVE(window) \
@@ -88,6 +90,8 @@
 	E_SHELL_WINDOW_ACTION ((window), "work-online")
 
 /* Action Groups */
+#define E_SHELL_WINDOW_ACTION_GROUP_CUSTOM_RULES(window) \
+	E_SHELL_WINDOW_ACTION_GROUP ((window), "custom-rules")
 #define E_SHELL_WINDOW_ACTION_GROUP_GAL_VIEW(window) \
 	E_SHELL_WINDOW_ACTION_GROUP ((window), "gal-view")
 #define E_SHELL_WINDOW_ACTION_GROUP_NEW_ITEM(window) \

Modified: branches/kill-bonobo/shell/e-shell-window-private.c
==============================================================================
--- branches/kill-bonobo/shell/e-shell-window-private.c	(original)
+++ branches/kill-bonobo/shell/e-shell-window-private.c	Mon Sep 22 21:03:28 2008
@@ -191,11 +191,15 @@
 	priv->gal_view_actions = gtk_action_group_new ("gal-view");
 	priv->new_item_actions = gtk_action_group_new ("new-item");
 	priv->new_source_actions = gtk_action_group_new ("new-source");
+	priv->custom_rule_actions = gtk_action_group_new ("custom-rules");
 	priv->switcher_actions = gtk_action_group_new ("switcher");
 	priv->loaded_views = loaded_views;
 	priv->active_view = "unknown";
 
 	merge_id = gtk_ui_manager_new_merge_id (priv->ui_manager);
+	priv->custom_rule_merge_id = merge_id;
+
+	merge_id = gtk_ui_manager_new_merge_id (priv->ui_manager);
 	priv->gal_view_merge_id = merge_id;
 
 	e_shell_window_actions_init (shell_window);
@@ -369,6 +373,7 @@
 	DISPOSE (priv->gal_view_actions);
 	DISPOSE (priv->new_item_actions);
 	DISPOSE (priv->new_source_actions);
+	DISPOSE (priv->custom_rule_actions);
 	DISPOSE (priv->switcher_actions);
 
 	g_hash_table_remove_all (priv->loaded_views);
@@ -426,6 +431,7 @@
 	e_shell_window_update_title (shell_window);
 	e_shell_window_update_new_menu (shell_window);
 	e_shell_window_update_view_menu (shell_window);
+	e_shell_window_update_search_menu (shell_window);
 
 	/* Notify all loaded views. */
 	list = g_hash_table_get_values (shell_window->priv->loaded_views);

Modified: branches/kill-bonobo/shell/e-shell-window-private.h
==============================================================================
--- branches/kill-bonobo/shell/e-shell-window-private.h	(original)
+++ branches/kill-bonobo/shell/e-shell-window-private.h	Mon Sep 22 21:03:28 2008
@@ -28,7 +28,6 @@
 
 #include <e-util/e-util.h>
 #include <e-util/gconf-bridge.h>
-#include <filter/rule-editor.h>
 #include <widgets/misc/e-menu-tool-button.h>
 #include <widgets/misc/e-online-button.h>
 #include <widgets/misc/e-search-bar.h>
@@ -73,7 +72,9 @@
 	GtkActionGroup *gal_view_actions;
 	GtkActionGroup *new_item_actions;
 	GtkActionGroup *new_source_actions;
+	GtkActionGroup *custom_rule_actions;
 	GtkActionGroup *switcher_actions;
+	guint custom_rule_merge_id;
 	guint gal_view_merge_id;
 
 	/*** Shell Views ***/
@@ -118,6 +119,8 @@
 void		e_shell_window_update_title	(EShellWindow *shell_window);
 void		e_shell_window_update_new_menu	(EShellWindow *shell_window);
 void		e_shell_window_update_view_menu	(EShellWindow *shell_window);
+void		e_shell_window_update_search_menu
+						(EShellWindow *shell_window);
 
 G_END_DECLS
 

Modified: branches/kill-bonobo/ui/evolution-contacts.ui
==============================================================================
--- branches/kill-bonobo/ui/evolution-contacts.ui	(original)
+++ branches/kill-bonobo/ui/evolution-contacts.ui	Mon Sep 22 21:03:28 2008
@@ -74,4 +74,11 @@
     <menuitem action='contact-clipboard-paste'/>
     <menuitem action='contact-delete'/>
   </popup>
+  <popup name='contact-search-options'>
+    <menuitem action='contact-search-name-contains'/>
+    <menuitem action='contact-search-email-begins-with'/>
+    <menuitem action='contact-search-any-field-contains'/>
+    <separator/>
+    <menuitem action='search-advanced'/>
+  </popup>
 </ui>

Modified: branches/kill-bonobo/ui/evolution-shell.ui
==============================================================================
--- branches/kill-bonobo/ui/evolution-shell.ui	(original)
+++ branches/kill-bonobo/ui/evolution-shell.ui	Mon Sep 22 21:03:28 2008
@@ -56,6 +56,10 @@
       <separator/>
       <menuitem action='search-save'/>
       <menuitem action='search-edit'/>
+      <separator/>
+      <placeholder name='search-actions'/>
+      <separator/>
+      <placeholder name='custom-rules'/>
     </menu>
     <menu action='help-menu'>
       <menuitem action='contents'/>

Modified: branches/kill-bonobo/widgets/misc/e-icon-entry.c
==============================================================================
--- branches/kill-bonobo/widgets/misc/e-icon-entry.c	(original)
+++ branches/kill-bonobo/widgets/misc/e-icon-entry.c	Mon Sep 22 21:03:28 2008
@@ -39,10 +39,16 @@
 	((obj), E_TYPE_ICON_ENTRY, EIconEntryPrivate))
 
 struct _EIconEntryPrivate {
+	GtkStateType visual_state;
 	GtkWidget *entry;
 	GtkWidget *hbox;
 };
 
+enum {
+	PROP_0,
+	PROP_VISUAL_STATE
+};
+
 static gpointer parent_class;
 
 static void
@@ -64,6 +70,7 @@
 {
 	GtkWidget *proxy;
 	GtkWidget *widget;
+	gchar *tooltip;
 
 	proxy = gtk_event_box_new ();
 	gtk_event_box_set_visible_window (GTK_EVENT_BOX (proxy), FALSE);
@@ -74,6 +81,10 @@
 	gtk_container_add (GTK_CONTAINER (proxy), widget);
 	gtk_widget_show (widget);
 
+	g_object_get (action, "tooltip", &tooltip, NULL);
+	gtk_widget_set_tooltip_text (proxy, tooltip);
+	g_free (tooltip);
+
 	g_signal_connect_swapped (
 		proxy, "button-press-event",
 		G_CALLBACK (gtk_action_activate), action);
@@ -122,55 +133,90 @@
 
 static void
 icon_entry_paint (GtkWidget *widget,
-		       GdkEventExpose *event)
+                  GdkEventExpose *event)
 {
 	EIconEntry *entry = E_ICON_ENTRY (widget);
 	GtkWidget *entry_widget = entry->priv->entry;
 	int x = 0, y = 0, width, height, focus_width;
 	gboolean interior_focus;
 
-	gtk_widget_style_get (entry_widget,
-			      "interior-focus", &interior_focus,
-			      "focus-line-width", &focus_width,
-			      NULL);
+	gtk_widget_style_get (
+		entry_widget,
+		"interior-focus", &interior_focus,
+		"focus-line-width", &focus_width, NULL);
 
 	gdk_drawable_get_size (widget->window, &width, &height);
 
-	if (GTK_WIDGET_HAS_FOCUS (entry_widget) && !interior_focus)
-	{
+	if (GTK_WIDGET_HAS_FOCUS (entry_widget) && !interior_focus) {
 		x += focus_width;
 		y += focus_width;
 		width -= 2 * focus_width;
 		height -= 2 * focus_width;
 	}
 
-	gtk_paint_flat_box (entry_widget->style, widget->window,
-			    GTK_WIDGET_STATE (entry_widget), GTK_SHADOW_NONE,
-			    NULL, entry_widget, "entry_bg",
-			    /* FIXME: was 0, 0 in gtk_entry_expose, but I think this is correct: */
-			    x, y, width, height);
-
-	gtk_paint_shadow (entry_widget->style, widget->window,
-			  GTK_STATE_NORMAL, GTK_SHADOW_IN,
-			  NULL, entry_widget, "entry",
-			  x, y, width, height);
+	gtk_paint_flat_box (
+		entry_widget->style, widget->window,
+		GTK_WIDGET_STATE (entry_widget), GTK_SHADOW_NONE,
+		NULL, entry_widget, "entry_bg",
+		/* FIXME: was 0, 0 in gtk_entry_expose, but I think this is correct: */
+		x, y, width, height);
+
+	gtk_paint_shadow (
+		entry_widget->style, widget->window,
+		GTK_STATE_NORMAL, GTK_SHADOW_IN,
+		NULL, entry_widget, "entry",
+		x, y, width, height);
 
-	if (GTK_WIDGET_HAS_FOCUS (entry_widget) && !interior_focus)
-	{
+	if (GTK_WIDGET_HAS_FOCUS (entry_widget) && !interior_focus) {
 		x -= focus_width;
 		y -= focus_width;
 		width += 2 * focus_width;
 		height += 2 * focus_width;
 
-		gtk_paint_focus (entry_widget->style, widget->window,
-				 GTK_WIDGET_STATE (entry_widget),
-				 NULL, entry_widget, "entry",
-				 /* FIXME: was 0, 0 in gtk_entry_draw_frame, but I think this is correct: */
-				 x, y, width, height);
+		gtk_paint_focus (
+			entry_widget->style, widget->window,
+			GTK_WIDGET_STATE (entry_widget),
+			NULL, entry_widget, "entry",
+			/* FIXME: was 0, 0 in gtk_entry_draw_frame, but I think this is correct: */
+			x, y, width, height);
 	}
 }
 
 static void
+icon_entry_set_property (GObject *object,
+                         guint property_id,
+                         const GValue *value,
+                         GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_VISUAL_STATE:
+			e_icon_entry_set_visual_state (
+				E_ICON_ENTRY (object),
+				g_value_get_enum (value));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+icon_entry_get_property (GObject *object,
+                         guint property_id,
+                         GValue *value,
+                         GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_VISUAL_STATE:
+			g_value_set_enum (
+				value, e_icon_entry_get_visual_state (
+				E_ICON_ENTRY (object)));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
 icon_entry_dispose (GObject *object)
 {
 	EIconEntryPrivate *priv;
@@ -324,6 +370,8 @@
 	g_type_class_add_private (class, sizeof (EIconEntryPrivate));
 
 	object_class = G_OBJECT_CLASS (class);
+	object_class->set_property = icon_entry_set_property;
+	object_class->get_property = icon_entry_get_property;
 	object_class->dispose = icon_entry_dispose;
 
 	widget_class = GTK_WIDGET_CLASS (class);
@@ -331,6 +379,17 @@
 	widget_class->size_request = icon_entry_size_request;
 	widget_class->size_allocate = icon_entry_size_allocate;
 	widget_class->expose_event = icon_entry_expose;
+
+	g_object_class_install_property (
+		object_class,
+		PROP_VISUAL_STATE,
+		g_param_spec_enum (
+			"visual-state",
+			NULL,
+			NULL,
+			GTK_TYPE_STATE_TYPE,
+			GTK_STATE_NORMAL,
+			G_PARAM_READWRITE));
 }
 
 static void
@@ -340,6 +399,7 @@
 	GtkWidget *container;
 
 	icon_entry->priv = E_ICON_ENTRY_GET_PRIVATE (icon_entry);
+	icon_entry->priv->visual_state = GTK_STATE_NORMAL;
 
 	GTK_WIDGET_UNSET_FLAGS (icon_entry, GTK_NO_WINDOW);
 
@@ -438,3 +498,46 @@
 	proxy = icon_entry_create_proxy (action);
 	gtk_box_pack_end (box, proxy, FALSE, FALSE, 2);
 }
+
+GtkStateType
+e_icon_entry_get_visual_state (EIconEntry *icon_entry)
+{
+	g_return_val_if_fail (E_IS_ICON_ENTRY (icon_entry), GTK_STATE_NORMAL);
+
+	return icon_entry->priv->visual_state;
+}
+
+void
+e_icon_entry_set_visual_state (EIconEntry *icon_entry,
+                               GtkStateType visual_state)
+{
+	GtkWidget *widget;
+	const GdkColor *base_color;
+	const GdkColor *text_color;
+
+	g_return_if_fail (E_IS_ICON_ENTRY (icon_entry));
+
+	if (visual_state == GTK_STATE_NORMAL) {
+		base_color = NULL;
+		text_color = NULL;
+	} else {
+		GtkStyle *style;
+
+		style = gtk_widget_get_default_style ();
+		base_color = &style->base[visual_state];
+		text_color = &style->text[visual_state];
+	}
+
+	widget = GTK_WIDGET (icon_entry);
+	gtk_widget_modify_base (widget, GTK_STATE_NORMAL, base_color);
+
+	widget = icon_entry->priv->entry;
+	gtk_widget_modify_base (widget, GTK_STATE_NORMAL, base_color);
+	gtk_widget_modify_text (widget, GTK_STATE_NORMAL, text_color);
+
+	widget = icon_entry->priv->hbox;
+	gtk_widget_modify_base (widget, GTK_STATE_NORMAL, base_color);
+
+	icon_entry->priv->visual_state = visual_state;
+	g_object_notify (G_OBJECT (icon_entry), "visual-state");
+}

Modified: branches/kill-bonobo/widgets/misc/e-icon-entry.h
==============================================================================
--- branches/kill-bonobo/widgets/misc/e-icon-entry.h	(original)
+++ branches/kill-bonobo/widgets/misc/e-icon-entry.h	Mon Sep 22 21:03:28 2008
@@ -82,6 +82,9 @@
 						 GtkAction *action);
 void		e_icon_entry_add_action_end	(EIconEntry *entry,
 						 GtkAction *action);
+GtkStateType	e_icon_entry_get_visual_state	(EIconEntry *entry);
+void		e_icon_entry_set_visual_state	(EIconEntry *entry,
+                                                 GtkStateType visual_state);
 
 G_END_DECLS
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]