aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthew Barnes <mbarnes@src.gnome.org>2008-09-23 05:03:28 +0800
committerMatthew Barnes <mbarnes@src.gnome.org>2008-09-23 05:03:28 +0800
commit73c370019c4de89d4c901ee8c25cc0cbb55992fb (patch)
tree26609470a1148d3bd364cbce5d5ab2f41e0e23d4
parent6b2295c93a40f6010d94399666a8e099aded8e85 (diff)
downloadgsoc2013-evolution-73c370019c4de89d4c901ee8c25cc0cbb55992fb.tar.gz
gsoc2013-evolution-73c370019c4de89d4c901ee8c25cc0cbb55992fb.tar.zst
gsoc2013-evolution-73c370019c4de89d4c901ee8c25cc0cbb55992fb.zip
Search UI is kinda sorta working. Still some outstanding issues.
svn path=/branches/kill-bonobo/; revision=36427
-rw-r--r--addressbook/gui/component/addressbook-component.c18
-rw-r--r--addressbook/gui/component/e-book-shell-module.c31
-rw-r--r--addressbook/gui/component/e-book-shell-view-actions.c126
-rw-r--r--addressbook/gui/component/e-book-shell-view-actions.h2
-rw-r--r--addressbook/gui/component/e-book-shell-view-private.c48
-rw-r--r--addressbook/gui/component/e-book-shell-view-private.h1
-rw-r--r--addressbook/gui/component/e-book-shell-view.c3
-rw-r--r--doc/reference/shell/tmpl/e-shell-content.sgml4
-rw-r--r--doc/reference/shell/tmpl/eshell-unused.sgml6
-rw-r--r--e-util/e-util.c11
-rw-r--r--e-util/e-util.h2
-rw-r--r--shell/Makefile.am2
-rw-r--r--shell/e-shell-content.c411
-rw-r--r--shell/e-shell-content.h17
-rw-r--r--shell/e-shell-sidebar.h2
-rw-r--r--shell/e-shell-switcher.h2
-rw-r--r--shell/e-shell-view.h3
-rw-r--r--shell/e-shell-window-actions.c193
-rw-r--r--shell/e-shell-window-actions.h4
-rw-r--r--shell/e-shell-window-private.c6
-rw-r--r--shell/e-shell-window-private.h5
-rw-r--r--ui/evolution-contacts.ui7
-rw-r--r--ui/evolution-shell.ui4
-rw-r--r--widgets/misc/e-icon-entry.c149
-rw-r--r--widgets/misc/e-icon-entry.h3
25 files changed, 829 insertions, 231 deletions
diff --git a/addressbook/gui/component/addressbook-component.c b/addressbook/gui/component/addressbook-component.c
index 5c3ad0999f..49e138e0de 100644
--- a/addressbook/gui/component/addressbook-component.c
+++ b/addressbook/gui/component/addressbook-component.c
@@ -92,25 +92,7 @@ addressbook_component_class_init (AddressbookComponentClass *class)
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);
- }
}
diff --git a/addressbook/gui/component/e-book-shell-module.c b/addressbook/gui/component/e-book-shell-module.c
index 1b3e778ce8..480320185e 100644
--- a/addressbook/gui/component/e-book-shell-module.c
+++ b/addressbook/gui/component/e-book-shell-module.c
@@ -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 @@ book_module_ensure_sources (EShellModule *shell_module)
}
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_init (GTypeModule *type_module)
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);
diff --git a/addressbook/gui/component/e-book-shell-view-actions.c b/addressbook/gui/component/e-book-shell-view-actions.c
index 89ca2c22a8..e27474aac0 100644
--- a/addressbook/gui/component/e-book-shell-view-actions.c
+++ b/addressbook/gui/component/e-book-shell-view-actions.c
@@ -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 @@ static void
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 @@ action_search_execute_cb (GtkAction *action,
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 @@ action_search_execute_cb (GtkAction *action,
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 @@ action_search_execute_cb (GtkAction *action,
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 @@ e_book_shell_view_actions_init (EBookShellView *book_shell_view)
EShellView *shell_view;
EShellWindow *shell_window;
GtkActionGroup *action_group;
- GtkUIManager *manager;
+ GtkUIManager *ui_manager;
GConfBridge *bridge;
GtkAction *action;
GObject *object;
@@ -740,11 +751,12 @@ e_book_shell_view_actions_init (EBookShellView *book_shell_view)
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 @@ e_book_shell_view_actions_init (EBookShellView *book_shell_view)
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 @@ e_book_shell_view_actions_update (EBookShellView *book_shell_view)
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);
+}
diff --git a/addressbook/gui/component/e-book-shell-view-actions.h b/addressbook/gui/component/e-book-shell-view-actions.h
index a809eeacf9..8119d7440c 100644
--- a/addressbook/gui/component/e-book-shell-view-actions.h
+++ b/addressbook/gui/component/e-book-shell-view-actions.h
@@ -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 */
diff --git a/addressbook/gui/component/e-book-shell-view-private.c b/addressbook/gui/component/e-book-shell-view-private.c
index 68d8425ef8..4dd88e7758 100644
--- a/addressbook/gui/component/e-book-shell-view-private.c
+++ b/addressbook/gui/component/e-book-shell-view-private.c
@@ -262,12 +262,6 @@ book_shell_view_show_popup_menu (GdkEventButton *event,
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 @@ e_book_shell_view_private_init (EBookShellView *book_shell_view,
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 @@ e_book_shell_view_private_constructed (EBookShellView *book_shell_view)
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 @@ e_book_shell_view_private_dispose (EBookShellView *book_shell_view)
DISPOSE (priv->source_list);
DISPOSE (priv->contact_actions);
+ DISPOSE (priv->filter_actions);
DISPOSE (priv->paned);
DISPOSE (priv->notebook);
@@ -543,41 +539,3 @@ e_book_shell_view_editor_weak_notify (EditorUidClosure *closure,
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);
-}
diff --git a/addressbook/gui/component/e-book-shell-view-private.h b/addressbook/gui/component/e-book-shell-view-private.h
index 24af21539b..f4a9d25b91 100644
--- a/addressbook/gui/component/e-book-shell-view-private.h
+++ b/addressbook/gui/component/e-book-shell-view-private.h
@@ -86,6 +86,7 @@ struct _EBookShellViewPrivate {
/*** UI Management ***/
GtkActionGroup *contact_actions;
+ GtkActionGroup *filter_actions;
/*** Other Stuff ***/
diff --git a/addressbook/gui/component/e-book-shell-view.c b/addressbook/gui/component/e-book-shell-view.c
index 9a90b1d1f5..c2b8450b79 100644
--- a/addressbook/gui/component/e-book-shell-view.c
+++ b/addressbook/gui/component/e-book-shell-view.c
@@ -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 @@ book_shell_view_class_init (EBookShellViewClass *class,
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 (
diff --git a/doc/reference/shell/tmpl/e-shell-content.sgml b/doc/reference/shell/tmpl/e-shell-content.sgml
index 3172527ad6..bb62b33070 100644
--- a/doc/reference/shell/tmpl/e-shell-content.sgml
+++ b/doc/reference/shell/tmpl/e-shell-content.sgml
@@ -53,12 +53,12 @@ EShellContent
</para>
-<!-- ##### ARG EShellContent:search-action ##### -->
+<!-- ##### ARG EShellContent:search-context ##### -->
<para>
</para>
-<!-- ##### ARG EShellContent:search-context ##### -->
+<!-- ##### ARG EShellContent:search-rule ##### -->
<para>
</para>
diff --git a/doc/reference/shell/tmpl/eshell-unused.sgml b/doc/reference/shell/tmpl/eshell-unused.sgml
index 448bdb8fcf..b18730bd1e 100644
--- a/doc/reference/shell/tmpl/eshell-unused.sgml
+++ b/doc/reference/shell/tmpl/eshell-unused.sgml
@@ -406,6 +406,12 @@ intelligent
@minor:
@revision:
+<!-- ##### ARG EShellContent:search-action ##### -->
+<para>
+
+</para>
+
+
<!-- ##### STRUCT EShellContentPrivate ##### -->
<para>
diff --git a/e-util/e-util.c b/e-util/e-util.c
index cec2ec1b69..0055407068 100644
--- a/e-util/e-util.c
+++ b/e-util/e-util.c
@@ -107,10 +107,10 @@ e_display_help (GtkWindow *parent,
/**
* 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 @@ e_display_help (GtkWindow *parent,
* 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)
diff --git a/e-util/e-util.h b/e-util/e-util.h
index d1a76c8ea6..a6aaa19a99 100644
--- a/e-util/e-util.h
+++ b/e-util/e-util.h
@@ -44,7 +44,7 @@ typedef enum {
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);
diff --git a/shell/Makefile.am b/shell/Makefile.am
index 3afa351426..0603f603fa 100644
--- a/shell/Makefile.am
+++ b/shell/Makefile.am
@@ -17,7 +17,7 @@ INCLUDES = \
-DEVOLUTION_GLADEDIR=\""$(gladedir)"\" \
-DEVOLUTION_HELPDIR=\""$(evolutionhelpdir)"\" \
-DEVOLUTION_MODULEDIR=\""$(moduledir)"\" \
- -DEVOLUTION_RULEDIR=\""$(ruledir)"\" \
+ -DEVOLUTION_RULEDIR=\""$(privdatadir)"\" \
-DEVOLUTION_UIDIR=\""$(evolutionuidir)"\" \
-DEVOLUTION_TOOLSDIR=\""$(privlibexecdir)"\" \
-DPREFIX=\""$(prefix)"\" \
diff --git a/shell/e-shell-content.c b/shell/e-shell-content.c
index 95cdc2d1cc..c16344ac15 100644
--- a/shell/e-shell-content.c
+++ b/shell/e-shell-content.c
@@ -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 @@ struct _EShellContentPrivate {
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 @@ struct _EShellContentPrivate {
GtkWidget *scope_combo_box;
GtkStateType search_state;
-
- GtkRadioAction *search_action;
- GtkWidget *search_popup_menu;
};
enum {
@@ -62,8 +62,8 @@ enum {
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 @@ enum {
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 @@ shell_content_entry_changed_cb (EShellContent *shell_content,
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 @@ shell_content_entry_focus_in_cb (EShellContent *shell_content,
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 @@ shell_content_entry_key_press_cb (EShellContent *shell_content,
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 @@ shell_content_init_search_context (EShellContent *shell_content)
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 @@ shell_content_init_search_context (EShellContent *shell_content)
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 @@ shell_content_set_property (GObject *object,
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 @@ shell_content_get_property (GObject *object,
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 @@ shell_content_dispose (GObject *object)
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 @@ 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;
widget_class = GTK_WIDGET_CLASS (class);
widget_class->realize = shell_content_realize;
@@ -614,23 +701,23 @@ shell_content_class_init (EShellContentClass *class)
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 @@ shell_content_init (EShellContent *shell_content)
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 @@ e_shell_content_set_filter_visible (EShellContent *shell_content,
}
}
-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_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_action;
+ 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 @@ e_shell_content_set_scope_visible (EShellContent *shell_content,
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);
+}
diff --git a/shell/e-shell-content.h b/shell/e-shell-content.h
index 6f4c83338a..1763bf4b22 100644
--- a/shell/e-shell-content.h
+++ b/shell/e-shell-content.h
@@ -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 @@ gboolean e_shell_content_get_filter_visible
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 @@ void e_shell_content_save_search_dialog
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
diff --git a/shell/e-shell-sidebar.h b/shell/e-shell-sidebar.h
index a6a67a40cc..9a27cba6b5 100644
--- a/shell/e-shell-sidebar.h
+++ b/shell/e-shell-sidebar.h
@@ -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 \
diff --git a/shell/e-shell-switcher.h b/shell/e-shell-switcher.h
index 67201279d2..499372f81e 100644
--- a/shell/e-shell-switcher.h
+++ b/shell/e-shell-switcher.h
@@ -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 \
diff --git a/shell/e-shell-view.h b/shell/e-shell-view.h
index 32fd4333f0..92382a9a49 100644
--- a/shell/e-shell-view.h
+++ b/shell/e-shell-view.h
@@ -72,6 +72,9 @@ struct _EShellViewClass {
/* 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);
diff --git a/shell/e-shell-window-actions.c b/shell/e-shell-window-actions.c
index f03c775b3d..5375774702 100644
--- a/shell/e-shell-window-actions.c
+++ b/shell/e-shell-window-actions.c
@@ -674,6 +674,29 @@ action_contents_cb (GtkAction *action,
}
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 @@ static void
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 @@ static GtkActionEntry shell_entries[] = {
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 @@ e_shell_window_actions_init (EShellWindow *shell_window)
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 @@ e_shell_window_update_view_menu (EShellWindow *shell_window)
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);
+ }
+}
diff --git a/shell/e-shell-window-actions.h b/shell/e-shell-window-actions.h
index 2e3595f0f7..858c8541ce 100644
--- a/shell/e-shell-window-actions.h
+++ b/shell/e-shell-window-actions.h
@@ -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) \
diff --git a/shell/e-shell-window-private.c b/shell/e-shell-window-private.c
index 8bfdefc536..782616cea4 100644
--- a/shell/e-shell-window-private.c
+++ b/shell/e-shell-window-private.c
@@ -191,11 +191,15 @@ e_shell_window_private_init (EShellWindow *shell_window)
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 @@ e_shell_window_private_dispose (EShellWindow *shell_window)
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_switch_to_view (EShellWindow *shell_window,
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);
diff --git a/shell/e-shell-window-private.h b/shell/e-shell-window-private.h
index e496a9834e..ed784b2ac7 100644
--- a/shell/e-shell-window-private.h
+++ b/shell/e-shell-window-private.h
@@ -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 @@ struct _EShellWindowPrivate {
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_icon (EShellWindow *shell_window);
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
diff --git a/ui/evolution-contacts.ui b/ui/evolution-contacts.ui
index 7d2379467a..ee97af7169 100644
--- a/ui/evolution-contacts.ui
+++ b/ui/evolution-contacts.ui
@@ -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>
diff --git a/ui/evolution-shell.ui b/ui/evolution-shell.ui
index 633703f24a..e2f33f8307 100644
--- a/ui/evolution-shell.ui
+++ b/ui/evolution-shell.ui
@@ -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'/>
diff --git a/widgets/misc/e-icon-entry.c b/widgets/misc/e-icon-entry.c
index 1c9ed12d96..86e42488a7 100644
--- a/widgets/misc/e-icon-entry.c
+++ b/widgets/misc/e-icon-entry.c
@@ -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 @@ icon_entry_create_proxy (GtkAction *action)
{
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 @@ icon_entry_create_proxy (GtkAction *action)
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 @@ icon_entry_get_borders (GtkWidget *widget,
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_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_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 @@ icon_entry_class_init (EIconEntryClass *class)
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 @@ icon_entry_class_init (EIconEntryClass *class)
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 @@ icon_entry_init (EIconEntry *icon_entry)
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 @@ e_icon_entry_add_action_end (EIconEntry *icon_entry,
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");
+}
diff --git a/widgets/misc/e-icon-entry.h b/widgets/misc/e-icon-entry.h
index 110720ab19..65aff61978 100644
--- a/widgets/misc/e-icon-entry.h
+++ b/widgets/misc/e-icon-entry.h
@@ -82,6 +82,9 @@ void e_icon_entry_add_action_start (EIconEntry *entry,
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