diff options
author | Matthew Barnes <mbarnes@redhat.com> | 2009-12-19 07:23:48 +0800 |
---|---|---|
committer | Matthew Barnes <mbarnes@redhat.com> | 2009-12-19 11:38:00 +0800 |
commit | 4cbbdedf522a6ac10df93a128bbf25f67173d66e (patch) | |
tree | fab7bf95e0927e4fa98c58a659e310afff7153ee /shell | |
parent | a1efb837566cdac798cd8777dd34e06e9782cf61 (diff) | |
download | gsoc2013-evolution-4cbbdedf522a6ac10df93a128bbf25f67173d66e.tar.gz gsoc2013-evolution-4cbbdedf522a6ac10df93a128bbf25f67173d66e.tar.zst gsoc2013-evolution-4cbbdedf522a6ac10df93a128bbf25f67173d66e.zip |
Refactor the EShell search API.
Move the search interface to a new widget: EShellSearchbar
The current search rule is now stored in EShellView, and the search
context in EShellViewClass similar to GalViewCollection (since it's
class-specific, not instance-specific).
Also add a couple new signals to EShellView: "clear-search" and
"custom-search" ("custom" refers to an advanced search or a saved
search -- something more complex than a quick search).
Still working out a few kinks. The search entry is clearly trying to
be too many things. We need a different way of indicating that you're
looking at search results. Perhaps a search results banner similar to
Nautilus.
Diffstat (limited to 'shell')
-rw-r--r-- | shell/Makefile.am | 2 | ||||
-rw-r--r-- | shell/e-shell-content.c | 1334 | ||||
-rw-r--r-- | shell/e-shell-content.h | 67 | ||||
-rw-r--r-- | shell/e-shell-searchbar.c | 1053 | ||||
-rw-r--r-- | shell/e-shell-searchbar.h | 119 | ||||
-rw-r--r-- | shell/e-shell-view.c | 292 | ||||
-rw-r--r-- | shell/e-shell-view.h | 33 | ||||
-rw-r--r-- | shell/e-shell-window-actions.c | 36 |
8 files changed, 1618 insertions, 1318 deletions
diff --git a/shell/Makefile.am b/shell/Makefile.am index 2dee1b2206..876b945f8f 100644 --- a/shell/Makefile.am +++ b/shell/Makefile.am @@ -22,6 +22,7 @@ eshellinclude_HEADERS = \ e-shell-backend.h \ e-shell-common.h \ e-shell-content.h \ + e-shell-searchbar.h \ e-shell-settings.h \ e-shell-sidebar.h \ e-shell-switcher.h \ @@ -64,6 +65,7 @@ libeshell_la_SOURCES = \ e-shell.c \ e-shell-backend.c \ e-shell-content.c \ + e-shell-searchbar.c \ e-shell-settings.c \ e-shell-sidebar.c \ e-shell-switcher.c \ diff --git a/shell/e-shell-content.c b/shell/e-shell-content.c index 6a883d5230..bc24b22222 100644 --- a/shell/e-shell-content.c +++ b/shell/e-shell-content.c @@ -31,6 +31,7 @@ #include "widgets/misc/e-hinted-entry.h" #include "e-shell-backend.h" +#include "e-shell-searchbar.h" #include "e-shell-view.h" #include "e-shell-window-actions.h" @@ -38,46 +39,18 @@ (G_TYPE_INSTANCE_GET_PRIVATE \ ((obj), E_TYPE_SHELL_CONTENT, EShellContentPrivate)) -#define STATE_KEY_SEARCH_FILTER "SearchFilter" -#define STATE_KEY_SEARCH_SCOPE "SearchScope" -#define STATE_KEY_SEARCH_TEXT "SearchText" - struct _EShellContentPrivate { gpointer shell_view; /* weak pointer */ - ERuleContext *search_context; - EFilterRule *search_rule; - gchar *system_filename; - gchar *user_filename; - - GtkWidget *search_bar; + GtkWidget *searchbar; - /* Search bar children (not referenced) */ - GtkWidget *filter_combo_box; - GtkWidget *search_entry; - GtkWidget *scope_combo_box; - GtkRadioAction *search_radio; /* to be able to manage radio here */ - - guint filter_visible : 1; - guint search_visible : 1; - guint scope_visible : 1; + /* Custom search rules. */ + gchar *user_filename; }; enum { PROP_0, - PROP_FILTER_ACTION, - PROP_FILTER_VALUE, - PROP_FILTER_VISIBLE, - PROP_SEARCH_CONTEXT, - PROP_SEARCH_HINT, - PROP_SEARCH_RULE, - PROP_SEARCH_TEXT, - PROP_SEARCH_VISIBLE, - PROP_SCOPE_ACTION, - PROP_SCOPE_VALUE, - PROP_SCOPE_VISIBLE, - PROP_SEARCH_RADIO_ACTION, PROP_SHELL_VIEW }; @@ -98,269 +71,6 @@ shell_content_dialog_rule_changed (GtkWidget *dialog, } static void -shell_content_update_search_widgets (EShellContent *shell_content) -{ - EShellView *shell_view; - EShellWindow *shell_window; - GtkAction *action; - GtkWidget *widget; - const gchar *search_text; - gboolean sensitive; - - g_return_if_fail (shell_content != NULL); - - shell_view = e_shell_content_get_shell_view (shell_content); - g_return_if_fail (shell_view != NULL); - - /* EShellView subclasses are responsible for actually - * executing the search. This is all cosmetic stuff. */ - - widget = shell_content->priv->search_entry; - shell_window = e_shell_view_get_shell_window (shell_view); - search_text = e_shell_content_get_search_text (shell_content); - - sensitive = - (search_text != NULL && *search_text != '\0') || - (e_shell_content_get_search_rule (shell_content) != NULL); - - if (sensitive) { - GtkStyle *style; - const GdkColor *fg_color, *bg_color; - - style = gtk_widget_get_style (widget); - fg_color = &style->text[(search_text != NULL && *search_text != '\0') ? GTK_STATE_SELECTED : GTK_STATE_INSENSITIVE]; - bg_color = &style->mid[GTK_STATE_SELECTED]; - - if (gdk_color_equal (fg_color, bg_color)) - bg_color = &style->base[GTK_STATE_SELECTED]; - - gtk_widget_modify_base (widget, GTK_STATE_NORMAL, bg_color); - gtk_widget_modify_text (widget, GTK_STATE_NORMAL, fg_color); - } else { - /* Text color will be updated when we move the focus. */ - gtk_widget_modify_base (widget, GTK_STATE_NORMAL, NULL); - } - - action = E_SHELL_WINDOW_ACTION_SEARCH_CLEAR (shell_window); - gtk_action_set_sensitive (action, sensitive); - - action = E_SHELL_WINDOW_ACTION_SEARCH_SAVE (shell_window); - gtk_action_set_sensitive (action, sensitive); -} - -static void -shell_content_execute_search_cb (EShellView *shell_view, - EShellContent *shell_content) -{ - GtkWidget *widget; - - shell_content_update_search_widgets (shell_content); - - if (!e_shell_view_is_active (shell_view)) - return; - - /* Direct the focus away from the search entry, so that a - * focus-in event is required before the text can be changed. - * This will reset the entry to the appropriate visual state. */ - widget = gtk_bin_get_child (GTK_BIN (shell_content)); - if (GTK_IS_PANED (widget)) - widget = gtk_paned_get_child1 (GTK_PANED (widget)); - gtk_widget_grab_focus (widget); -} - -static void -shell_content_entry_activate_cb (EShellContent *shell_content, - GtkEntry *entry) -{ - EShellView *shell_view; - EShellWindow *shell_window; - GtkAction *action; - const gchar *text; - - shell_view = e_shell_content_get_shell_view (shell_content); - shell_window = e_shell_view_get_shell_window (shell_view); - - text = gtk_entry_get_text (entry); - if (text && *text) - action = E_SHELL_WINDOW_ACTION_SEARCH_QUICK (shell_window); - else - action = E_SHELL_WINDOW_ACTION_SEARCH_CLEAR (shell_window); - - gtk_action_activate (action); -} - -static void -shell_content_entry_changed_cb (EShellContent *shell_content, - GtkEntry *entry) -{ - EShellView *shell_view; - EShellWindow *shell_window; - GtkAction *action; - const gchar *text; - gboolean sensitive; - - shell_view = e_shell_content_get_shell_view (shell_content); - shell_window = e_shell_view_get_shell_window (shell_view); - - text = gtk_entry_get_text (entry); - sensitive = (text != NULL && *text != '\0' && !e_hinted_entry_get_hint_shown (E_HINTED_ENTRY (entry))); - - action = E_SHELL_WINDOW_ACTION_SEARCH_QUICK (shell_window); - gtk_action_set_sensitive (action, sensitive); -} - -static void -shell_content_entry_icon_press_cb (EShellContent *shell_content, - GtkEntryIconPosition icon_pos, - GdkEvent *event) -{ - EShellView *shell_view; - EShellWindow *shell_window; - GtkAction *action; - - /* Show the search options menu when the icon is pressed. */ - - if (icon_pos != GTK_ENTRY_ICON_PRIMARY) - return; - - shell_view = e_shell_content_get_shell_view (shell_content); - shell_window = e_shell_view_get_shell_window (shell_view); - - action = E_SHELL_WINDOW_ACTION_SEARCH_OPTIONS (shell_window); - gtk_action_activate (action); -} - -static void -shell_content_entry_icon_release_cb (EShellContent *shell_content, - GtkEntryIconPosition icon_pos, - GdkEvent *event) -{ - EShellView *shell_view; - EShellWindow *shell_window; - GtkAction *action; - - /* Clear the search when the icon is pressed and released. */ - - if (icon_pos != GTK_ENTRY_ICON_SECONDARY) - return; - - shell_view = e_shell_content_get_shell_view (shell_content); - shell_window = e_shell_view_get_shell_window (shell_view); - - action = E_SHELL_WINDOW_ACTION_SEARCH_CLEAR (shell_window); - gtk_action_activate (action); -} - -static gboolean -shell_content_entry_key_press_cb (EShellContent *shell_content, - GdkEventKey *key_event, - GtkWidget *entry) -{ - EShellView *shell_view; - EShellWindow *shell_window; - GtkAction *action; - guint mask; - - mask = gtk_accelerator_get_default_mod_mask (); - if ((key_event->state & mask) != GDK_MOD1_MASK) - return FALSE; - - if (key_event->keyval != GDK_Down) - return FALSE; - - shell_view = e_shell_content_get_shell_view (shell_content); - shell_window = e_shell_view_get_shell_window (shell_view); - - action = E_SHELL_WINDOW_ACTION_SEARCH_OPTIONS (shell_window); - gtk_action_activate (action); - - return TRUE; -} - -static void -shell_content_init_search_context (EShellContent *shell_content) -{ - EShellContentClass *shell_content_class; - EShellView *shell_view; - EShellViewClass *shell_view_class; - EShellBackend *shell_backend; - ERuleContext *context; - EFilterRule *rule; - EFilterPart *part; - gchar *system_filename; - gchar *user_filename; - - shell_view = e_shell_content_get_shell_view (shell_content); - shell_backend = e_shell_view_get_shell_backend (shell_view); - shell_view_class = E_SHELL_VIEW_GET_CLASS (shell_view); - g_return_if_fail (shell_view_class->search_rules != NULL); - - shell_content_class = E_SHELL_CONTENT_GET_CLASS (shell_content); - g_return_if_fail (shell_content_class->new_search_context != NULL); - - /* The basename for built-in searches is specified in the - * shell view class. All built-in search rules live in the - * same directory. */ - system_filename = g_build_filename ( - EVOLUTION_RULEDIR, shell_view_class->search_rules, NULL); - - /* The filename for custom saved searches is always of - * the form "$(shell_backend_data_dir)/searches.xml". */ - user_filename = g_build_filename ( - e_shell_backend_get_data_dir (shell_backend), - "searches.xml", NULL); - - context = shell_content_class->new_search_context (); - e_rule_context_add_part_set ( - context, "partset", E_TYPE_FILTER_PART, - e_rule_context_add_part, e_rule_context_next_part); - e_rule_context_add_rule_set ( - context, "ruleset", E_TYPE_FILTER_RULE, - e_rule_context_add_rule, e_rule_context_next_rule); - e_rule_context_load (context, system_filename, user_filename); - - /* XXX Not sure why this is necessary. */ - g_object_set_data_full ( - G_OBJECT (context), "system", - g_strdup (system_filename), g_free); - g_object_set_data_full ( - G_OBJECT (context), "user", - g_strdup (user_filename), g_free); - - rule = e_filter_rule_new (); - part = e_rule_context_next_part (context, NULL); - if (part == NULL) - g_warning ( - "Could not load %s search: no parts", - e_shell_view_get_name (shell_view)); - else - e_filter_rule_add_part (rule, e_filter_part_clone (part)); - - shell_content->priv->search_context = context; - shell_content->priv->system_filename = system_filename; - shell_content->priv->user_filename = user_filename; -} - -static void -shell_content_activate_advanced_search (EShellContent *shell_content) -{ - GtkRadioAction *radio_action; - const gchar *search_text; - - g_return_if_fail (shell_content != NULL); - g_return_if_fail (shell_content->priv->search_entry != NULL); - - /* cannot mix text search with an Advanced Search, thus unsetting search text */ - search_text = e_shell_content_get_search_text (shell_content); - if (search_text) - e_shell_content_set_search_text (shell_content, NULL); - - radio_action = e_shell_content_get_search_radio_action (shell_content); - if (radio_action) - g_object_set (G_OBJECT (radio_action), "current-value", -1, NULL); -} - -static void shell_content_set_shell_view (EShellContent *shell_content, EShellView *shell_view) { @@ -380,72 +90,6 @@ shell_content_set_property (GObject *object, GParamSpec *pspec) { switch (property_id) { - case PROP_FILTER_ACTION: - e_shell_content_set_filter_action ( - E_SHELL_CONTENT (object), - g_value_get_object (value)); - return; - - case PROP_FILTER_VALUE: - e_shell_content_set_filter_value ( - E_SHELL_CONTENT (object), - g_value_get_int (value)); - return; - - case PROP_FILTER_VISIBLE: - e_shell_content_set_filter_visible ( - E_SHELL_CONTENT (object), - g_value_get_boolean (value)); - return; - - case PROP_SEARCH_HINT: - e_shell_content_set_search_hint ( - E_SHELL_CONTENT (object), - g_value_get_string (value)); - return; - - case PROP_SEARCH_RULE: - e_shell_content_set_search_rule ( - E_SHELL_CONTENT (object), - g_value_get_object (value)); - return; - - case PROP_SEARCH_TEXT: - e_shell_content_set_search_text ( - E_SHELL_CONTENT (object), - g_value_get_string (value)); - return; - - case PROP_SEARCH_VISIBLE: - e_shell_content_set_search_visible ( - E_SHELL_CONTENT (object), - g_value_get_boolean (value)); - return; - - case PROP_SCOPE_ACTION: - e_shell_content_set_scope_action ( - E_SHELL_CONTENT (object), - g_value_get_object (value)); - return; - - case PROP_SCOPE_VALUE: - e_shell_content_set_scope_value ( - E_SHELL_CONTENT (object), - g_value_get_int (value)); - return; - - case PROP_SCOPE_VISIBLE: - e_shell_content_set_scope_visible ( - E_SHELL_CONTENT (object), - g_value_get_boolean (value)); - return; - - case PROP_SEARCH_RADIO_ACTION: - e_shell_content_set_search_radio_action ( - E_SHELL_CONTENT (object), - g_value_get_object (value)); - return; - case PROP_SHELL_VIEW: shell_content_set_shell_view ( E_SHELL_CONTENT (object), @@ -463,78 +107,6 @@ shell_content_get_property (GObject *object, GParamSpec *pspec) { switch (property_id) { - case PROP_FILTER_ACTION: - g_value_set_object ( - value, e_shell_content_get_filter_action ( - E_SHELL_CONTENT (object))); - return; - - case PROP_FILTER_VALUE: - g_value_set_int ( - value, e_shell_content_get_filter_value ( - E_SHELL_CONTENT (object))); - return; - - case PROP_FILTER_VISIBLE: - g_value_set_boolean ( - value, e_shell_content_get_filter_visible ( - E_SHELL_CONTENT (object))); - return; - - case PROP_SEARCH_CONTEXT: - g_value_set_object ( - value, e_shell_content_get_search_context ( - E_SHELL_CONTENT (object))); - return; - - case PROP_SEARCH_HINT: - g_value_set_string ( - value, e_shell_content_get_search_hint ( - E_SHELL_CONTENT (object))); - return; - - case PROP_SEARCH_RULE: - g_value_set_object ( - value, e_shell_content_get_search_rule ( - E_SHELL_CONTENT (object))); - return; - - case PROP_SEARCH_TEXT: - g_value_set_string ( - value, e_shell_content_get_search_text ( - E_SHELL_CONTENT (object))); - return; - - case PROP_SEARCH_VISIBLE: - g_value_set_boolean ( - value, e_shell_content_get_search_visible ( - E_SHELL_CONTENT (object))); - return; - - case PROP_SCOPE_ACTION: - g_value_set_object ( - value, e_shell_content_get_scope_action ( - E_SHELL_CONTENT (object))); - return; - - case PROP_SCOPE_VALUE: - g_value_set_int ( - value, e_shell_content_get_scope_value ( - E_SHELL_CONTENT (object))); - return; - - case PROP_SCOPE_VISIBLE: - g_value_set_boolean ( - value, e_shell_content_get_scope_visible ( - E_SHELL_CONTENT (object))); - return; - - case PROP_SEARCH_RADIO_ACTION: - g_value_set_object ( - value, e_shell_content_get_search_radio_action ( - E_SHELL_CONTENT (object))); - return; - case PROP_SHELL_VIEW: g_value_set_object ( value, e_shell_content_get_shell_view ( @@ -558,85 +130,42 @@ shell_content_dispose (GObject *object) priv->shell_view = NULL; } - if (priv->search_context != NULL) { - g_object_unref (priv->search_context); - priv->search_context = NULL; - } - - if (priv->search_radio) { - g_signal_handlers_disconnect_matched ( - priv->search_radio, G_SIGNAL_MATCH_DATA, - 0, 0, NULL, NULL, object); - g_object_unref (priv->search_radio); - priv->search_radio = NULL; - } - /* Chain up to parent's dispose() method. */ G_OBJECT_CLASS (parent_class)->dispose (object); } static void -shell_content_finalize (GObject *object) -{ - EShellContentPrivate *priv; - - priv = E_SHELL_CONTENT_GET_PRIVATE (object); - - g_free (priv->system_filename); - g_free (priv->user_filename); - - /* Chain up to parent's finalize() method. */ - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -static void shell_content_constructed (GObject *object) { - EShellView *shell_view; - EShellWindow *shell_window; + EShellContentClass *class; EShellContent *shell_content; - GtkSizeGroup *size_group; - GtkAction *action; + EShellBackend *shell_backend; + EShellView *shell_view; GtkWidget *widget; + const gchar *data_dir; shell_content = E_SHELL_CONTENT (object); shell_view = e_shell_content_get_shell_view (shell_content); - shell_window = e_shell_view_get_shell_window (shell_view); - size_group = e_shell_view_get_size_group (shell_view); - - g_signal_connect_after ( - shell_view, "execute-search", - G_CALLBACK (shell_content_execute_search_cb), - shell_content); - - widget = shell_content->priv->search_entry; - - action = E_SHELL_WINDOW_ACTION_SEARCH_CLEAR (shell_window); - e_binding_new ( - action, "sensitive", - widget, "secondary-icon-sensitive"); - e_binding_new ( - action, "stock-id", - widget, "secondary-icon-stock"); - e_binding_new ( - action, "tooltip", - widget, "secondary-icon-tooltip-text"); - - action = E_SHELL_WINDOW_ACTION_SEARCH_OPTIONS (shell_window); - e_binding_new ( - action, "sensitive", - widget, "primary-icon-sensitive"); - e_binding_new ( - action, "stock-id", - widget, "primary-icon-stock"); - e_binding_new ( - action, "tooltip", - widget, "primary-icon-tooltip-text"); - - widget = shell_content->priv->search_bar; - gtk_size_group_add_widget (size_group, widget); - - shell_content_init_search_context (shell_content); + shell_backend = e_shell_view_get_shell_backend (shell_view); + + /* XXX Regenerate the filename for custom saved search as done + * in shell_view_init_search_context(). ERuleContext ought + * to remember the filename when loading rules so you don't + * have to keep passing it in when saving rules. */ + data_dir = e_shell_backend_get_data_dir (shell_backend); + shell_content->priv->user_filename = + g_build_filename (data_dir, "searches.xml", NULL); + + class = E_SHELL_CONTENT_GET_CLASS (shell_content); + if (class->construct_searchbar != NULL) + widget = class->construct_searchbar (shell_content); + else + widget = NULL; + if (widget != NULL) { + gtk_widget_set_parent (widget, GTK_WIDGET (shell_content)); + shell_content->priv->searchbar = g_object_ref (widget); + gtk_widget_show (widget); + } } static void @@ -649,11 +178,11 @@ shell_content_destroy (GtkObject *gtk_object) /* Unparent the widget before destroying it to avoid * writing a custom GtkContainer::remove() method. */ - if (priv->search_bar != NULL) { - gtk_widget_unparent (priv->search_bar); - gtk_widget_destroy (priv->search_bar); - g_object_unref (priv->search_bar); - priv->search_bar = NULL; + if (priv->searchbar != NULL) { + gtk_widget_unparent (priv->searchbar); + gtk_widget_destroy (priv->searchbar); + g_object_unref (priv->searchbar); + priv->searchbar = NULL; } /* Chain up to parent's destroy() method. */ @@ -676,8 +205,10 @@ shell_content_size_request (GtkWidget *widget, child = gtk_bin_get_child (GTK_BIN (widget)); gtk_widget_size_request (child, requisition); - child = priv->search_bar; - gtk_widget_size_request (child, &child_requisition); + if (priv->searchbar == NULL) + return; + + gtk_widget_size_request (priv->searchbar, &child_requisition); requisition->width = MAX (requisition->width, child_requisition.width); requisition->height += child_requisition.height; } @@ -695,15 +226,20 @@ shell_content_size_allocate (GtkWidget *widget, widget->allocation = *allocation; - child = priv->search_bar; - gtk_widget_size_request (child, &child_requisition); + child = priv->searchbar; + + if (child == NULL) + child_requisition.height = 0; + else + gtk_widget_size_request (child, &child_requisition); child_allocation.x = allocation->x; child_allocation.y = allocation->y; child_allocation.width = allocation->width; child_allocation.height = child_requisition.height; - gtk_widget_size_allocate (child, &child_allocation); + if (child != NULL) + gtk_widget_size_allocate (child, &child_allocation); child_allocation.y += child_requisition.height; child_allocation.height = @@ -724,14 +260,46 @@ shell_content_forall (GtkContainer *container, priv = E_SHELL_CONTENT_GET_PRIVATE (container); - if (include_internals) - callback (priv->search_bar, callback_data); + if (include_internals && priv->searchbar != NULL) + callback (priv->searchbar, callback_data); /* Chain up to parent's forall() method. */ GTK_CONTAINER_CLASS (parent_class)->forall ( container, include_internals, callback, callback_data); } +static gchar * +shell_content_get_search_name (EShellContent *shell_content) +{ + EShellSearchbar *searchbar; + EShellView *shell_view; + EFilterRule *rule; + const gchar *search_text; + + shell_view = e_shell_content_get_shell_view (shell_content); + + rule = e_shell_view_get_search_rule (shell_view); + g_return_val_if_fail (E_IS_FILTER_RULE (rule), NULL); + + searchbar = E_SHELL_SEARCHBAR (shell_content->priv->searchbar); + search_text = e_shell_searchbar_get_search_text (searchbar); + + if (search_text == NULL || *search_text == '\0') + search_text = "''"; + + return g_strdup_printf ("%s %s", rule->name, search_text); +} + +static GtkWidget * +shell_content_construct_searchbar (EShellContent *shell_content) +{ + EShellView *shell_view; + + shell_view = e_shell_content_get_shell_view (shell_content); + + return e_shell_searchbar_new (shell_view); +} + static void shell_content_class_init (EShellContentClass *class) { @@ -747,7 +315,6 @@ shell_content_class_init (EShellContentClass *class) object_class->set_property = shell_content_set_property; object_class->get_property = shell_content_get_property; object_class->dispose = shell_content_dispose; - object_class->finalize = shell_content_finalize; object_class->constructed = shell_content_constructed; gtk_object_class = GTK_OBJECT_CLASS (class); @@ -760,134 +327,8 @@ shell_content_class_init (EShellContentClass *class) container_class = GTK_CONTAINER_CLASS (class); container_class->forall = shell_content_forall; - class->new_search_context = e_rule_context_new; - - g_object_class_install_property ( - object_class, - PROP_FILTER_ACTION, - g_param_spec_object ( - "filter-action", - NULL, - NULL, - GTK_TYPE_RADIO_ACTION, - G_PARAM_READWRITE)); - - g_object_class_install_property ( - object_class, - PROP_FILTER_VALUE, - g_param_spec_int ( - "filter-value", - NULL, - NULL, - G_MININT, - G_MAXINT, - 0, - G_PARAM_READWRITE)); - - g_object_class_install_property ( - object_class, - PROP_FILTER_VISIBLE, - g_param_spec_boolean ( - "filter-visible", - NULL, - NULL, - TRUE, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT)); - - g_object_class_install_property ( - object_class, - PROP_SEARCH_CONTEXT, - g_param_spec_object ( - "search-context", - NULL, - NULL, - E_TYPE_RULE_CONTEXT, - G_PARAM_READABLE)); - - g_object_class_install_property ( - object_class, - PROP_SEARCH_HINT, - g_param_spec_string ( - "search-hint", - NULL, - NULL, - NULL, - G_PARAM_READWRITE)); - - g_object_class_install_property ( - object_class, - PROP_SEARCH_RULE, - g_param_spec_object ( - "search-rule", - NULL, - NULL, - E_TYPE_FILTER_RULE, - G_PARAM_READWRITE)); - - g_object_class_install_property ( - object_class, - PROP_SEARCH_TEXT, - g_param_spec_string ( - "search-text", - NULL, - NULL, - NULL, - G_PARAM_READWRITE)); - - g_object_class_install_property ( - object_class, - PROP_SEARCH_VISIBLE, - g_param_spec_boolean ( - "search-visible", - NULL, - NULL, - TRUE, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT)); - - g_object_class_install_property ( - object_class, - PROP_SCOPE_ACTION, - g_param_spec_object ( - "scope-action", - NULL, - NULL, - GTK_TYPE_RADIO_ACTION, - G_PARAM_READWRITE)); - - g_object_class_install_property ( - object_class, - PROP_SCOPE_VALUE, - g_param_spec_int ( - "scope-value", - NULL, - NULL, - G_MININT, - G_MAXINT, - 0, - G_PARAM_READWRITE)); - - g_object_class_install_property ( - object_class, - PROP_SCOPE_VISIBLE, - g_param_spec_boolean ( - "scope-visible", - NULL, - NULL, - FALSE, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT)); - - g_object_class_install_property ( - object_class, - PROP_SEARCH_RADIO_ACTION, - g_param_spec_object ( - "search-radio-action", - NULL, - NULL, - GTK_TYPE_RADIO_ACTION, - G_PARAM_READWRITE)); + class->get_search_name = shell_content_get_search_name; + class->construct_searchbar = shell_content_construct_searchbar; /** * EShellContent:shell-view @@ -909,128 +350,9 @@ shell_content_class_init (EShellContentClass *class) static void shell_content_init (EShellContent *shell_content) { - GtkBox *box; - GtkLabel *label; - GtkWidget *widget; - shell_content->priv = E_SHELL_CONTENT_GET_PRIVATE (shell_content); GTK_WIDGET_SET_FLAGS (shell_content, GTK_NO_WINDOW); - - /*** Build the Search Bar ***/ - - widget = gtk_hbox_new (FALSE, 24); - gtk_widget_set_parent (widget, GTK_WIDGET (shell_content)); - shell_content->priv->search_bar = g_object_ref (widget); - gtk_widget_show (widget); - - /* Filter Combo Widgets */ - - box = GTK_BOX (shell_content->priv->search_bar); - - widget = gtk_hbox_new (FALSE, 3); - gtk_box_pack_start (box, widget, FALSE, FALSE, 0); - - e_binding_new ( - shell_content, "filter-visible", - widget, "visible"); - - box = GTK_BOX (widget); - - /* Translators: The "Show:" label precedes a combo box that - * allows the user to filter the current view. Examples of - * items that appear in the combo box are "Unread Messages", - * "Important Messages", or "Active Appointments". */ - widget = gtk_label_new_with_mnemonic (_("Sho_w:")); - gtk_box_pack_start (box, widget, FALSE, FALSE, 0); - gtk_widget_show (widget); - - label = GTK_LABEL (widget); - - widget = e_action_combo_box_new (); - gtk_label_set_mnemonic_widget (label, widget); - gtk_box_pack_start (box, widget, FALSE, FALSE, 0); - shell_content->priv->filter_combo_box = widget; - gtk_widget_show (widget); - - /* Search Entry Widgets */ - - box = GTK_BOX (shell_content->priv->search_bar); - - widget = gtk_hbox_new (FALSE, 3); - gtk_box_pack_start (box, widget, TRUE, TRUE, 0); - - e_binding_new ( - shell_content, "search-visible", - widget, "visible"); - - box = GTK_BOX (widget); - - /* Translators: This is part of the quick search interface. - * example: Search: [_______________] in [ Current Folder ] */ - widget = gtk_label_new_with_mnemonic (_("Sear_ch:")); - gtk_box_pack_start (box, widget, FALSE, FALSE, 0); - gtk_widget_show (widget); - - label = GTK_LABEL (widget); - - widget = e_hinted_entry_new (); - gtk_label_set_mnemonic_widget (label, widget); - gtk_box_pack_start (box, widget, TRUE, TRUE, 0); - shell_content->priv->search_entry = widget; - gtk_widget_show (widget); - - g_signal_connect_swapped ( - widget, "activate", - G_CALLBACK (shell_content_entry_activate_cb), - shell_content); - - g_signal_connect_swapped ( - widget, "changed", - G_CALLBACK (shell_content_entry_changed_cb), - shell_content); - - g_signal_connect_swapped ( - widget, "icon-press", - G_CALLBACK (shell_content_entry_icon_press_cb), - shell_content); - - g_signal_connect_swapped ( - widget, "icon-release", - G_CALLBACK (shell_content_entry_icon_release_cb), - shell_content); - - g_signal_connect_swapped ( - widget, "key-press-event", - G_CALLBACK (shell_content_entry_key_press_cb), - shell_content); - - /* Scope Combo Widgets */ - - box = GTK_BOX (shell_content->priv->search_bar); - - widget = gtk_hbox_new (FALSE, 3); - gtk_box_pack_start (box, widget, FALSE, FALSE, 0); - - e_binding_new ( - shell_content, "scope-visible", - widget, "visible"); - - box = GTK_BOX (widget); - - /* Translators: This is part of the quick search interface. - * example: Search: [_______________] in [ Current Folder ] */ - widget = gtk_label_new_with_mnemonic (_("i_n")); - gtk_box_pack_start (box, widget, FALSE, FALSE, 0); - gtk_widget_show (widget); - - label = GTK_LABEL (widget); - - widget = e_action_combo_box_new (); - gtk_label_set_mnemonic_widget (label, widget); - gtk_box_pack_start (box, widget, FALSE, FALSE, 0); - shell_content->priv->scope_combo_box = widget; - gtk_widget_show (widget); } GType @@ -1077,6 +399,24 @@ e_shell_content_new (EShellView *shell_view) } /** + * e_shell_content_get_searchbar: + * @shell_view: an #EShellView + * + * Returns the search bar widget returned by the + * <structfield>construct_searchbar</structfield> method in + * #EShellContentClass. + * + * Returns: the search bar widget + **/ +GtkWidget * +e_shell_content_get_searchbar (EShellContent *shell_content) +{ + g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), NULL); + + return shell_content->priv->searchbar; +} + +/** * e_shell_content_check_state: * @shell_content: an #EShellContent * @@ -1118,371 +458,27 @@ e_shell_content_get_shell_view (EShellContent *shell_content) return E_SHELL_VIEW (shell_content->priv->shell_view); } -GtkRadioAction * -e_shell_content_get_filter_action (EShellContent *shell_content) -{ - EActionComboBox *combo_box; - - g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), NULL); - - combo_box = E_ACTION_COMBO_BOX (shell_content->priv->filter_combo_box); - - return e_action_combo_box_get_action (combo_box); -} - -void -e_shell_content_set_filter_action (EShellContent *shell_content, - GtkRadioAction *filter_action) -{ - EActionComboBox *combo_box; - - g_return_if_fail (E_IS_SHELL_CONTENT (shell_content)); - - combo_box = E_ACTION_COMBO_BOX (shell_content->priv->filter_combo_box); - - e_action_combo_box_set_action (combo_box, filter_action); - - g_object_notify (G_OBJECT (shell_content), "filter-action"); -} - -gint -e_shell_content_get_filter_value (EShellContent *shell_content) -{ - EActionComboBox *combo_box; - - g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), 0); - - combo_box = E_ACTION_COMBO_BOX (shell_content->priv->filter_combo_box); - - return e_action_combo_box_get_current_value (combo_box); -} - -void -e_shell_content_set_filter_value (EShellContent *shell_content, - gint filter_value) -{ - EActionComboBox *combo_box; - - g_return_if_fail (E_IS_SHELL_CONTENT (shell_content)); - - combo_box = E_ACTION_COMBO_BOX (shell_content->priv->filter_combo_box); - - e_action_combo_box_set_current_value (combo_box, filter_value); - - g_object_notify (G_OBJECT (shell_content), "filter-value"); -} - -gboolean -e_shell_content_get_filter_visible (EShellContent *shell_content) -{ - g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), FALSE); - - return shell_content->priv->filter_visible; -} - -void -e_shell_content_set_filter_visible (EShellContent *shell_content, - gboolean filter_visible) -{ - g_return_if_fail (E_IS_SHELL_CONTENT (shell_content)); - - shell_content->priv->filter_visible = filter_visible; - - g_object_notify (G_OBJECT (shell_content), "filter-visible"); -} - -void -e_shell_content_add_filter_separator_before (EShellContent *shell_content, - gint action_value) -{ - EActionComboBox *combo_box; - - g_return_if_fail (E_IS_SHELL_CONTENT (shell_content)); - - combo_box = E_ACTION_COMBO_BOX (shell_content->priv->filter_combo_box); - - e_action_combo_box_add_separator_before (combo_box, action_value); -} - -void -e_shell_content_add_filter_separator_after (EShellContent *shell_content, - gint action_value) -{ - EActionComboBox *combo_box; - - g_return_if_fail (E_IS_SHELL_CONTENT (shell_content)); - - combo_box = E_ACTION_COMBO_BOX (shell_content->priv->filter_combo_box); - - e_action_combo_box_add_separator_after (combo_box, action_value); -} - -ERuleContext * -e_shell_content_get_search_context (EShellContent *shell_content) -{ - g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), NULL); - - return shell_content->priv->search_context; -} - -const gchar * -e_shell_content_get_search_hint (EShellContent *shell_content) -{ - EHintedEntry *entry; - - g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), NULL); - - entry = E_HINTED_ENTRY (shell_content->priv->search_entry); - - return e_hinted_entry_get_hint (entry); -} - -void -e_shell_content_set_search_hint (EShellContent *shell_content, - const gchar *search_hint) -{ - EHintedEntry *entry; - - g_return_if_fail (E_IS_SHELL_CONTENT (shell_content)); - - entry = E_HINTED_ENTRY (shell_content->priv->search_entry); - - e_hinted_entry_set_hint (entry, search_hint); - - g_object_notify (G_OBJECT (shell_content), "search-hint"); -} - -EFilterRule * -e_shell_content_get_search_rule (EShellContent *shell_content) -{ - g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), NULL); - - return shell_content->priv->search_rule; -} - -void -e_shell_content_set_search_rule (EShellContent *shell_content, - EFilterRule *search_rule) -{ - g_return_if_fail (E_IS_SHELL_CONTENT (shell_content)); - - if (search_rule != NULL) { - g_return_if_fail (E_IS_FILTER_RULE (search_rule)); - g_object_ref (search_rule); - } - - if (shell_content->priv->search_rule != NULL) - g_object_unref (shell_content->priv->search_rule); - - shell_content->priv->search_rule = search_rule; - - shell_content_update_search_widgets (shell_content); - g_object_notify (G_OBJECT (shell_content), "search-rule"); -} - -/* free returned string with g_free */ +/** + * e_shell_content_get_search_name: + * @shell_content: an #EShellContent + * + * Returns a newly-allocated string containing a suitable name for the + * current search criteria. This is used as the suggested name in the + * Save Search dialog. Free the returned string with g_free(). + * + * Returns: a name for the current search criteria + **/ gchar * -e_shell_content_get_search_rule_as_string (EShellContent *shell_content) +e_shell_content_get_search_name (EShellContent *shell_content) { - EFilterRule *rule; - GString *str; + EShellContentClass *class; g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), NULL); - rule = e_shell_content_get_search_rule (shell_content); - - if (!rule) - return NULL; - - str = g_string_new (""); - e_filter_rule_build_code (rule, str); + class = E_SHELL_CONTENT_GET_CLASS (shell_content); + g_return_val_if_fail (class->get_search_name != NULL, NULL); - return g_string_free (str, FALSE); -} - -const gchar * -e_shell_content_get_search_text (EShellContent *shell_content) -{ - EHintedEntry *entry; - - g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), NULL); - - entry = E_HINTED_ENTRY (shell_content->priv->search_entry); - - return e_hinted_entry_get_text (entry); -} - -void -e_shell_content_set_search_text (EShellContent *shell_content, - const gchar *search_text) -{ - EHintedEntry *entry; - - g_return_if_fail (E_IS_SHELL_CONTENT (shell_content)); - - entry = E_HINTED_ENTRY (shell_content->priv->search_entry); - - e_hinted_entry_set_text (entry, search_text); - - shell_content_update_search_widgets (shell_content); - g_object_notify (G_OBJECT (shell_content), "search-text"); -} - -gboolean -e_shell_content_get_search_visible (EShellContent *shell_content) -{ - g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), FALSE); - - return shell_content->priv->search_visible; -} - -void -e_shell_content_set_search_visible (EShellContent *shell_content, - gboolean search_visible) -{ - g_return_if_fail (E_IS_SHELL_CONTENT (shell_content)); - - shell_content->priv->search_visible = search_visible; - - g_object_notify (G_OBJECT (shell_content), "search-visible"); -} - -GtkRadioAction * -e_shell_content_get_scope_action (EShellContent *shell_content) -{ - EActionComboBox *combo_box; - - g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), NULL); - - combo_box = E_ACTION_COMBO_BOX (shell_content->priv->scope_combo_box); - - return e_action_combo_box_get_action (combo_box); -} - -void -e_shell_content_set_scope_action (EShellContent *shell_content, - GtkRadioAction *scope_action) -{ - EActionComboBox *combo_box; - - g_return_if_fail (E_IS_SHELL_CONTENT (shell_content)); - - combo_box = E_ACTION_COMBO_BOX (shell_content->priv->scope_combo_box); - - e_action_combo_box_set_action (combo_box, scope_action); - - g_object_notify (G_OBJECT (shell_content), "scope-action"); -} - -gint -e_shell_content_get_scope_value (EShellContent *shell_content) -{ - EActionComboBox *combo_box; - - g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), 0); - - combo_box = E_ACTION_COMBO_BOX (shell_content->priv->scope_combo_box); - - return e_action_combo_box_get_current_value (combo_box); -} - -void -e_shell_content_set_scope_value (EShellContent *shell_content, - gint scope_value) -{ - EActionComboBox *combo_box; - - g_return_if_fail (E_IS_SHELL_CONTENT (shell_content)); - - combo_box = E_ACTION_COMBO_BOX (shell_content->priv->scope_combo_box); - - e_action_combo_box_set_current_value (combo_box, scope_value); - - g_object_notify (G_OBJECT (shell_content), "scope-value"); -} - -gboolean -e_shell_content_get_scope_visible (EShellContent *shell_content) -{ - g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), FALSE); - - return shell_content->priv->scope_visible; -} - -void -e_shell_content_set_scope_visible (EShellContent *shell_content, - gboolean scope_visible) -{ - g_return_if_fail (E_IS_SHELL_CONTENT (shell_content)); - - shell_content->priv->scope_visible = scope_visible; - - g_object_notify (G_OBJECT (shell_content), "scope-visible"); -} - -static void -search_radio_changed_cb (GtkRadioAction *action, - GtkRadioAction *current, - EShellContent *shell_content) -{ - EShellView *shell_view; - const gchar *search_text; - const gchar *label; - gint current_value; - - shell_view = e_shell_content_get_shell_view (shell_content); - - label = gtk_action_get_label (GTK_ACTION (current)); - e_shell_content_set_search_hint (shell_content, label); - - current_value = gtk_radio_action_get_current_value (current); - search_text = e_shell_content_get_search_text (shell_content); - - if (current_value != -1) { - e_shell_content_set_search_rule (shell_content, NULL); - e_shell_content_set_search_text (shell_content, search_text); - if (search_text != NULL && *search_text != '\0') - e_shell_view_execute_search (shell_view); - } else if (search_text != NULL) { - e_shell_content_set_search_text (shell_content, NULL); - } -} - -void -e_shell_content_set_search_radio_action (EShellContent *shell_content, - GtkRadioAction *search_action) -{ - g_return_if_fail (E_IS_SHELL_CONTENT (shell_content)); - - if (search_action != NULL) { - g_return_if_fail (GTK_IS_RADIO_ACTION (search_action)); - g_object_ref (search_action); - } - - if (shell_content->priv->search_radio) { - g_signal_handlers_disconnect_matched ( - shell_content->priv->search_radio, - G_SIGNAL_MATCH_DATA, 0, 0, NULL, - search_radio_changed_cb, shell_content); - g_object_unref (shell_content->priv->search_radio); - } - - shell_content->priv->search_radio = search_action; - - if (shell_content->priv->search_radio != NULL) - g_signal_connect ( - shell_content->priv->search_radio, "changed", - G_CALLBACK (search_radio_changed_cb), shell_content); - - g_object_notify (G_OBJECT (shell_content), "search-radio-action"); -} - -GtkRadioAction * -e_shell_content_get_search_radio_action (EShellContent *shell_content) -{ - g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), NULL); - - return shell_content->priv->search_radio; + return class->get_search_name (shell_content); } void @@ -1504,14 +500,14 @@ e_shell_content_run_advanced_search_dialog (EShellContent *shell_content) shell_window = e_shell_view_get_shell_window (shell_view); user_filename = shell_content->priv->user_filename; - rule = e_shell_content_get_search_rule (shell_content); + rule = e_shell_view_get_search_rule (shell_view); if (rule == NULL) rule = e_filter_rule_new (); else rule = e_filter_rule_clone (rule); - context = e_shell_content_get_search_context (shell_content); + context = E_SHELL_VIEW_GET_CLASS (shell_view)->search_context; widget = e_filter_rule_get_widget (rule, context); e_filter_rule_set_source (rule, E_FILTER_SOURCE_INCOMING); @@ -1548,10 +544,7 @@ run: goto run; } - e_shell_content_set_search_rule (shell_content, rule); - - shell_content_activate_advanced_search (shell_content); - e_shell_view_execute_search (shell_view); + e_shell_view_custom_search (shell_view, rule); if (response == GTK_RESPONSE_APPLY) { if (!e_rule_context_find_rule (context, rule->name, rule->source)) @@ -1568,13 +561,15 @@ exit: void e_shell_content_run_edit_searches_dialog (EShellContent *shell_content) { + EShellView *shell_view; ERuleContext *context; ERuleEditor *editor; const gchar *user_filename; g_return_if_fail (E_IS_SHELL_CONTENT (shell_content)); - context = e_shell_content_get_search_context (shell_content); + shell_view = e_shell_content_get_shell_view (shell_content); + context = E_SHELL_VIEW_GET_CLASS (shell_view)->search_context; user_filename = shell_content->priv->user_filename; editor = e_rule_editor_new ( @@ -1596,7 +591,6 @@ e_shell_content_run_save_search_dialog (EShellContent *shell_content) GtkWidget *widget; EFilterRule *rule; ERuleContext *context; - const gchar *search_text; const gchar *user_filename; gchar *search_name; gint response; @@ -1608,19 +602,15 @@ e_shell_content_run_save_search_dialog (EShellContent *shell_content) shell_window = e_shell_view_get_shell_window (shell_view); user_filename = shell_content->priv->user_filename; - rule = e_shell_content_get_search_rule (shell_content); + rule = e_shell_view_get_search_rule (shell_view); g_return_if_fail (E_IS_FILTER_RULE (rule)); rule = e_filter_rule_clone (rule); - search_text = e_shell_content_get_search_text (shell_content); - if (search_text == NULL || *search_text == '\0') - search_text = "''"; - - search_name = g_strdup_printf ("%s %s", rule->name, search_text); + search_name = e_shell_content_get_search_name (shell_content); e_filter_rule_set_name (rule, search_name); g_free (search_name); - context = e_shell_content_get_search_context (shell_content); + context = E_SHELL_VIEW_GET_CLASS (shell_view)->search_context; widget = e_filter_rule_get_widget (rule, context); e_filter_rule_set_source (rule, E_FILTER_SOURCE_INCOMING); @@ -1656,83 +646,13 @@ run: goto run; } - e_rule_context_add_rule (context, rule); + /* XXX This function steals the rule reference, so + * counteract that by referencing it again. */ + e_rule_context_add_rule (context, g_object_ref (rule)); + e_rule_context_save (context, user_filename); exit: g_object_unref (rule); gtk_widget_destroy (dialog); } - -void -e_shell_content_restore_state (EShellContent *shell_content, - const gchar *group_name) -{ - EShellView *shell_view; - EShellWindow *shell_window; - GKeyFile *key_file; - GtkAction *action; - GtkWidget *widget; - const gchar *search_text; - const gchar *key; - gchar *string; - - g_return_if_fail (E_IS_SHELL_CONTENT (shell_content)); - g_return_if_fail (group_name != NULL); - - shell_view = e_shell_content_get_shell_view (shell_content); - shell_window = e_shell_view_get_shell_window (shell_view); - key_file = e_shell_view_get_state_key_file (shell_view); - - /* Changing the combo boxes triggers searches, so block - * the search action until the state is fully restored. */ - action = E_SHELL_WINDOW_ACTION_SEARCH_QUICK (shell_window); - gtk_action_block_activate (action); - e_shell_view_block_execute_search (shell_view); - - key = STATE_KEY_SEARCH_FILTER; - string = g_key_file_get_string (key_file, group_name, key, NULL); - if (string != NULL && *string != '\0') - action = e_shell_window_get_action (shell_window, string); - else - action = NULL; - if (action != NULL) - gtk_action_activate (action); - else { - /* Pick the first combo box item. */ - widget = shell_content->priv->filter_combo_box; - gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 0); - } - g_free (string); - - key = STATE_KEY_SEARCH_SCOPE; - string = g_key_file_get_string (key_file, group_name, key, NULL); - if (string != NULL && *string != '\0') - action = e_shell_window_get_action (shell_window, string); - else - action = NULL; - if (action != NULL) - gtk_action_activate (action); - else { - /* Pick the first combo box item. */ - widget = shell_content->priv->scope_combo_box; - gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 0); - } - g_free (string); - - key = STATE_KEY_SEARCH_TEXT; - string = g_key_file_get_string (key_file, group_name, key, NULL); - search_text = e_shell_content_get_search_text (shell_content); - if (search_text != NULL && *search_text == '\0') - search_text = NULL; - if (g_strcmp0 (string, search_text) != 0) - e_shell_content_set_search_text (shell_content, string); - g_free (string); - - action = E_SHELL_WINDOW_ACTION_SEARCH_QUICK (shell_window); - gtk_action_unblock_activate (action); - e_shell_view_unblock_execute_search (shell_view); - - /* Now execute the search. */ - e_shell_view_execute_search (shell_view); -} diff --git a/shell/e-shell-content.h b/shell/e-shell-content.h index 9ee9219cfb..3c3332b17b 100644 --- a/shell/e-shell-content.h +++ b/shell/e-shell-content.h @@ -29,8 +29,6 @@ #define E_SHELL_CONTENT_H #include <shell/e-shell-common.h> -#include <filter/e-filter-rule.h> -#include <filter/e-rule-context.h> /* Standard GObject macros */ #define E_TYPE_SHELL_CONTENT \ @@ -74,81 +72,30 @@ struct _EShellContent { struct _EShellContentClass { GtkBinClass parent_class; - /* Factory Methods */ - ERuleContext * (*new_search_context) (void); - + /* Methods */ guint32 (*check_state) (EShellContent *shell_content); + gchar * (*get_search_name) (EShellContent *shell_content); + + /* This is a protected method. Not for public use. */ + GtkWidget * (*construct_searchbar) (EShellContent *shell_content); }; GType e_shell_content_get_type (void); GtkWidget * e_shell_content_new (struct _EShellView *shell_view); +GtkWidget * e_shell_content_get_searchbar (EShellContent *shell_content); guint32 e_shell_content_check_state (EShellContent *shell_content); struct _EShellView * e_shell_content_get_shell_view (EShellContent *shell_content); -GtkRadioAction *e_shell_content_get_filter_action - (EShellContent *shell_content); -void e_shell_content_set_filter_action - (EShellContent *shell_content, - GtkRadioAction *filter_action); -gint e_shell_content_get_filter_value(EShellContent *shell_content); -void e_shell_content_set_filter_value(EShellContent *shell_content, - gint filter_value); -gboolean e_shell_content_get_filter_visible - (EShellContent *shell_content); -void e_shell_content_set_filter_visible - (EShellContent *shell_content, - gboolean filter_visible); -void e_shell_content_add_filter_separator_before - (EShellContent *shell_content, - gint action_value); -void e_shell_content_add_filter_separator_after - (EShellContent *shell_content, - gint action_value); -ERuleContext * e_shell_content_get_search_context - (EShellContent *shell_content); -const gchar * e_shell_content_get_search_hint (EShellContent *shell_content); -void e_shell_content_set_search_hint (EShellContent *shell_content, - const gchar *search_hint); -EFilterRule * e_shell_content_get_search_rule (EShellContent *shell_content); -void e_shell_content_set_search_rule (EShellContent *shell_content, - EFilterRule *search_rule); -gchar * e_shell_content_get_search_rule_as_string - (EShellContent *shell_content); -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); -gboolean e_shell_content_get_search_visible - (EShellContent *shell_content); -void e_shell_content_set_search_visible - (EShellContent *shell_content, - gboolean search_visible); -GtkRadioAction *e_shell_content_get_scope_action(EShellContent *shell_content); -void e_shell_content_set_scope_action(EShellContent *shell_content, - GtkRadioAction *scope_action); -gint e_shell_content_get_scope_value (EShellContent *shell_content); -void e_shell_content_set_scope_value (EShellContent *shell_content, - gint scope_value); -gboolean e_shell_content_get_scope_visible - (EShellContent *shell_content); -void e_shell_content_set_scope_visible - (EShellContent *shell_content, - gboolean scope_visible); -void e_shell_content_set_search_radio_action - (EShellContent *shell_content, - GtkRadioAction *search_action); -GtkRadioAction *e_shell_content_get_search_radio_action - (EShellContent *shell_content); 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); +gchar * e_shell_content_get_search_name (EShellContent *shell_content); 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); -void e_shell_content_restore_state (EShellContent *shell_content, - const gchar *group_name); G_END_DECLS diff --git a/shell/e-shell-searchbar.c b/shell/e-shell-searchbar.c new file mode 100644 index 0000000000..f9b0b2e967 --- /dev/null +++ b/shell/e-shell-searchbar.c @@ -0,0 +1,1053 @@ +/* + * e-shell-searchbar.c + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include "e-shell-searchbar.h" + +#include <config.h> +#include <glib/gi18n-lib.h> + +#include "e-util/e-binding.h" +#include "widgets/misc/e-action-combo-box.h" +#include "widgets/misc/e-hinted-entry.h" + +#include "e-shell-window-actions.h" + +#define E_SHELL_SEARCHBAR_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_SHELL_SEARCHBAR, EShellSearchbarPrivate)) + +#define SEARCH_OPTION_ADVANCED (-1) + +#define STATE_KEY_SEARCH_FILTER "SearchFilter" +#define STATE_KEY_SEARCH_SCOPE "SearchScope" +#define STATE_KEY_SEARCH_TEXT "SearchText" + +struct _EShellSearchbarPrivate { + + gpointer shell_view; /* weak pointer */ + + GtkRadioAction *search_option; + EFilterRule *search_rule; + + /* Child Widgets (not referenced) */ + GtkWidget *filter_combo_box; + GtkWidget *search_entry; + GtkWidget *scope_combo_box; + + guint filter_visible : 1; + guint search_visible : 1; + guint scope_visible : 1; +}; + +enum { + PROP_0, + PROP_FILTER_COMBO_BOX, + PROP_FILTER_VISIBLE, + PROP_SEARCH_HINT, + PROP_SEARCH_OPTION, + PROP_SEARCH_TEXT, + PROP_SEARCH_VISIBLE, + PROP_SCOPE_COMBO_BOX, + PROP_SCOPE_VISIBLE, + PROP_SHELL_VIEW +}; + +static gpointer parent_class; + +static void +shell_searchbar_update_search_widgets (EShellSearchbar *searchbar) +{ + EShellView *shell_view; + EShellWindow *shell_window; + GtkAction *action; + GtkWidget *widget; + const gchar *search_text; + gboolean sensitive; + + /* EShellView subclasses are responsible for actually + * executing the search. This is all cosmetic stuff. */ + + widget = searchbar->priv->search_entry; + shell_view = e_shell_searchbar_get_shell_view (searchbar); + shell_window = e_shell_view_get_shell_window (shell_view); + search_text = e_shell_searchbar_get_search_text (searchbar); + + sensitive = + (search_text != NULL && *search_text != '\0') || + (e_shell_view_get_search_rule (shell_view) != NULL); + + if (sensitive) { + GtkStyle *style; + const GdkColor *color; + + style = gtk_widget_get_style (widget); + color = &style->mid[GTK_STATE_SELECTED]; + + gtk_widget_modify_base (widget, GTK_STATE_NORMAL, color); + gtk_widget_modify_text (widget, GTK_STATE_NORMAL, NULL); + } else { + /* Text color will be updated when we move the focus. */ + gtk_widget_modify_base (widget, GTK_STATE_NORMAL, NULL); + } + + action = E_SHELL_WINDOW_ACTION_SEARCH_CLEAR (shell_window); + gtk_action_set_sensitive (action, sensitive); + + action = E_SHELL_WINDOW_ACTION_SEARCH_SAVE (shell_window); + gtk_action_set_sensitive (action, sensitive); +} + +static void +shell_searchbar_clear_search_cb (EShellView *shell_view, + EShellSearchbar *searchbar) +{ + GtkRadioAction *search_option; + gint current_value; + + e_shell_searchbar_set_search_text (searchbar, NULL); + + search_option = e_shell_searchbar_get_search_option (searchbar); + if (search_option == NULL) + return; + + /* Reset the search option if it's set to advanced search. */ + current_value = gtk_radio_action_get_current_value (search_option); + if (current_value == SEARCH_OPTION_ADVANCED) + gtk_radio_action_set_current_value (search_option, 0); +} + +static void +shell_searchbar_custom_search_cb (EShellView *shell_view, + EFilterRule *custom_rule, + EShellSearchbar *searchbar) +{ + GtkRadioAction *search_option; + gint value = SEARCH_OPTION_ADVANCED; + + e_shell_searchbar_set_search_text (searchbar, NULL); + + search_option = e_shell_searchbar_get_search_option (searchbar); + if (search_option != NULL) + gtk_radio_action_set_current_value (search_option, value); +} + +static void +shell_searchbar_execute_search_cb (EShellView *shell_view, + EShellSearchbar *searchbar) +{ + GtkWidget *widget; + + shell_searchbar_update_search_widgets (searchbar); + + if (!e_shell_view_is_active (shell_view)) + return; + + /* Direct the focus away from the search entry, so that a + * focus-in event is required before the text can be changed. + * This will reset the entry to the appropriate visual state. */ + widget = searchbar->priv->search_entry; + gtk_widget_child_focus (widget, GTK_DIR_TAB_FORWARD); +} + +static void +shell_searchbar_entry_activate_cb (EShellSearchbar *searchbar) +{ + EShellView *shell_view; + EShellWindow *shell_window; + GtkAction *action; + const gchar *search_text; + + shell_view = e_shell_searchbar_get_shell_view (searchbar); + shell_window = e_shell_view_get_shell_window (shell_view); + + search_text = e_shell_searchbar_get_search_text (searchbar); + if (search_text != NULL && *search_text != '\0') + action = E_SHELL_WINDOW_ACTION_SEARCH_QUICK (shell_window); + else + action = E_SHELL_WINDOW_ACTION_SEARCH_CLEAR (shell_window); + + gtk_action_activate (action); +} + +static void +shell_searchbar_entry_changed_cb (EShellSearchbar *searchbar) +{ + EShellView *shell_view; + EShellWindow *shell_window; + GtkAction *action; + const gchar *search_text; + gboolean sensitive; + + shell_view = e_shell_searchbar_get_shell_view (searchbar); + shell_window = e_shell_view_get_shell_window (shell_view); + + search_text = e_shell_searchbar_get_search_text (searchbar); + sensitive = (search_text != NULL && *search_text != '\0'); + + action = E_SHELL_WINDOW_ACTION_SEARCH_QUICK (shell_window); + gtk_action_set_sensitive (action, sensitive); +} + +static void +shell_searchbar_entry_icon_press_cb (EShellSearchbar *searchbar, + GtkEntryIconPosition icon_pos, + GdkEvent *event) +{ + EShellView *shell_view; + EShellWindow *shell_window; + GtkAction *action; + + /* Show the search options menu when the icon is pressed. */ + + if (icon_pos != GTK_ENTRY_ICON_PRIMARY) + return; + + shell_view = e_shell_searchbar_get_shell_view (searchbar); + shell_window = e_shell_view_get_shell_window (shell_view); + + action = E_SHELL_WINDOW_ACTION_SEARCH_OPTIONS (shell_window); + gtk_action_activate (action); +} + +static void +shell_searchbar_entry_icon_release_cb (EShellSearchbar *searchbar, + GtkEntryIconPosition icon_pos, + GdkEvent *event) +{ + EShellView *shell_view; + EShellWindow *shell_window; + GtkAction *action; + + /* Clear the search when the icon is pressed and released. */ + + if (icon_pos != GTK_ENTRY_ICON_SECONDARY) + return; + + shell_view = e_shell_searchbar_get_shell_view (searchbar); + shell_window = e_shell_view_get_shell_window (shell_view); + + action = E_SHELL_WINDOW_ACTION_SEARCH_CLEAR (shell_window); + gtk_action_activate (action); +} + +static gboolean +shell_searchbar_entry_key_press_cb (EShellSearchbar *searchbar, + GdkEventKey *key_event, + GtkWindow *entry) +{ + EShellView *shell_view; + EShellWindow *shell_window; + GtkAction *action; + guint mask; + + mask = gtk_accelerator_get_default_mod_mask (); + if ((key_event->state & mask) != GDK_MOD1_MASK) + return FALSE; + + if (key_event->keyval != GDK_Down) + return FALSE; + + shell_view = e_shell_searchbar_get_shell_view (searchbar); + shell_window = e_shell_view_get_shell_window (shell_view); + + action = E_SHELL_WINDOW_ACTION_SEARCH_OPTIONS (shell_window); + gtk_action_activate (action); + + return TRUE; +} + +static void +shell_searchbar_option_changed_cb (GtkRadioAction *action, + GtkRadioAction *current, + EShellSearchbar *searchbar) +{ + EShellView *shell_view; + const gchar *search_text; + const gchar *label; + gint current_value; + + shell_view = e_shell_searchbar_get_shell_view (searchbar); + + label = gtk_action_get_label (GTK_ACTION (current)); + e_shell_searchbar_set_search_hint (searchbar, label); + + current_value = gtk_radio_action_get_current_value (current); + search_text = e_shell_searchbar_get_search_text (searchbar); + + if (current_value != SEARCH_OPTION_ADVANCED) { + e_shell_view_set_search_rule (shell_view, NULL); + e_shell_searchbar_set_search_text (searchbar, search_text); + if (search_text != NULL && *search_text != '\0') + e_shell_view_execute_search (shell_view); + } else if (search_text != NULL) + e_shell_searchbar_set_search_text (searchbar, NULL); +} + +static void +shell_searchbar_set_shell_view (EShellSearchbar *searchbar, + EShellView *shell_view) +{ + g_return_if_fail (searchbar->priv->shell_view == NULL); + + searchbar->priv->shell_view = shell_view; + + g_object_add_weak_pointer ( + G_OBJECT (shell_view), + &searchbar->priv->shell_view); +} + +static void +shell_searchbar_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_FILTER_VISIBLE: + e_shell_searchbar_set_filter_visible ( + E_SHELL_SEARCHBAR (object), + g_value_get_boolean (value)); + return; + + case PROP_SEARCH_HINT: + e_shell_searchbar_set_search_hint ( + E_SHELL_SEARCHBAR (object), + g_value_get_string (value)); + return; + + case PROP_SEARCH_OPTION: + e_shell_searchbar_set_search_option ( + E_SHELL_SEARCHBAR (object), + g_value_get_object (value)); + return; + + case PROP_SEARCH_TEXT: + e_shell_searchbar_set_search_text ( + E_SHELL_SEARCHBAR (object), + g_value_get_string (value)); + return; + + case PROP_SEARCH_VISIBLE: + e_shell_searchbar_set_search_visible ( + E_SHELL_SEARCHBAR (object), + g_value_get_boolean (value)); + return; + + case PROP_SCOPE_VISIBLE: + e_shell_searchbar_set_scope_visible ( + E_SHELL_SEARCHBAR (object), + g_value_get_boolean (value)); + return; + + case PROP_SHELL_VIEW: + shell_searchbar_set_shell_view ( + E_SHELL_SEARCHBAR (object), + g_value_get_object (value)); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +shell_searchbar_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_FILTER_COMBO_BOX: + g_value_set_object ( + value, e_shell_searchbar_get_filter_combo_box ( + E_SHELL_SEARCHBAR (object))); + return; + + case PROP_FILTER_VISIBLE: + g_value_set_boolean ( + value, e_shell_searchbar_get_filter_visible ( + E_SHELL_SEARCHBAR (object))); + return; + + case PROP_SEARCH_HINT: + g_value_set_string ( + value, e_shell_searchbar_get_search_hint ( + E_SHELL_SEARCHBAR (object))); + return; + + case PROP_SEARCH_OPTION: + g_value_set_object ( + value, e_shell_searchbar_get_search_option ( + E_SHELL_SEARCHBAR (object))); + return; + + case PROP_SEARCH_TEXT: + g_value_set_string ( + value, e_shell_searchbar_get_search_text ( + E_SHELL_SEARCHBAR (object))); + return; + + case PROP_SEARCH_VISIBLE: + g_value_set_boolean ( + value, e_shell_searchbar_get_search_visible ( + E_SHELL_SEARCHBAR (object))); + return; + + case PROP_SCOPE_COMBO_BOX: + g_value_set_object ( + value, e_shell_searchbar_get_scope_combo_box ( + E_SHELL_SEARCHBAR (object))); + return; + + case PROP_SCOPE_VISIBLE: + g_value_set_boolean ( + value, e_shell_searchbar_get_scope_visible ( + E_SHELL_SEARCHBAR (object))); + return; + + case PROP_SHELL_VIEW: + g_value_set_object ( + value, e_shell_searchbar_get_shell_view ( + E_SHELL_SEARCHBAR (object))); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +shell_searchbar_dispose (GObject *object) +{ + EShellSearchbarPrivate *priv; + + priv = E_SHELL_SEARCHBAR_GET_PRIVATE (object); + + if (priv->shell_view != NULL) { + g_object_remove_weak_pointer ( + G_OBJECT (priv->shell_view), &priv->shell_view); + priv->shell_view = NULL; + } + + if (priv->search_option != NULL) { + g_signal_handlers_disconnect_matched ( + priv->search_option, G_SIGNAL_MATCH_DATA, + 0, 0, NULL, NULL, object); + g_object_unref (priv->search_option); + priv->search_option = NULL; + } + + /* Chain up to parent's dispose() method. */ + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +shell_searchbar_constructed (GObject *object) +{ + EShellView *shell_view; + EShellWindow *shell_window; + EShellSearchbar *searchbar; + GtkSizeGroup *size_group; + GtkAction *action; + GtkWidget *widget; + + searchbar = E_SHELL_SEARCHBAR (object); + shell_view = e_shell_searchbar_get_shell_view (searchbar); + shell_window = e_shell_view_get_shell_window (shell_view); + size_group = e_shell_view_get_size_group (shell_view); + + g_signal_connect ( + shell_view, "clear-search", + G_CALLBACK (shell_searchbar_clear_search_cb), + searchbar); + + g_signal_connect ( + shell_view, "custom-search", + G_CALLBACK (shell_searchbar_custom_search_cb), + searchbar); + + g_signal_connect_after ( + shell_view, "execute-search", + G_CALLBACK (shell_searchbar_execute_search_cb), + searchbar); + + widget = searchbar->priv->search_entry; + + action = E_SHELL_WINDOW_ACTION_SEARCH_CLEAR (shell_window); + + e_binding_new ( + action, "sensitive", + widget, "secondary-icon-sensitive"); + e_binding_new ( + action, "stock-id", + widget, "secondary-icon-stock"); + e_binding_new ( + action, "tooltip", + widget, "secondary-icon-tooltip-text"); + + action = E_SHELL_WINDOW_ACTION_SEARCH_OPTIONS (shell_window); + + e_binding_new ( + action, "sensitive", + widget, "primary-icon-sensitive"); + e_binding_new ( + action, "stock-id", + widget, "primary-icon-stock"); + e_binding_new ( + action, "tooltip", + widget, "primary-icon-tooltip-text"); + + widget = GTK_WIDGET (searchbar); + gtk_size_group_add_widget (size_group, widget); +} + +static void +shell_searchbar_class_init (EShellSearchbarClass *class) +{ + GObjectClass *object_class; + + parent_class = g_type_class_peek_parent (class); + g_type_class_add_private (class, sizeof (EShellSearchbarPrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->set_property = shell_searchbar_set_property; + object_class->get_property = shell_searchbar_get_property; + object_class->dispose = shell_searchbar_dispose; + object_class->constructed = shell_searchbar_constructed; + + g_object_class_install_property ( + object_class, + PROP_FILTER_COMBO_BOX, + g_param_spec_object ( + "filter-combo-box", + NULL, + NULL, + E_TYPE_ACTION_COMBO_BOX, + G_PARAM_READABLE)); + + g_object_class_install_property ( + object_class, + PROP_FILTER_VISIBLE, + g_param_spec_boolean ( + "filter-visible", + NULL, + NULL, + TRUE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property ( + object_class, + PROP_SEARCH_HINT, + g_param_spec_string ( + "search-hint", + NULL, + NULL, + NULL, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + object_class, + PROP_SEARCH_OPTION, + g_param_spec_object ( + "search-option", + NULL, + NULL, + GTK_TYPE_RADIO_ACTION, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + object_class, + PROP_SEARCH_TEXT, + g_param_spec_string ( + "search-text", + NULL, + NULL, + NULL, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + object_class, + PROP_SEARCH_VISIBLE, + g_param_spec_boolean ( + "search-visible", + NULL, + NULL, + TRUE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property ( + object_class, + PROP_SCOPE_COMBO_BOX, + g_param_spec_object ( + "scope-combo-box", + NULL, + NULL, + E_TYPE_ACTION_COMBO_BOX, + G_PARAM_READABLE)); + + g_object_class_install_property ( + object_class, + PROP_SCOPE_VISIBLE, + g_param_spec_boolean ( + "scope-visible", + NULL, + NULL, + FALSE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + /** + * EShellContent:shell-view + * + * The #EShellView to which the searchbar widget belongs. + **/ + g_object_class_install_property ( + object_class, + PROP_SHELL_VIEW, + g_param_spec_object ( + "shell-view", + NULL, + NULL, + E_TYPE_SHELL_VIEW, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY)); +} + +static void +shell_searchbar_init (EShellSearchbar *searchbar) +{ + GtkBox *box; + GtkLabel *label; + GtkWidget *widget; + + searchbar->priv = E_SHELL_SEARCHBAR_GET_PRIVATE (searchbar); + + gtk_box_set_spacing (GTK_BOX (searchbar), 24); + + /* Filter Combo Widgets */ + + box = GTK_BOX (searchbar); + + widget = gtk_hbox_new (FALSE, 3); + gtk_box_pack_start (box, widget, FALSE, FALSE, 0); + + e_binding_new ( + searchbar, "filter-visible", + widget, "visible"); + + box = GTK_BOX (widget); + + /* Translators: The "Show:" label precedes a combo box that + * allows the user to filter the current view. Examples of + * items that appear in the combo box are "Unread Messages", + * "Important Messages", or "Active Appointments". */ + widget = gtk_label_new_with_mnemonic (_("Sho_w:")); + gtk_box_pack_start (box, widget, FALSE, FALSE, 0); + gtk_widget_show (widget); + + label = GTK_LABEL (widget); + + widget = e_action_combo_box_new (); + gtk_label_set_mnemonic_widget (label, widget); + gtk_box_pack_start (box, widget, FALSE, FALSE, 0); + searchbar->priv->filter_combo_box = widget; + gtk_widget_show (widget); + + /* Search Entry Widgets */ + + box = GTK_BOX (searchbar); + + widget = gtk_hbox_new (FALSE, 3); + gtk_box_pack_start (box, widget, TRUE, TRUE, 0); + + e_binding_new ( + searchbar, "search-visible", + widget, "visible"); + + box = GTK_BOX (widget); + + /* Translators: This is part of the quick search interface. + * example: Search: [_______________] in [ Current Folder ] */ + widget = gtk_label_new_with_mnemonic (_("Sear_ch:")); + gtk_box_pack_start (box, widget, FALSE, FALSE, 0); + gtk_widget_show (widget); + + label = GTK_LABEL (widget); + + widget = e_hinted_entry_new (); + gtk_label_set_mnemonic_widget (label, widget); + gtk_box_pack_start (box, widget, TRUE, TRUE, 0); + searchbar->priv->search_entry = widget; + gtk_widget_show (widget); + + g_signal_connect_swapped ( + widget, "activate", + G_CALLBACK (shell_searchbar_entry_activate_cb), + searchbar); + + g_signal_connect_swapped ( + widget, "changed", + G_CALLBACK (shell_searchbar_entry_changed_cb), + searchbar); + + g_signal_connect_swapped ( + widget, "icon-press", + G_CALLBACK (shell_searchbar_entry_icon_press_cb), + searchbar); + + g_signal_connect_swapped ( + widget, "icon-release", + G_CALLBACK (shell_searchbar_entry_icon_release_cb), + searchbar); + + g_signal_connect_swapped ( + widget, "key-press-event", + G_CALLBACK (shell_searchbar_entry_key_press_cb), + searchbar); + + /* Scope Combo Widgets */ + + box = GTK_BOX (searchbar); + + widget = gtk_hbox_new (FALSE, 3); + gtk_box_pack_start (box, widget, FALSE, FALSE, 0); + + e_binding_new ( + searchbar, "scope-visible", + widget, "visible"); + + box = GTK_BOX (widget); + + /* Translators: This is part of the quick search interface. + * example: Search: [_______________] in [ Current Folder ] */ + widget = gtk_label_new_with_mnemonic (_("i_n")); + gtk_box_pack_start (box, widget, FALSE, FALSE, 0); + gtk_widget_show (widget); + + label = GTK_LABEL (widget); + + widget = e_action_combo_box_new (); + gtk_label_set_mnemonic_widget (label, widget); + gtk_box_pack_start (box, widget, FALSE, FALSE, 0); + searchbar->priv->scope_combo_box = widget; + gtk_widget_show (widget); +} + +GType +e_shell_searchbar_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) { + static const GTypeInfo type_info = { + sizeof (EShellSearchbarClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) shell_searchbar_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (EShellSearchbar), + 0, /* n_preallocs */ + (GInstanceInitFunc) shell_searchbar_init, + NULL /* value_table */ + }; + + type = g_type_register_static ( + GTK_TYPE_BOX, "EShellSearchbar", &type_info, 0); + } + + return type; +} + +/** + * e_shell_searchbar_new: + * @shell_view: an #EShellView + * + * Creates a new #EShellSearchbar instance. + * + * Returns: a new #EShellSearchbar instance + **/ +GtkWidget * +e_shell_searchbar_new (EShellView *shell_view) +{ + g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL); + + return g_object_new ( + E_TYPE_SHELL_SEARCHBAR, "shell-view", shell_view, NULL); +} + +/** + * e_shell_searchbar_get_shell_view: + * @searchbar: an #EShellSearchbar + * + * Returns the #EShellView that was passed to e_shell_searchbar_new(). + * + * Returns: the #EShellView to which @searchbar belongs + **/ +EShellView * +e_shell_searchbar_get_shell_view (EShellSearchbar *searchbar) +{ + g_return_val_if_fail (E_IS_SHELL_SEARCHBAR (searchbar), NULL); + + return E_SHELL_VIEW (searchbar->priv->shell_view); +} + +EActionComboBox * +e_shell_searchbar_get_filter_combo_box (EShellSearchbar *searchbar) +{ + g_return_val_if_fail (E_IS_SHELL_SEARCHBAR (searchbar), NULL); + + return E_ACTION_COMBO_BOX (searchbar->priv->filter_combo_box); +} + +gboolean +e_shell_searchbar_get_filter_visible (EShellSearchbar *searchbar) +{ + g_return_val_if_fail (E_IS_SHELL_SEARCHBAR (searchbar), FALSE); + + return searchbar->priv->filter_visible; +} + +void +e_shell_searchbar_set_filter_visible (EShellSearchbar *searchbar, + gboolean filter_visible) +{ + g_return_if_fail (E_IS_SHELL_SEARCHBAR (searchbar)); + + searchbar->priv->filter_visible = filter_visible; + + g_object_notify (G_OBJECT (searchbar), "filter-visible"); +} + +const gchar * +e_shell_searchbar_get_search_hint (EShellSearchbar *searchbar) +{ + EHintedEntry *entry; + + g_return_val_if_fail (E_IS_SHELL_SEARCHBAR (searchbar), NULL); + + entry = E_HINTED_ENTRY (searchbar->priv->search_entry); + + return e_hinted_entry_get_hint (entry); +} + +void +e_shell_searchbar_set_search_hint (EShellSearchbar *searchbar, + const gchar *search_hint) +{ + EHintedEntry *entry; + + g_return_if_fail (E_IS_SHELL_SEARCHBAR (searchbar)); + + entry = E_HINTED_ENTRY (searchbar->priv->search_entry); + + e_hinted_entry_set_hint (entry, search_hint); + + g_object_notify (G_OBJECT (searchbar), "search-hint"); +} + +GtkRadioAction * +e_shell_searchbar_get_search_option (EShellSearchbar *searchbar) +{ + g_return_val_if_fail (E_IS_SHELL_SEARCHBAR (searchbar), NULL); + + return searchbar->priv->search_option; +} + +void +e_shell_searchbar_set_search_option (EShellSearchbar *searchbar, + GtkRadioAction *search_option) +{ + g_return_if_fail (E_IS_SHELL_SEARCHBAR (searchbar)); + + if (search_option != NULL) { + g_return_if_fail (GTK_IS_RADIO_ACTION (search_option)); + g_object_ref (search_option); + } + + if (searchbar->priv->search_option != NULL) { + g_signal_handlers_disconnect_matched ( + searchbar->priv->search_option, + G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, + searchbar); + g_object_unref (searchbar->priv->search_option); + } + + searchbar->priv->search_option = search_option; + + if (search_option != NULL) + g_signal_connect ( + search_option, "changed", + G_CALLBACK (shell_searchbar_option_changed_cb), + searchbar); + + g_object_notify (G_OBJECT (searchbar), "search-option"); +} + +const gchar * +e_shell_searchbar_get_search_text (EShellSearchbar *searchbar) +{ + EHintedEntry *entry; + + g_return_val_if_fail (E_IS_SHELL_SEARCHBAR (searchbar), NULL); + + entry = E_HINTED_ENTRY (searchbar->priv->search_entry); + + return e_hinted_entry_get_text (entry); +} + +void +e_shell_searchbar_set_search_text (EShellSearchbar *searchbar, + const gchar *search_text) +{ + EHintedEntry *entry; + + g_return_if_fail (E_IS_SHELL_SEARCHBAR (searchbar)); + + entry = E_HINTED_ENTRY (searchbar->priv->search_entry); + + e_hinted_entry_set_text (entry, search_text); + + shell_searchbar_update_search_widgets (searchbar); + + g_object_notify (G_OBJECT (searchbar), "search-text"); +} + +gboolean +e_shell_searchbar_get_search_visible (EShellSearchbar *searchbar) +{ + g_return_val_if_fail (E_IS_SHELL_SEARCHBAR (searchbar), FALSE); + + return searchbar->priv->search_visible; +} + +void +e_shell_searchbar_set_search_visible (EShellSearchbar *searchbar, + gboolean search_visible) +{ + g_return_if_fail (E_IS_SHELL_SEARCHBAR (searchbar)); + + searchbar->priv->search_visible = search_visible; + + g_object_notify (G_OBJECT (searchbar), "search-visible"); +} + +EActionComboBox * +e_shell_searchbar_get_scope_combo_box (EShellSearchbar *searchbar) +{ + g_return_val_if_fail (E_IS_SHELL_SEARCHBAR (searchbar), NULL); + + return E_ACTION_COMBO_BOX (searchbar->priv->scope_combo_box); +} + +gboolean +e_shell_searchbar_get_scope_visible (EShellSearchbar *searchbar) +{ + g_return_val_if_fail (E_IS_SHELL_SEARCHBAR (searchbar), FALSE); + + return searchbar->priv->scope_visible; +} + +void +e_shell_searchbar_set_scope_visible (EShellSearchbar *searchbar, + gboolean scope_visible) +{ + g_return_if_fail (E_IS_SHELL_SEARCHBAR (searchbar)); + + searchbar->priv->scope_visible = scope_visible; + + g_object_notify (G_OBJECT (searchbar), "scope-visible"); +} + +void +e_shell_searchbar_restore_state (EShellSearchbar *searchbar, + const gchar *group_name) +{ + EShellView *shell_view; + EShellWindow *shell_window; + GKeyFile *key_file; + GtkAction *action; + GtkWidget *widget; + const gchar *search_text; + const gchar *key; + gchar *string; + + g_return_if_fail (E_IS_SHELL_SEARCHBAR (searchbar)); + g_return_if_fail (group_name != NULL); + + shell_view = e_shell_searchbar_get_shell_view (searchbar); + shell_window = e_shell_view_get_shell_window (shell_view); + key_file = e_shell_view_get_state_key_file (shell_view); + + /* Changing the combo boxes triggers searches, so block + * the search action until the state is fully restored. */ + action = E_SHELL_WINDOW_ACTION_SEARCH_QUICK (shell_window); + gtk_action_block_activate (action); + + e_shell_view_block_execute_search (shell_view); + + key = STATE_KEY_SEARCH_FILTER; + string = g_key_file_get_string (key_file, group_name, key, NULL); + if (string != NULL && *string != '\0') + action = e_shell_window_get_action (shell_window, string); + else + action = NULL; + if (action != NULL) + gtk_action_activate (action); + else { + /* Pick the first combo box item. */ + widget = searchbar->priv->filter_combo_box; + gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 0); + } + g_free (string); + + key = STATE_KEY_SEARCH_SCOPE; + string = g_key_file_get_string (key_file, group_name, key, NULL); + if (string != NULL && *string != '\0') + action = e_shell_window_get_action (shell_window, string); + else + action = NULL; + if (action != NULL) + gtk_action_activate (action); + else { + /* Pick the first combo box item. */ + widget = searchbar->priv->scope_combo_box; + gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 0); + } + g_free (string); + + key = STATE_KEY_SEARCH_TEXT; + string = g_key_file_get_string (key_file, group_name, key, NULL); + search_text = e_shell_searchbar_get_search_text (searchbar); + if (search_text != NULL && *search_text == '\0') + search_text = NULL; + if (g_strcmp0 (string, search_text) != 0) + e_shell_searchbar_set_search_text (searchbar, string); + g_free (string); + + e_shell_view_unblock_execute_search (shell_view); + + action = E_SHELL_WINDOW_ACTION_SEARCH_QUICK (shell_window); + gtk_action_unblock_activate (action); + + /* Now execute the search. */ + e_shell_view_execute_search (shell_view); +} diff --git a/shell/e-shell-searchbar.h b/shell/e-shell-searchbar.h new file mode 100644 index 0000000000..b6104491b4 --- /dev/null +++ b/shell/e-shell-searchbar.h @@ -0,0 +1,119 @@ +/* + * e-shell-searchbar.h + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +/** + * SECTION: e-shell-searchbar + * @short_description: quick search interface + * @include: shell/e-shell-searchbar.h + **/ + +#ifndef E_SHELL_SEARCHBAR_H +#define E_SHELL_SEARCHBAR_H + +#include <shell/e-shell-common.h> +#include <shell/e-shell-view.h> +#include <misc/e-action-combo-box.h> + +/* Standard GObject macros */ +#define E_TYPE_SHELL_SEARCHBAR \ + (e_shell_searchbar_get_type ()) +#define E_SHELL_SEARCHBAR(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_SHELL_SEARCHBAR, EShellSearchbar)) +#define E_SHELL_SEARCHBAR_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_SHELL_SEARCHBAR, EShellSearchbarClass)) +#define E_IS_SHELL_SEARCHBAR(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_SHELL_SEARCHBAR)) +#define E_IS_SHELL_SEARCHBAR_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_SHELL_SEARCHBAR)) +#define E_SHELL_SEARCHBAR_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_SHELL_SEARCHBAR, EShellSearchbarClass)) + +G_BEGIN_DECLS + +typedef struct _EShellSearchbar EShellSearchbar; +typedef struct _EShellSearchbarClass EShellSearchbarClass; +typedef struct _EShellSearchbarPrivate EShellSearchbarPrivate; + +/** + * EShellSearchbar: + * + * Contains only private data that should be read and manipulated using the + * functions below. + **/ +struct _EShellSearchbar { + GtkBox parent; + EShellSearchbarPrivate *priv; +}; + +struct _EShellSearchbarClass { + GtkBoxClass parent_class; +}; + +GType e_shell_searchbar_get_type (void); +GtkWidget * e_shell_searchbar_new (EShellView *shell_view); +EShellView * e_shell_searchbar_get_shell_view(EShellSearchbar *searchbar); +EActionComboBox * + e_shell_searchbar_get_filter_combo_box + (EShellSearchbar *searchbar); +gboolean e_shell_searchbar_get_filter_visible + (EShellSearchbar *searchbar); +void e_shell_searchbar_set_filter_visible + (EShellSearchbar *searchbar, + gboolean filter_visible); +const gchar * e_shell_searchbar_get_search_hint + (EShellSearchbar *searchbar); +void e_shell_searchbar_set_search_hint + (EShellSearchbar *searchbar, + const gchar *search_hint); +GtkRadioAction *e_shell_searchbar_get_search_option + (EShellSearchbar *searchbar); +void e_shell_searchbar_set_search_option + (EShellSearchbar *searchbar, + GtkRadioAction *search_option); +const gchar * e_shell_searchbar_get_search_text + (EShellSearchbar *searchbar); +void e_shell_searchbar_set_search_text + (EShellSearchbar *searchbar, + const gchar *search_text); +gboolean e_shell_searchbar_get_search_visible + (EShellSearchbar *searchbar); +void e_shell_searchbar_set_search_visible + (EShellSearchbar *searchbar, + gboolean search_visible); +EActionComboBox * + e_shell_searchbar_get_scope_combo_box + (EShellSearchbar *searchbar); +gboolean e_shell_searchbar_get_scope_visible + (EShellSearchbar *searchbar); +void e_shell_searchbar_set_scope_visible + (EShellSearchbar *searchbar, + gboolean scope_visible); +void e_shell_searchbar_restore_state (EShellSearchbar *searchbar, + const gchar *group_name); + +G_END_DECLS + +#endif /* E_SHELL_SEARCHBAR_H */ diff --git a/shell/e-shell-view.c b/shell/e-shell-view.c index 2439706224..d87f8b7632 100644 --- a/shell/e-shell-view.c +++ b/shell/e-shell-view.c @@ -26,6 +26,7 @@ #include "e-util/e-util.h" #include "e-util/e-plugin-ui.h" +#include "filter/e-rule-context.h" #include "e-shell-window-actions.h" @@ -53,6 +54,7 @@ struct _EShellViewPrivate { GtkWidget *shell_sidebar; GtkWidget *shell_taskbar; + EFilterRule *search_rule; guint execute_search_blocked; }; @@ -60,18 +62,21 @@ enum { PROP_0, PROP_ACTION, PROP_PAGE_NUM, - PROP_TITLE, + PROP_SEARCH_RULE, PROP_SHELL_BACKEND, PROP_SHELL_CONTENT, PROP_SHELL_SIDEBAR, PROP_SHELL_TASKBAR, PROP_SHELL_WINDOW, PROP_STATE_KEY_FILE, + PROP_TITLE, PROP_VIEW_ID }; enum { TOGGLED, + CLEAR_SEARCH, + CUSTOM_SEARCH, EXECUTE_SEARCH, UPDATE_ACTIONS, LAST_SIGNAL @@ -81,6 +86,61 @@ static gpointer parent_class; static gulong signals[LAST_SIGNAL]; static void +shell_view_init_search_context (EShellViewClass *class) +{ + EShellBackend *shell_backend; + ERuleContext *search_context; + EFilterRule *rule; + EFilterPart *part; + const gchar *data_dir; + gchar *system_filename; + gchar *user_filename; + + shell_backend = class->shell_backend; + + /* Sanity check the class fields we need. */ + g_return_if_fail (class->search_rules != NULL); + g_return_if_fail (E_IS_SHELL_BACKEND (shell_backend)); + + /* The basename for built-in searches is specified in the + * shell view class. All built-in search rules live in the + * same directory. */ + system_filename = g_build_filename ( + EVOLUTION_RULEDIR, class->search_rules, NULL); + + /* The filename for custom saved searches is always of + * the form "$(shell_backend_data_dir)/searches.xml". */ + data_dir = e_shell_backend_get_data_dir (shell_backend); + user_filename = g_build_filename (data_dir, "searches.xml", NULL); + + /* Create the search context instance. Subclasses may override + * the GType so check that it's really an ERuleContext instance. */ + search_context = g_object_new (class->search_context_type, NULL); + g_return_if_fail (E_IS_RULE_CONTEXT (search_context)); + class->search_context = search_context; + + e_rule_context_add_part_set ( + search_context, "partset", E_TYPE_FILTER_PART, + e_rule_context_add_part, e_rule_context_next_part); + e_rule_context_add_rule_set ( + search_context, "ruleset", E_TYPE_FILTER_RULE, + e_rule_context_add_rule, e_rule_context_next_rule); + e_rule_context_load (search_context, system_filename, user_filename); + + rule = e_filter_rule_new (); + part = e_rule_context_next_part (search_context, NULL); + if (part == NULL) + g_warning ( + "Could not load %s search: no parts", + G_OBJECT_CLASS_NAME (class)); + else + e_filter_rule_add_part (rule, e_filter_part_clone (part)); + + g_free (system_filename); + g_free (user_filename); +} + +static void shell_view_init_view_collection (EShellViewClass *class) { EShellBackend *shell_backend; @@ -249,10 +309,10 @@ shell_view_set_property (GObject *object, g_value_get_int (value)); return; - case PROP_TITLE: - e_shell_view_set_title ( + case PROP_SEARCH_RULE: + e_shell_view_set_search_rule ( E_SHELL_VIEW (object), - g_value_get_string (value)); + g_value_get_object (value)); return; case PROP_SHELL_WINDOW: @@ -261,6 +321,12 @@ shell_view_set_property (GObject *object, g_value_get_object (value)); return; + case PROP_TITLE: + e_shell_view_set_title ( + E_SHELL_VIEW (object), + g_value_get_string (value)); + return; + case PROP_VIEW_ID: e_shell_view_set_view_id ( E_SHELL_VIEW (object), @@ -290,9 +356,9 @@ shell_view_get_property (GObject *object, E_SHELL_VIEW (object))); return; - case PROP_TITLE: - g_value_set_string ( - value, e_shell_view_get_title ( + case PROP_SEARCH_RULE: + g_value_set_object ( + value, e_shell_view_get_search_rule ( E_SHELL_VIEW (object))); return; @@ -331,6 +397,12 @@ shell_view_get_property (GObject *object, E_SHELL_VIEW (object))); return; + case PROP_TITLE: + g_value_set_string ( + value, e_shell_view_get_title ( + E_SHELL_VIEW (object))); + return; + case PROP_VIEW_ID: g_value_set_string ( value, e_shell_view_get_view_id ( @@ -376,6 +448,11 @@ shell_view_dispose (GObject *object) priv->shell_taskbar = NULL; } + if (priv->search_rule != NULL) { + g_object_unref (priv->search_rule); + priv->search_rule = NULL; + } + /* Chain up to parent's dispose() method. */ G_OBJECT_CLASS (parent_class)->dispose (object); } @@ -430,6 +507,21 @@ shell_view_constructed (GObject *object) } static void +shell_view_clear_search (EShellView *shell_view) +{ + e_shell_view_set_search_rule (shell_view, NULL); + e_shell_view_execute_search (shell_view); +} + +static void +shell_view_custom_search (EShellView *shell_view, + EFilterRule *custom_rule) +{ + e_shell_view_set_search_rule (shell_view, custom_rule); + e_shell_view_execute_search (shell_view); +} + +static void shell_view_toggled (EShellView *shell_view) { EShellViewPrivate *priv = shell_view->priv; @@ -475,11 +567,15 @@ shell_view_class_init (EShellViewClass *class) object_class->finalize = shell_view_finalize; object_class->constructed = shell_view_constructed; + class->search_context_type = E_TYPE_RULE_CONTEXT; + /* Default Factories */ class->new_shell_content = e_shell_content_new; class->new_shell_sidebar = e_shell_sidebar_new; class->new_shell_taskbar = e_shell_taskbar_new; + class->clear_search = shell_view_clear_search; + class->custom_search = shell_view_custom_search; class->toggled = shell_view_toggled; /** @@ -516,23 +612,22 @@ shell_view_class_init (EShellViewClass *class) G_PARAM_READWRITE)); /** - * EShellView:title + * EShellView:search-rule * - * The title of the shell view. Also serves as the #EShellWindow - * title when the shell view is active. + * Criteria for the current search results. **/ g_object_class_install_property ( object_class, - PROP_TITLE, - g_param_spec_string ( - "title", - _("Title"), - _("The title of the shell view"), - NULL, + PROP_SEARCH_RULE, + g_param_spec_object ( + "search-rule", + _("Search Rule"), + _("Criteria for the current search results"), + E_TYPE_FILTER_RULE, G_PARAM_READWRITE)); /** - * EShellView::shell-backend + * EShellView:shell-backend * * The #EShellBackend for this shell view. **/ @@ -627,6 +722,22 @@ shell_view_class_init (EShellViewClass *class) G_PARAM_READABLE)); /** + * EShellView:title + * + * The title of the shell view. Also serves as the #EShellWindow + * title when the shell view is active. + **/ + g_object_class_install_property ( + object_class, + PROP_TITLE, + g_param_spec_string ( + "title", + _("Title"), + _("The title of the shell view"), + NULL, + G_PARAM_READWRITE)); + + /** * EShellView:view-id * * The current #GalView ID. @@ -665,6 +776,40 @@ shell_view_class_init (EShellViewClass *class) G_TYPE_NONE, 0); /** + * EShellView::clear-search + * @shell_view: the #EShellView which emitted the signal + * + * Clears the current search. See e_shell_view_clear_search() for + * details. + **/ + signals[CLEAR_SEARCH] = g_signal_new ( + "clear-search", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EShellViewClass, clear_search), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + /** + * EShellView::custom-search + * @shell_view: the #EShellView which emitted the signal + * @custom_rule: criteria for the custom search + * + * Emitted when an advanced or saved search is about to be executed. + * See e_shell_view_custom_search() for details. + **/ + signals[CUSTOM_SEARCH] = g_signal_new ( + "custom-search", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EShellViewClass, custom_search), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + E_TYPE_FILTER_RULE); + + /** * EShellView::execute-search * @shell_view: the #EShellView which emitted the signal * @@ -709,6 +854,9 @@ shell_view_init (EShellView *shell_view, { GtkSizeGroup *size_group; + if (class->search_context == NULL) + shell_view_init_search_context (class); + if (class->view_collection == NULL) shell_view_init_view_collection (class); @@ -963,6 +1111,78 @@ e_shell_view_set_page_num (EShellView *shell_view, } /** + * e_shell_view_get_search_rule: + * @shell_view: an #EShellView + * + * Returns the search criteria used to generate the current search results. + * + * Returns: the current search criteria + **/ +EFilterRule * +e_shell_view_get_search_rule (EShellView *shell_view) +{ + g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL); + + return shell_view->priv->search_rule; +} + +/** + * e_shell_view_set_search_rule: + * @shell_view: an #EShellView + * @search_rule: an #EFilterRule + * + * Sets the search criteria used to generate the current search results. + * Note that this will not trigger a search. e_shell_view_execute_search() + * must be called explicitly. + **/ +void +e_shell_view_set_search_rule (EShellView *shell_view, + EFilterRule *search_rule) +{ + g_return_if_fail (E_IS_SHELL_VIEW (shell_view)); + + if (search_rule != NULL) { + g_return_if_fail (E_IS_FILTER_RULE (search_rule)); + g_object_ref (search_rule); + } + + if (shell_view->priv->search_rule != NULL) + g_object_unref (shell_view->priv->search_rule); + + shell_view->priv->search_rule = search_rule; + + g_object_notify (G_OBJECT (shell_view), "search-rule"); +} + +/** + * e_shell_view_get_search_query: + * @shell_view: an #EShellView + * + * Converts the #EShellView:search-rule property to a newly-allocated + * S-expression string. If the #EShellView:search-rule property is %NULL + * the function returns %NULL. + * + * Returns: an S-expression string, or %NULL + **/ +gchar * +e_shell_view_get_search_query (EShellView *shell_view) +{ + EFilterRule *rule; + GString *string; + + g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL); + + rule = e_shell_view_get_search_rule (shell_view); + if (rule == NULL) + return NULL; + + string = g_string_sized_new (1024); + e_filter_rule_build_code (rule, string); + + return g_string_free (string, FALSE); +} + +/** * e_shell_view_get_size_group: * @shell_view: an #EShellView * @@ -1109,6 +1329,44 @@ e_shell_view_set_state_dirty (EShellView *shell_view) } /** + * e_shell_view_clear_search: + * @shell_view: an #EShellView + * + * Emits the #EShellView::clear-search signal. + * + * The default method sets the #EShellView:search-rule property to + * %NULL and then emits the #EShellView::execute-search signal. + **/ +void +e_shell_view_clear_search (EShellView *shell_view) +{ + g_return_if_fail (E_IS_SHELL_VIEW (shell_view)); + + g_signal_emit (shell_view, signals[CLEAR_SEARCH], 0); +} + +/** + * e_shell_view_custom_search: + * @shell_view: an #EShellView + * @custom_rule: an #EFilterRule + * + * Emits the #EShellView::custom-search signal to indicate an advanced + * or saved search is about to be executed. + * + * The default method sets the #EShellView:search-rule property to + * @custom_rule and then emits the #EShellView::execute-search signal. + **/ +void +e_shell_view_custom_search (EShellView *shell_view, + EFilterRule *custom_rule) +{ + g_return_if_fail (E_IS_SHELL_VIEW (shell_view)); + g_return_if_fail (E_IS_FILTER_RULE (custom_rule)); + + g_signal_emit (shell_view, signals[CUSTOM_SEARCH], 0, custom_rule); +} + +/** * e_shell_view_execute_search: * @shell_view: an #EShellView * diff --git a/shell/e-shell-view.h b/shell/e-shell-view.h index 8cbfabd0ba..60f3fcbdd2 100644 --- a/shell/e-shell-view.h +++ b/shell/e-shell-view.h @@ -35,6 +35,8 @@ #include <shell/e-shell-taskbar.h> #include <shell/e-shell-window.h> +#include <filter/e-filter-rule.h> +#include <filter/e-rule-context.h> #include <menus/gal-view-collection.h> #include <menus/gal-view-instance.h> @@ -88,6 +90,11 @@ struct _EShellView { * @ui_manager_id: The #GtkUIManager ID for #EPluginUI. Plugins * should use to this ID in their "eplug" files to * add menu and toolbar items to the shell view. + * @search_context_type:GType of the search context, which should be an + * instance of ERuleContextClass or a custom subclass. + * @search_context: A unique @search_context_type instance is created + * automatically for each subclass and shared across + * all instances of that subclass. * @search_options: Widget path in the UI definition to the search * options popup menu. The menu gets shown when the * user clicks the "find" icon in the search entry. @@ -111,6 +118,11 @@ struct _EShellView { * @toggled: Class method for the #EShellView::toggled signal. * Subclasses should rarely need to override the * default behavior. + * @custom_search: Class method for the #EShellView::custom-search + * signal. This is emitted prior to executing an + * advanced or saved search. The default method sets + * the #EShellView:search-rule property and then emits + * the #EShellView::execute-search signal. * @execute_search: Class method for the #EShellView::execute-search * signal. There is no default behavior; subclasses * should override this. @@ -134,6 +146,11 @@ struct _EShellViewClass { * Usually "org.gnome.evolution.$(VIEW_NAME)". */ const gchar *ui_manager_id; + /* Search context. Subclasses may override the type. + * A unique instance is created for each subclass. */ + GType search_context_type; + ERuleContext *search_context; + /* Widget path to the search options popup menu. */ const gchar *search_options; @@ -153,6 +170,9 @@ struct _EShellViewClass { /* Signals */ void (*toggled) (EShellView *shell_view); + void (*clear_search) (EShellView *shell_view); + void (*custom_search) (EShellView *shell_view, + EFilterRule *custom_rule); void (*execute_search) (EShellView *shell_view); void (*update_actions) (EShellView *shell_view); }; @@ -170,6 +190,10 @@ gboolean e_shell_view_is_active (EShellView *shell_view); gint e_shell_view_get_page_num (EShellView *shell_view); void e_shell_view_set_page_num (EShellView *shell_view, gint page_num); +EFilterRule * e_shell_view_get_search_rule (EShellView *shell_view); +void e_shell_view_set_search_rule (EShellView *shell_view, + EFilterRule *search_rule); +gchar * e_shell_view_get_search_query (EShellView *shell_view); GtkSizeGroup * e_shell_view_get_size_group (EShellView *shell_view); EShellBackend * e_shell_view_get_shell_backend (EShellView *shell_view); EShellContent * e_shell_view_get_shell_content (EShellView *shell_view); @@ -178,9 +202,14 @@ EShellTaskbar * e_shell_view_get_shell_taskbar (EShellView *shell_view); EShellWindow * e_shell_view_get_shell_window (EShellView *shell_view); GKeyFile * e_shell_view_get_state_key_file (EShellView *shell_view); void e_shell_view_set_state_dirty (EShellView *shell_view); +void e_shell_view_clear_search (EShellView *shell_view); +void e_shell_view_custom_search (EShellView *shell_view, + EFilterRule *custom_rule); void e_shell_view_execute_search (EShellView *shell_view); -void e_shell_view_block_execute_search (EShellView *shell_view); -void e_shell_view_unblock_execute_search (EShellView *shell_view); +void e_shell_view_block_execute_search + (EShellView *shell_view); +void e_shell_view_unblock_execute_search + (EShellView *shell_view); void e_shell_view_update_actions (EShellView *shell_view); GtkWidget * e_shell_view_show_popup_menu (EShellView *shell_view, const gchar *widget_path, diff --git a/shell/e-shell-window-actions.c b/shell/e-shell-window-actions.c index 03fa5379eb..4483347beb 100644 --- a/shell/e-shell-window-actions.c +++ b/shell/e-shell-window-actions.c @@ -705,7 +705,6 @@ action_custom_rule_cb (GtkAction *action, { EFilterRule *rule; EShellView *shell_view; - EShellContent *shell_content; const gchar *view_name; rule = g_object_get_data (G_OBJECT (action), "rule"); @@ -713,14 +712,11 @@ action_custom_rule_cb (GtkAction *action, view_name = e_shell_window_get_active_view (shell_window); shell_view = e_shell_window_get_shell_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 (E_IS_FILTER_RULE (rule)); - e_shell_content_set_search_rule (shell_content, rule); - - e_shell_view_execute_search (shell_view); + e_shell_view_custom_search (shell_view, rule); } /** @@ -1044,25 +1040,12 @@ action_search_clear_cb (GtkAction *action, EShellWindow *shell_window) { EShellView *shell_view; - EShellContent *shell_content; - GtkRadioAction *search_action; const gchar *view_name; view_name = e_shell_window_get_active_view (shell_window); shell_view = e_shell_window_get_shell_view (shell_window, view_name); - shell_content = e_shell_view_get_shell_content (shell_view); - - e_shell_content_set_search_rule (shell_content, NULL); - e_shell_content_set_search_text (shell_content, NULL); - - /* change from Advanced Search to the first one, so filling a text will do something */ - search_action = e_shell_content_get_search_radio_action (shell_content); - if (search_action && gtk_radio_action_get_current_value (search_action) == -1) - gtk_radio_action_set_current_value (search_action, 0); - - e_shell_view_execute_search (shell_view); - e_shell_window_update_search_menu (shell_window); + e_shell_view_clear_search (shell_view); } /** @@ -1125,20 +1108,11 @@ static void action_search_quick_cb (GtkAction *action, EShellWindow *shell_window) { - EShellContent *shell_content; EShellView *shell_view; - GtkRadioAction *radio_action; const gchar *view_name; view_name = e_shell_window_get_active_view (shell_window); shell_view = e_shell_window_get_shell_view (shell_window, view_name); - shell_content = e_shell_view_get_shell_content (shell_view); - - radio_action = e_shell_content_get_search_radio_action (shell_content); - if (radio_action && gtk_radio_action_get_current_value (radio_action) == -1) { - /* change Advanced Search to a default search type automatically */ - gtk_radio_action_set_current_value (radio_action, 0); - } e_shell_view_execute_search (shell_view); } @@ -2213,7 +2187,6 @@ e_shell_window_update_view_menu (EShellWindow *shell_window) void e_shell_window_update_search_menu (EShellWindow *shell_window) { - EShellContent *shell_content; EShellView *shell_view; EShellViewClass *shell_view_class; ERuleContext *context; @@ -2237,15 +2210,14 @@ e_shell_window_update_search_menu (EShellWindow *shell_window) * Without this we would crash at E_SHELL_VIEW_GET_CLASS(). */ g_return_if_fail (shell_view != NULL); - 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); + context = shell_view_class->search_context; source = E_FILTER_SOURCE_INCOMING; /* Update sensitivity of search actions. */ - sensitive = (e_shell_content_get_search_rule (shell_content) != NULL); + sensitive = (e_shell_view_get_search_rule (shell_view) != NULL); gtk_action_set_sensitive (ACTION (SEARCH_CLEAR), sensitive); gtk_action_set_sensitive (ACTION (SEARCH_SAVE), sensitive); |