diff options
author | Matthew Barnes <mbarnes@redhat.com> | 2010-02-03 23:01:58 +0800 |
---|---|---|
committer | Matthew Barnes <mbarnes@redhat.com> | 2010-02-07 02:46:40 +0800 |
commit | 31e449ebed6a136e643ec3bf4c0d9f1b3fc87897 (patch) | |
tree | d3ab719626888d56370eee15e2bcc64c2cdbb072 | |
parent | c211d932475c1b53f118bceda65bc4915e90140a (diff) | |
download | gsoc2013-evolution-31e449ebed6a136e643ec3bf4c0d9f1b3fc87897.tar.gz gsoc2013-evolution-31e449ebed6a136e643ec3bf4c0d9f1b3fc87897.tar.zst gsoc2013-evolution-31e449ebed6a136e643ec3bf4c0d9f1b3fc87897.zip |
Implement account-wide search scope in mail.
Also, let EShellSearchbar handle search state persistence.
-rw-r--r-- | doc/reference/shell/tmpl/e-shell-searchbar.sgml | 14 | ||||
-rw-r--r-- | doc/reference/shell/tmpl/eshell-unused.sgml | 8 | ||||
-rw-r--r-- | modules/addressbook/e-book-shell-view-actions.c | 26 | ||||
-rw-r--r-- | modules/calendar/e-cal-shell-view-actions.c | 26 | ||||
-rw-r--r-- | modules/calendar/e-memo-shell-view-actions.c | 26 | ||||
-rw-r--r-- | modules/calendar/e-task-shell-view-actions.c | 26 | ||||
-rw-r--r-- | modules/mail/e-mail-shell-view-actions.c | 89 | ||||
-rw-r--r-- | modules/mail/e-mail-shell-view-private.c | 59 | ||||
-rw-r--r-- | modules/mail/e-mail-shell-view-private.h | 10 | ||||
-rw-r--r-- | modules/mail/e-mail-shell-view.c | 385 | ||||
-rw-r--r-- | shell/e-shell-searchbar.c | 263 | ||||
-rw-r--r-- | shell/e-shell-searchbar.h | 21 | ||||
-rw-r--r-- | shell/e-shell-view.c | 8 | ||||
-rw-r--r-- | shell/e-shell-window.c | 3 | ||||
-rw-r--r-- | widgets/misc/e-action-combo-box.c | 3 |
15 files changed, 745 insertions, 222 deletions
diff --git a/doc/reference/shell/tmpl/e-shell-searchbar.sgml b/doc/reference/shell/tmpl/e-shell-searchbar.sgml index aeedaf3f35..3c55a58f6d 100644 --- a/doc/reference/shell/tmpl/e-shell-searchbar.sgml +++ b/doc/reference/shell/tmpl/e-shell-searchbar.sgml @@ -73,6 +73,11 @@ EShellSearchbar </para> +<!-- ##### ARG EShellSearchbar:state-group ##### --> +<para> + +</para> + <!-- ##### FUNCTION e_shell_searchbar_new ##### --> <para> @@ -217,12 +222,3 @@ EShellSearchbar @scope_visible: -<!-- ##### FUNCTION e_shell_searchbar_restore_state ##### --> -<para> - -</para> - -@searchbar: -@group_name: - - diff --git a/doc/reference/shell/tmpl/eshell-unused.sgml b/doc/reference/shell/tmpl/eshell-unused.sgml index f0e339d5ab..8769407347 100644 --- a/doc/reference/shell/tmpl/eshell-unused.sgml +++ b/doc/reference/shell/tmpl/eshell-unused.sgml @@ -2649,6 +2649,14 @@ intelligent @online: @Returns: +<!-- ##### FUNCTION e_shell_searchbar_restore_state ##### --> +<para> + +</para> + +@searchbar: +@group_name: + <!-- ##### FUNCTION e_shell_set_line_status ##### --> <para> diff --git a/modules/addressbook/e-book-shell-view-actions.c b/modules/addressbook/e-book-shell-view-actions.c index 32b227c723..c439fafec8 100644 --- a/modules/addressbook/e-book-shell-view-actions.c +++ b/modules/addressbook/e-book-shell-view-actions.c @@ -655,14 +655,6 @@ action_gal_save_custom_view_cb (GtkAction *action, gal_view_instance_save_as (view_instance); } -static void -action_search_filter_cb (GtkRadioAction *action, - GtkRadioAction *current, - EShellView *shell_view) -{ - e_shell_view_execute_search (shell_view); -} - static GtkActionEntry contact_entries[] = { { "address-book-copy", @@ -1022,9 +1014,6 @@ e_book_shell_view_actions_init (EBookShellView *book_shell_view) gtk_action_set_visible (action, FALSE); e_shell_searchbar_set_search_option ( searchbar, GTK_RADIO_ACTION (action)); - gtk_radio_action_set_current_value ( - GTK_RADIO_ACTION (action), - CONTACT_SEARCH_NAME_CONTAINS); /* Lockdown Printing Actions */ action_group = ACTION_GROUP (LOCKDOWN_PRINTING); @@ -1097,13 +1086,13 @@ e_book_shell_view_update_search_filter (EBookShellView *book_shell_view) action_group = ACTION_GROUP (CONTACTS_FILTER); e_action_group_remove_all_actions (action_group); - /* Add the standard filter actions. */ + /* Add the standard filter actions. No callback is needed + * because changes in the EActionComboBox are detected and + * handled by EShellSearchbar. */ gtk_action_group_add_radio_actions ( action_group, contact_filter_entries, G_N_ELEMENTS (contact_filter_entries), - CONTACT_FILTER_ANY_CATEGORY, - G_CALLBACK (action_search_filter_cb), - book_shell_view); + CONTACT_FILTER_ANY_CATEGORY, NULL, NULL); /* Retrieve the radio group from an action we just added. */ list = gtk_action_group_list_actions (action_group); @@ -1154,12 +1143,17 @@ e_book_shell_view_update_search_filter (EBookShellView *book_shell_view) } g_list_free (list); - /* Use any action in the group; doesn't matter which. */ book_shell_content = book_shell_view->priv->book_shell_content; searchbar = e_book_shell_content_get_searchbar (book_shell_content); combo_box = e_shell_searchbar_get_filter_combo_box (searchbar); + + e_shell_view_block_execute_search (shell_view); + + /* Use any action in the group; doesn't matter which. */ e_action_combo_box_set_action (combo_box, radio_action); ii = CONTACT_FILTER_UNMATCHED; e_action_combo_box_add_separator_after (combo_box, ii); + + e_shell_view_unblock_execute_search (shell_view); } diff --git a/modules/calendar/e-cal-shell-view-actions.c b/modules/calendar/e-cal-shell-view-actions.c index 19fc7e6c53..03a6eb6bd3 100644 --- a/modules/calendar/e-cal-shell-view-actions.c +++ b/modules/calendar/e-cal-shell-view-actions.c @@ -1222,14 +1222,6 @@ action_gal_save_custom_view_cb (GtkAction *action, gal_view_instance_save_as (view_instance); } -static void -action_search_filter_cb (GtkRadioAction *action, - GtkRadioAction *current, - EShellView *shell_view) -{ - e_shell_view_execute_search (shell_view); -} - static GtkActionEntry calendar_entries[] = { { "calendar-copy", @@ -1719,9 +1711,6 @@ e_cal_shell_view_actions_init (ECalShellView *cal_shell_view) gtk_action_set_visible (action, FALSE); e_shell_searchbar_set_search_option ( searchbar, GTK_RADIO_ACTION (action)); - gtk_radio_action_set_current_value ( - GTK_RADIO_ACTION (action), - CALENDAR_SEARCH_SUMMARY_CONTAINS); /* Lockdown Printing Actions */ action_group = ACTION_GROUP (LOCKDOWN_PRINTING); @@ -1784,13 +1773,13 @@ e_cal_shell_view_update_search_filter (ECalShellView *cal_shell_view) action_group = ACTION_GROUP (CALENDAR_FILTER); e_action_group_remove_all_actions (action_group); - /* Add the standard filter actions. */ + /* Add the standard filter actions. No callback is needed + * because changes in the EActionComboBox are detected and + * handled by EShellSearchbar. */ gtk_action_group_add_radio_actions ( action_group, calendar_filter_entries, G_N_ELEMENTS (calendar_filter_entries), - CALENDAR_FILTER_ANY_CATEGORY, - G_CALLBACK (action_search_filter_cb), - cal_shell_view); + CALENDAR_FILTER_ANY_CATEGORY, NULL, NULL); /* Retrieve the radio group from an action we just added. */ list = gtk_action_group_list_actions (action_group); @@ -1841,10 +1830,13 @@ e_cal_shell_view_update_search_filter (ECalShellView *cal_shell_view) } g_list_free (list); - /* Use any action in the group; doesn't matter which. */ cal_shell_content = cal_shell_view->priv->cal_shell_content; searchbar = e_cal_shell_content_get_searchbar (cal_shell_content); combo_box = e_shell_searchbar_get_filter_combo_box (searchbar); + + e_shell_view_block_execute_search (shell_view); + + /* Use any action in the group; doesn't matter which. */ e_action_combo_box_set_action (combo_box, radio_action); ii = CALENDAR_FILTER_UNMATCHED; @@ -1852,4 +1844,6 @@ e_cal_shell_view_update_search_filter (ECalShellView *cal_shell_view) ii = CALENDAR_FILTER_NEXT_7_DAYS_APPOINTMENTS; e_action_combo_box_add_separator_after (combo_box, ii); + + e_shell_view_unblock_execute_search (shell_view); } diff --git a/modules/calendar/e-memo-shell-view-actions.c b/modules/calendar/e-memo-shell-view-actions.c index 24aced8528..f53b8ff406 100644 --- a/modules/calendar/e-memo-shell-view-actions.c +++ b/modules/calendar/e-memo-shell-view-actions.c @@ -560,14 +560,6 @@ action_memo_view_cb (GtkRadioAction *action, gtk_orientable_set_orientation (orientable, orientation); } -static void -action_search_filter_cb (GtkRadioAction *action, - GtkRadioAction *current, - EShellView *shell_view) -{ - e_shell_view_execute_search (shell_view); -} - static GtkActionEntry memo_entries[] = { { "memo-delete", @@ -892,9 +884,6 @@ e_memo_shell_view_actions_init (EMemoShellView *memo_shell_view) gtk_action_set_visible (action, FALSE); e_shell_searchbar_set_search_option ( searchbar, GTK_RADIO_ACTION (action)); - gtk_radio_action_set_current_value ( - GTK_RADIO_ACTION (action), - MEMO_SEARCH_SUMMARY_CONTAINS); /* Lockdown Printing Actions */ action_group = ACTION_GROUP (LOCKDOWN_PRINTING); @@ -967,13 +956,13 @@ e_memo_shell_view_update_search_filter (EMemoShellView *memo_shell_view) action_group = ACTION_GROUP (MEMOS_FILTER); e_action_group_remove_all_actions (action_group); - /* Add the standard filter actions. */ + /* Add the standard filter actions. No callback is needed + * because changes in the EActionComboBox are detected and + * handled by EShellSearchbar. */ gtk_action_group_add_radio_actions ( action_group, memo_filter_entries, G_N_ELEMENTS (memo_filter_entries), - MEMO_FILTER_ANY_CATEGORY, - G_CALLBACK (action_search_filter_cb), - memo_shell_view); + MEMO_FILTER_ANY_CATEGORY, NULL, NULL); /* Retrieve the radio group from an action we just added. */ list = gtk_action_group_list_actions (action_group); @@ -1024,12 +1013,17 @@ e_memo_shell_view_update_search_filter (EMemoShellView *memo_shell_view) } g_list_free (list); - /* Use any action in the group; doesn't matter which. */ memo_shell_content = memo_shell_view->priv->memo_shell_content; searchbar = e_memo_shell_content_get_searchbar (memo_shell_content); combo_box = e_shell_searchbar_get_filter_combo_box (searchbar); + + e_shell_view_block_execute_search (shell_view); + + /* Use any action in the group; doesn't matter which. */ e_action_combo_box_set_action (combo_box, radio_action); ii = MEMO_FILTER_UNMATCHED; e_action_combo_box_add_separator_after (combo_box, ii); + + e_shell_view_unblock_execute_search (shell_view); } diff --git a/modules/calendar/e-task-shell-view-actions.c b/modules/calendar/e-task-shell-view-actions.c index c18882dd2b..55873dd9f9 100644 --- a/modules/calendar/e-task-shell-view-actions.c +++ b/modules/calendar/e-task-shell-view-actions.c @@ -43,14 +43,6 @@ action_gal_save_custom_view_cb (GtkAction *action, } static void -action_search_filter_cb (GtkRadioAction *action, - GtkRadioAction *current, - EShellView *shell_view) -{ - e_shell_view_execute_search (shell_view); -} - -static void action_task_assign_cb (GtkAction *action, ETaskShellView *task_shell_view) { @@ -1091,9 +1083,6 @@ e_task_shell_view_actions_init (ETaskShellView *task_shell_view) gtk_action_set_visible (action, FALSE); e_shell_searchbar_set_search_option ( searchbar, GTK_RADIO_ACTION (action)); - gtk_radio_action_set_current_value ( - GTK_RADIO_ACTION (action), - TASK_SEARCH_SUMMARY_CONTAINS); /* Lockdown Printing Actions */ action_group = ACTION_GROUP (LOCKDOWN_PRINTING); @@ -1166,13 +1155,13 @@ e_task_shell_view_update_search_filter (ETaskShellView *task_shell_view) action_group = ACTION_GROUP (TASKS_FILTER); e_action_group_remove_all_actions (action_group); - /* Add the standard filter actions. */ + /* Add the standard filter actions. No callback is needed + * because changes in the EActionComboBox are detected and + * handled by EShellSearchbar. */ gtk_action_group_add_radio_actions ( action_group, task_filter_entries, G_N_ELEMENTS (task_filter_entries), - TASK_FILTER_ANY_CATEGORY, - G_CALLBACK (action_search_filter_cb), - task_shell_view); + TASK_FILTER_ANY_CATEGORY, NULL, NULL); /* Retrieve the radio group from an action we just added. */ list = gtk_action_group_list_actions (action_group); @@ -1223,10 +1212,13 @@ e_task_shell_view_update_search_filter (ETaskShellView *task_shell_view) } g_list_free (list); - /* Use any action in the group; doesn't matter which. */ task_shell_content = task_shell_view->priv->task_shell_content; searchbar = e_task_shell_content_get_searchbar (task_shell_content); combo_box = e_shell_searchbar_get_filter_combo_box (searchbar); + + e_shell_view_block_execute_search (shell_view); + + /* Use any action in the group; doesn't matter which. */ e_action_combo_box_set_action (combo_box, radio_action); ii = TASK_FILTER_UNMATCHED; @@ -1234,4 +1226,6 @@ e_task_shell_view_update_search_filter (ETaskShellView *task_shell_view) ii = TASK_FILTER_TASKS_WITH_ATTACHMENTS; e_action_combo_box_add_separator_after (combo_box, ii); + + e_shell_view_unblock_execute_search (shell_view); } diff --git a/modules/mail/e-mail-shell-view-actions.c b/modules/mail/e-mail-shell-view-actions.c index 6b72c7796d..766489fbe2 100644 --- a/modules/mail/e-mail-shell-view-actions.c +++ b/modules/mail/e-mail-shell-view-actions.c @@ -848,74 +848,6 @@ action_mail_view_cb (GtkRadioAction *action, gtk_orientable_set_orientation (orientable, orientation); } -static void -action_search_filter_cb (GtkRadioAction *action, - GtkRadioAction *current, - EShellView *shell_view) -{ - EShellContent *shell_content; - EMailReader *reader; - GKeyFile *key_file; - const gchar *folder_uri; - - shell_content = e_shell_view_get_shell_content (shell_view); - key_file = e_shell_view_get_state_key_file (shell_view); - - reader = E_MAIL_READER (shell_content); - folder_uri = e_mail_reader_get_folder_uri (reader); - - if (folder_uri != NULL) { - const gchar *key; - const gchar *string; - gchar *group_name; - - key = STATE_KEY_SEARCH_FILTER; - string = gtk_action_get_name (GTK_ACTION (current)); - group_name = g_strdup_printf ("Folder %s", folder_uri); - - g_key_file_set_string (key_file, group_name, key, string); - e_shell_view_set_state_dirty (shell_view); - - g_free (group_name); - } - - e_shell_view_execute_search (shell_view); -} - -static void -action_search_scope_cb (GtkRadioAction *action, - GtkRadioAction *current, - EShellView *shell_view) -{ - EShellContent *shell_content; - EMailReader *reader; - GKeyFile *key_file; - const gchar *folder_uri; - - shell_content = e_shell_view_get_shell_content (shell_view); - key_file = e_shell_view_get_state_key_file (shell_view); - - reader = E_MAIL_READER (shell_content); - folder_uri = e_mail_reader_get_folder_uri (reader); - - if (folder_uri != NULL) { - const gchar *key; - const gchar *string; - gchar *group_name; - - key = STATE_KEY_SEARCH_SCOPE; - string = gtk_action_get_name (GTK_ACTION (current)); - group_name = g_strdup_printf ("Folder %s", folder_uri); - - g_key_file_set_string (key_file, group_name, key, string); - e_shell_view_set_state_dirty (shell_view); - - g_free (group_name); - } - - e_shell_view_execute_search (shell_view); -} - static GtkActionEntry mail_entries[] = { { "mail-account-disable", @@ -1449,8 +1381,7 @@ e_mail_shell_view_actions_init (EMailShellView *mail_shell_view) gtk_action_group_add_radio_actions ( action_group, mail_scope_entries, G_N_ELEMENTS (mail_scope_entries), - MAIL_SCOPE_CURRENT_FOLDER, - G_CALLBACK (action_search_scope_cb), mail_shell_view); + MAIL_SCOPE_CURRENT_FOLDER, NULL, NULL); action = ACTION (MAIL_SCOPE_ALL_ACCOUNTS); combo_box = e_shell_searchbar_get_scope_combo_box (searchbar); @@ -1462,9 +1393,6 @@ e_mail_shell_view_actions_init (EMailShellView *mail_shell_view) gtk_action_set_visible (action, FALSE); e_shell_searchbar_set_search_option ( searchbar, GTK_RADIO_ACTION (action)); - gtk_radio_action_set_current_value ( - GTK_RADIO_ACTION (action), - MAIL_SEARCH_SUBJECT_OR_ADDRESSES_CONTAIN); /* Bind GObject properties for GConf keys. */ @@ -1716,13 +1644,13 @@ e_mail_shell_view_update_search_filter (EMailShellView *mail_shell_view) action_group = ACTION_GROUP (MAIL_FILTER); e_action_group_remove_all_actions (action_group); - /* Add the standard filter actions. */ + /* Add the standard filter actions. No callback is needed + * because changes in the EActionComboBox are detected and + * handled by EShellSearchbar. */ gtk_action_group_add_radio_actions ( action_group, mail_filter_entries, G_N_ELEMENTS (mail_filter_entries), - MAIL_FILTER_ALL_MESSAGES, - G_CALLBACK (action_search_filter_cb), - mail_shell_view); + MAIL_FILTER_ALL_MESSAGES, NULL, NULL); /* Retrieve the radio group from an action we just added. */ list = gtk_action_group_list_actions (action_group); @@ -1763,10 +1691,13 @@ e_mail_shell_view_update_search_filter (EMailShellView *mail_shell_view) ii++; } - /* Use any action in the group; doesn't matter which. */ mail_shell_content = mail_shell_view->priv->mail_shell_content; searchbar = e_mail_shell_content_get_searchbar (mail_shell_content); combo_box = e_shell_searchbar_get_filter_combo_box (searchbar); + + e_shell_view_block_execute_search (shell_view); + + /* Use any action in the group; doesn't matter which. */ e_action_combo_box_set_action (combo_box, radio_action); ii = MAIL_FILTER_UNREAD_MESSAGES; @@ -1775,5 +1706,7 @@ e_mail_shell_view_update_search_filter (EMailShellView *mail_shell_view) ii = MAIL_FILTER_READ_MESSAGES; e_action_combo_box_add_separator_after (combo_box, ii); + e_shell_view_unblock_execute_search (shell_view); + g_object_unref (tree_model); } diff --git a/modules/mail/e-mail-shell-view-private.c b/modules/mail/e-mail-shell-view-private.c index 377811e518..125432c7f7 100644 --- a/modules/mail/e-mail-shell-view-private.c +++ b/modules/mail/e-mail-shell-view-private.c @@ -416,6 +416,7 @@ void e_mail_shell_view_private_constructed (EMailShellView *mail_shell_view) { EMailShellViewPrivate *priv = mail_shell_view->priv; + EMailShellContent *mail_shell_content; EMailShellSidebar *mail_shell_sidebar; EShell *shell; EShellView *shell_view; @@ -424,8 +425,10 @@ e_mail_shell_view_private_constructed (EMailShellView *mail_shell_view) EShellSettings *shell_settings; EShellSidebar *shell_sidebar; EShellWindow *shell_window; + EShellSearchbar *searchbar; EMFormatHTMLDisplay *html_display; EMFolderTree *folder_tree; + EActionComboBox *combo_box; ERuleContext *context; EFilterRule *rule = NULL; GtkTreeSelection *selection; @@ -472,6 +475,16 @@ e_mail_shell_view_private_constructed (EMailShellView *mail_shell_view) folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar); selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (folder_tree)); + mail_shell_content = E_MAIL_SHELL_CONTENT (shell_content); + searchbar = e_mail_shell_content_get_searchbar (mail_shell_content); + combo_box = e_shell_searchbar_get_scope_combo_box (searchbar); + + /* The folder tree and scope combo box are both insensitive + * when searching beyond the currently selected folder. */ + e_mutual_binding_new ( + folder_tree, "sensitive", + combo_box, "sensitive"); + web_view = E_WEB_VIEW (EM_FORMAT_HTML (html_display)->html); g_signal_connect_swapped ( @@ -616,6 +629,21 @@ e_mail_shell_view_private_dispose (EMailShellView *mail_shell_view) for (ii = 0; ii < MAIL_NUM_SEARCH_RULES; ii++) DISPOSE (priv->search_rules[ii]); + + if (priv->search_account_all != NULL) { + camel_object_unref (priv->search_account_all); + priv->search_account_all = NULL; + } + + if (priv->search_account_current != NULL) { + camel_object_unref (priv->search_account_current); + priv->search_account_current = NULL; + } + + if (priv->search_account_cancel != NULL) { + camel_operation_unref (priv->search_account_cancel); + priv->search_account_cancel = NULL; + } } void @@ -630,8 +658,11 @@ e_mail_shell_view_restore_state (EMailShellView *mail_shell_view) EMailShellContent *mail_shell_content; EShellSearchbar *searchbar; EMailReader *reader; + CamelFolder *folder; + CamelVeeFolder *vee_folder; + const gchar *old_state_group; const gchar *folder_uri; - gchar *group_name; + gchar *new_state_group; /* XXX Move this to EMailShellContent. */ @@ -641,14 +672,34 @@ e_mail_shell_view_restore_state (EMailShellView *mail_shell_view) searchbar = e_mail_shell_content_get_searchbar (mail_shell_content); reader = E_MAIL_READER (mail_shell_content); + folder = e_mail_reader_get_folder (reader); folder_uri = e_mail_reader_get_folder_uri (reader); if (folder_uri == NULL) return; - group_name = g_strdup_printf ("Folder %s", folder_uri); - e_shell_searchbar_restore_state (searchbar, group_name); - g_free (group_name); + /* Do not restore state if we're running a "Current Account" + * or "All Accounts" search, since we don't want the search + * criteria to be destroyed in those cases. */ + + vee_folder = mail_shell_view->priv->search_account_all; + if (vee_folder != NULL && folder == CAMEL_FOLDER (vee_folder)) + return; + + vee_folder = mail_shell_view->priv->search_account_current; + if (vee_folder != NULL && folder == CAMEL_FOLDER (vee_folder)) + return; + + new_state_group = g_strdup_printf ("Folder %s", folder_uri); + old_state_group = e_shell_searchbar_get_state_group (searchbar); + + /* Avoid loading search state unnecessarily. */ + if (g_strcmp0 (new_state_group, old_state_group) != 0) { + e_shell_searchbar_set_state_group (searchbar, new_state_group); + e_shell_searchbar_load_state (searchbar); + } + + g_free (new_state_group); } /* Helper for e_mail_shell_view_create_filter_from_selected() */ diff --git a/modules/mail/e-mail-shell-view-private.h b/modules/mail/e-mail-shell-view-private.h index 44a02eddbd..9cdd71d13c 100644 --- a/modules/mail/e-mail-shell-view-private.h +++ b/modules/mail/e-mail-shell-view-private.h @@ -28,6 +28,9 @@ #include <gtkhtml/gtkhtml.h> #include <camel/camel-disco-store.h> #include <camel/camel-offline-store.h> +#include <camel/camel-operation.h> +#include <camel/camel-vee-folder.h> +#include <camel/camel-vee-store.h> #include <camel/camel-vtrash-folder.h> #include <camel/camel-search-private.h> /* for camel_search_word */ @@ -58,6 +61,8 @@ #include "mail-config.h" #include "mail-ops.h" #include "mail-send-recv.h" +#include "mail-session.h" +#include "mail-tools.h" #include "mail-vfolder.h" #include "message-list.h" @@ -147,6 +152,11 @@ struct _EMailShellViewPrivate { /* EShell::prepare-for-quit */ gulong prepare_for_quit_handler_id; + /* Search folders for interactive search. */ + CamelVeeFolder *search_account_all; + CamelVeeFolder *search_account_current; + CamelOperation *search_account_cancel; + guint show_deleted : 1; }; diff --git a/modules/mail/e-mail-shell-view.c b/modules/mail/e-mail-shell-view.c index 6016a14717..ce3c285a37 100644 --- a/modules/mail/e-mail-shell-view.c +++ b/modules/mail/e-mail-shell-view.c @@ -25,6 +25,114 @@ static gpointer parent_class; static GType mail_shell_view_type; +/* ETable spec for search results */ +static const gchar *SEARCH_RESULTS_STATE = +"<ETableState>" +" <column source=\"0\"/>" +" <column source=\"3\"/>" +" <column source=\"1\"/>" +" <column source=\"14\"/>" +" <column source=\"5\"/>" +" <column source=\"7\"/>" +" <column source=\"13\"/>" +" <grouping>" +" <leaf column=\"7\" ascending=\"false\"/>" +" </grouping>" +"</ETableState>"; + +typedef struct { + MailMsg base; + + CamelFolder *folder; + CamelOperation *cancel; + GList *folder_list; +} SearchResultsMsg; + +static gchar * +search_results_desc (SearchResultsMsg *msg) +{ + return g_strdup (_("Searching")); +} + +static void +search_results_exec (SearchResultsMsg *msg) +{ + GList *copied_list; + + camel_operation_register (msg->cancel); + + copied_list = g_list_copy (msg->folder_list); + g_list_foreach (copied_list, (GFunc) camel_object_ref, NULL); + + camel_vee_folder_set_folders ( + CAMEL_VEE_FOLDER (msg->folder), copied_list); + + g_list_foreach (copied_list, (GFunc) camel_object_unref, NULL); + g_list_free (copied_list); +} + +static void +search_results_done (SearchResultsMsg *msg) +{ +} + +static void +search_results_free (SearchResultsMsg *msg) +{ + camel_object_unref (msg->folder); + + g_list_foreach (msg->folder_list, (GFunc) camel_object_unref, NULL); + g_list_free (msg->folder_list); +} + +static MailMsgInfo search_results_setup_info = { + sizeof (SearchResultsMsg), + (MailMsgDescFunc) search_results_desc, + (MailMsgExecFunc) search_results_exec, + (MailMsgDoneFunc) search_results_done, + (MailMsgFreeFunc) search_results_free +}; + +static gint +mail_shell_view_setup_search_results_folder (CamelFolder *folder, + GList *folder_list, + CamelOperation *cancel) +{ + SearchResultsMsg *msg; + gint id; + + camel_object_ref (folder); + + msg = mail_msg_new (&search_results_setup_info); + msg->folder = folder; + msg->cancel = cancel; + msg->folder_list = folder_list; + + id = msg->base.seq; + mail_msg_slow_ordered_push (msg); + + return id; +} + +static void +mail_shell_view_show_search_results_folder (EMailShellView *mail_shell_view, + CamelFolder *folder, + const gchar *folder_uri) +{ + GtkWidget *message_list; + EMailReader *reader; + + reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content); + message_list = e_mail_reader_get_message_list (reader); + + message_list_freeze (MESSAGE_LIST (message_list)); + + e_mail_reader_set_folder (reader, folder, folder_uri); + e_tree_set_state (E_TREE (message_list), SEARCH_RESULTS_STATE); + + message_list_thaw (MESSAGE_LIST (message_list)); +} + static void mail_shell_view_dispose (GObject *object) { @@ -88,36 +196,47 @@ mail_shell_view_execute_search (EShellView *shell_view) { EMailShellViewPrivate *priv; EMailShellContent *mail_shell_content; + EMailShellSidebar *mail_shell_sidebar; EShell *shell; EShellWindow *shell_window; + EShellBackend *shell_backend; EShellContent *shell_content; + EShellSidebar *shell_sidebar; EShellSettings *shell_settings; EShellSearchbar *searchbar; EActionComboBox *combo_box; + EMFolderTree *folder_tree; + GtkTreeSelection *selection; GtkWidget *message_list; EFilterRule *rule; EMailReader *reader; + CamelVeeFolder *search_folder; CamelFolder *folder; + CamelStore *store; GtkAction *action; GtkTreeModel *model; GtkTreePath *path; GtkTreeIter tree_iter; GString *string; - GList *iter; + GList *list, *iter; GSList *search_strings = NULL; const gchar *folder_uri; + const gchar *data_dir; const gchar *text; gboolean valid; gchar *query; gchar *temp; gchar *tag; + gchar *uri; const gchar *use_tag; gint value; priv = E_MAIL_SHELL_VIEW_GET_PRIVATE (shell_view); shell_window = e_shell_view_get_shell_window (shell_view); + shell_backend = e_shell_view_get_shell_backend (shell_view); shell_content = e_shell_view_get_shell_content (shell_view); + shell_sidebar = e_shell_view_get_shell_sidebar (shell_view); shell = e_shell_window_get_shell (shell_window); shell_settings = e_shell_get_shell_settings (shell); @@ -125,33 +244,16 @@ mail_shell_view_execute_search (EShellView *shell_view) mail_shell_content = E_MAIL_SHELL_CONTENT (shell_content); searchbar = e_mail_shell_content_get_searchbar (mail_shell_content); + mail_shell_sidebar = E_MAIL_SHELL_SIDEBAR (shell_sidebar); + folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar); + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (folder_tree)); + reader = E_MAIL_READER (shell_content); folder = e_mail_reader_get_folder (reader); folder_uri = e_mail_reader_get_folder_uri (reader); message_list = e_mail_reader_get_message_list (reader); - if (folder_uri != NULL) { - GKeyFile *key_file; - const gchar *key; - const gchar *string; - gchar *group_name; - - key_file = e_shell_view_get_state_key_file (shell_view); - - key = STATE_KEY_SEARCH_TEXT; - string = e_shell_searchbar_get_search_text (searchbar); - group_name = g_strdup_printf ("Folder %s", folder_uri); - - if (string != NULL && *string != '\0') - g_key_file_set_string ( - key_file, group_name, key, string); - else - g_key_file_remove_key ( - key_file, group_name, key, NULL); - e_shell_view_set_state_dirty (shell_view); - - g_free (group_name); - } + data_dir = e_shell_backend_get_data_dir (shell_backend); /* This returns a new object reference. */ model = e_shell_settings_get_object ( @@ -357,6 +459,243 @@ filter: break; } + /* Apply selected scope. */ + + combo_box = e_shell_searchbar_get_scope_combo_box (searchbar); + value = e_action_combo_box_get_current_value (combo_box); + switch (value) { + case MAIL_SCOPE_CURRENT_FOLDER: + goto execute; + + case MAIL_SCOPE_CURRENT_ACCOUNT: + goto current_account; + + case MAIL_SCOPE_ALL_ACCOUNTS: + goto all_accounts; + + default: + g_warn_if_reached (); + goto execute; + } + +all_accounts: + + /* Prepare search folder for all accounts. */ + + /* If the search text is empty, cancel any + * account-wide searches still in progress. */ + text = e_shell_searchbar_get_search_text (searchbar); + if (text == NULL || *text == '\0') { + if (priv->search_account_all != NULL) { + camel_object_unref (priv->search_account_all); + priv->search_account_all = NULL; + } + + if (priv->search_account_cancel != NULL) { + camel_operation_cancel (priv->search_account_cancel); + camel_operation_unref (priv->search_account_cancel); + priv->search_account_cancel = NULL; + } + + /* Simulate a folder tree selection change, so the + * message list is reset to the correct folder via + * our EMFolderTree::folder-selected handler. */ + g_signal_emit_by_name (selection, "changed"); + + gtk_widget_set_sensitive (GTK_WIDGET (combo_box), TRUE); + + goto execute; + } + + search_folder = priv->search_account_all; + + /* Skip the search if we already have the results. */ + if (search_folder != NULL) + if (g_strcmp0 (query, search_folder->expression) == 0) + goto execute; + + /* Disable the scope combo while search is in progress. */ + gtk_widget_set_sensitive (GTK_WIDGET (combo_box), FALSE); + + /* If we already have a search folder, reuse it. */ + if (search_folder != NULL) { + if (priv->search_account_cancel != NULL) { + camel_operation_cancel (priv->search_account_cancel); + camel_operation_unref (priv->search_account_cancel); + priv->search_account_cancel = NULL; + } + + camel_vee_folder_set_expression (search_folder, query); + + goto execute; + } + + /* Create a new search folder. */ + + list = NULL; /* list of CamelFolders */ + + /* FIXME Using data_dir like this is not portable. */ + uri = g_strdup_printf ("vfolder:%s/vfolder", data_dir); + store = camel_session_get_store (session, uri, NULL); + g_free (uri); + + search_folder = (CamelVeeFolder *) camel_vee_folder_new ( + store, _("All Account Search"), CAMEL_STORE_VEE_FOLDER_AUTO); + priv->search_account_all = search_folder; + + /* Add local folders. */ + iter = mail_vfolder_get_sources_local (); + while (iter != NULL) { + CamelException ex; + + camel_exception_init (&ex); + + folder_uri = iter->data; + folder = mail_tool_uri_to_folder (folder_uri, 0, &ex); + + if (folder != NULL) + list = g_list_append (list, folder); + else + g_warning ("Could not open vfolder source: %s", folder_uri); + + camel_exception_clear (&ex); + iter = g_list_next (iter); + } + + /* Add remote folders. */ + iter = mail_vfolder_get_sources_remote (); + while (iter != NULL) { + CamelException ex; + + camel_exception_init (&ex); + + folder_uri = iter->data; + folder = mail_tool_uri_to_folder (folder_uri, 0, &ex); + + if (folder != NULL) + list = g_list_append (list, folder); + else + g_warning ("Could not open vfolder source: %s", folder_uri); + + camel_exception_clear (&ex); + iter = g_list_next (iter); + } + + camel_vee_folder_set_expression (search_folder, query); + + priv->search_account_cancel = camel_operation_new (NULL, NULL); + + /* This takes ownership of the folder list. */ + mail_shell_view_setup_search_results_folder ( + CAMEL_FOLDER (search_folder), list, + priv->search_account_cancel); + + uri = mail_tools_folder_to_url (CAMEL_FOLDER (search_folder)); + + mail_shell_view_show_search_results_folder ( + E_MAIL_SHELL_VIEW (shell_view), + CAMEL_FOLDER (search_folder), uri); + + g_free (uri); + + goto execute; + +current_account: + + /* Prepare search folder for current account only. */ + + /* If the search text is empty, cancel any + * account-wide searches still in progress. */ + text = e_shell_searchbar_get_search_text (searchbar); + if (text == NULL || *text == '\0') { + if (priv->search_account_current != NULL) { + camel_object_unref (priv->search_account_current); + priv->search_account_current = NULL; + } + + if (priv->search_account_cancel != NULL) { + camel_operation_cancel (priv->search_account_cancel); + camel_operation_unref (priv->search_account_cancel); + priv->search_account_cancel = NULL; + } + + /* Simulate a folder tree selection change, so the + * message list is reset to the correct folder via + * our EMFolderTree::folder-selected handler. */ + g_signal_emit_by_name (selection, "changed"); + + gtk_widget_set_sensitive (GTK_WIDGET (combo_box), TRUE); + + goto execute; + } + + search_folder = priv->search_account_current; + + /* Skip the search if we already have the results. */ + if (search_folder != NULL) + if (g_strcmp0 (query, search_folder->expression) == 0) + goto execute; + + /* Disable the scope combo while search is in progress. */ + gtk_widget_set_sensitive (GTK_WIDGET (combo_box), FALSE); + + /* If we already have a search folder, reuse it. */ + if (search_folder != NULL) { + if (priv->search_account_cancel != NULL) { + camel_operation_cancel (priv->search_account_cancel); + camel_operation_unref (priv->search_account_cancel); + priv->search_account_cancel = NULL; + } + + camel_vee_folder_set_expression (search_folder, query); + + goto execute; + } + + /* Create a new search folder. */ + + store = folder->parent_store; + list = NULL; /* list of CamelFolders */ + + if (store->folders != NULL) { + GPtrArray *array; + guint ii; + + array = camel_object_bag_list (store->folders); + for (ii = 0; ii < array->len; ii++) + list = g_list_append (list, array->pdata[ii]); + } + + /* FIXME Using data_dir like this is not portable. */ + uri = g_strdup_printf ("vfolder:%s/vfolder", data_dir); + store = camel_session_get_store (session, uri, NULL); + g_free (uri); + + search_folder = (CamelVeeFolder *) camel_vee_folder_new ( + store, _("Account Search"), CAMEL_STORE_VEE_FOLDER_AUTO); + priv->search_account_current = search_folder; + + camel_vee_folder_set_expression (search_folder, query); + + priv->search_account_cancel = camel_operation_new (NULL, NULL); + + /* This takes ownership of the folder list. */ + mail_shell_view_setup_search_results_folder ( + CAMEL_FOLDER (search_folder), list, + priv->search_account_cancel); + + uri = mail_tools_folder_to_url (CAMEL_FOLDER (search_folder)); + + mail_shell_view_show_search_results_folder ( + E_MAIL_SHELL_VIEW (shell_view), + CAMEL_FOLDER (search_folder), uri); + + g_free (uri); + +execute: + + /* Finally, execute the search. */ + message_list_set_search (MESSAGE_LIST (message_list), query); e_mail_shell_content_set_search_strings ( diff --git a/shell/e-shell-searchbar.c b/shell/e-shell-searchbar.c index a84e1eb1cb..f334e821e9 100644 --- a/shell/e-shell-searchbar.c +++ b/shell/e-shell-searchbar.c @@ -24,6 +24,7 @@ #include <config.h> #include <glib/gi18n-lib.h> +#include "e-util/e-util.h" #include "e-util/e-binding.h" #include "widgets/misc/e-action-combo-box.h" #include "widgets/misc/e-hinted-entry.h" @@ -36,7 +37,11 @@ #define SEARCH_OPTION_ADVANCED (-1) +/* Default "state key file" group: [Search Bar] */ +#define STATE_GROUP_DEFAULT "Search Bar" + #define STATE_KEY_SEARCH_FILTER "SearchFilter" +#define STATE_KEY_SEARCH_OPTION "SearchOption" #define STATE_KEY_SEARCH_SCOPE "SearchScope" #define STATE_KEY_SEARCH_TEXT "SearchText" @@ -52,16 +57,21 @@ struct _EShellSearchbarPrivate { GtkWidget *search_entry; GtkWidget *scope_combo_box; + /* State Key File */ + gchar *state_group; + guint filter_visible : 1; + guint label_visible : 1; guint search_visible : 1; guint scope_visible : 1; - guint label_visible : 1; + guint state_dirty : 1; }; enum { PROP_0, PROP_FILTER_COMBO_BOX, PROP_FILTER_VISIBLE, + PROP_LABEL_VISIBLE, PROP_SEARCH_HINT, PROP_SEARCH_OPTION, PROP_SEARCH_TEXT, @@ -69,7 +79,7 @@ enum { PROP_SCOPE_COMBO_BOX, PROP_SCOPE_VISIBLE, PROP_SHELL_VIEW, - PROP_LABEL_VISIBLE, + PROP_STATE_GROUP }; static gpointer parent_class; @@ -159,6 +169,8 @@ shell_searchbar_execute_search_cb (EShellView *shell_view, shell_searchbar_update_search_widgets (searchbar); + e_shell_searchbar_save_state (searchbar); + if (!e_shell_view_is_active (shell_view)) return; @@ -324,13 +336,14 @@ shell_searchbar_set_property (GObject *object, GParamSpec *pspec) { switch (property_id) { - case PROP_LABEL_VISIBLE: - e_shell_searchbar_set_label_visible ( + case PROP_FILTER_VISIBLE: + e_shell_searchbar_set_filter_visible ( E_SHELL_SEARCHBAR (object), g_value_get_boolean (value)); return; - case PROP_FILTER_VISIBLE: - e_shell_searchbar_set_filter_visible ( + + case PROP_LABEL_VISIBLE: + e_shell_searchbar_set_label_visible ( E_SHELL_SEARCHBAR (object), g_value_get_boolean (value)); return; @@ -370,6 +383,12 @@ shell_searchbar_set_property (GObject *object, E_SHELL_SEARCHBAR (object), g_value_get_object (value)); return; + + case PROP_STATE_GROUP: + e_shell_searchbar_set_state_group ( + E_SHELL_SEARCHBAR (object), + g_value_get_string (value)); + return; } G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); @@ -441,6 +460,12 @@ shell_searchbar_get_property (GObject *object, value, e_shell_searchbar_get_shell_view ( E_SHELL_SEARCHBAR (object))); return; + + case PROP_STATE_GROUP: + g_value_set_string ( + value, e_shell_searchbar_get_state_group ( + E_SHELL_SEARCHBAR (object))); + return; } G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); @@ -488,18 +513,25 @@ shell_searchbar_constructed (GObject *object) g_signal_connect ( shell_view, "clear-search", - G_CALLBACK (shell_searchbar_clear_search_cb), - searchbar); + G_CALLBACK (shell_searchbar_clear_search_cb), searchbar); g_signal_connect ( shell_view, "custom-search", - G_CALLBACK (shell_searchbar_custom_search_cb), - searchbar); + G_CALLBACK (shell_searchbar_custom_search_cb), searchbar); g_signal_connect_after ( shell_view, "execute-search", - G_CALLBACK (shell_searchbar_execute_search_cb), - searchbar); + G_CALLBACK (shell_searchbar_execute_search_cb), searchbar); + + widget = searchbar->priv->filter_combo_box; + + g_signal_connect_swapped ( + widget, "changed", + G_CALLBACK (e_shell_searchbar_set_state_dirty), searchbar); + + g_signal_connect_swapped ( + widget, "changed", + G_CALLBACK (e_shell_view_execute_search), shell_view); widget = searchbar->priv->search_entry; @@ -532,9 +564,22 @@ shell_searchbar_constructed (GObject *object) } static void +shell_searchbar_map (GtkWidget *widget) +{ + /* Chain up to parent's map() method. */ + GTK_WIDGET_CLASS (parent_class)->map (widget); + + /* Load state after constructed() so we don't derail + * subclass initialization. We wait until map() so we + * have usable style colors for the entry box. */ + e_shell_searchbar_load_state (E_SHELL_SEARCHBAR (widget)); +} + +static void shell_searchbar_class_init (EShellSearchbarClass *class) { GObjectClass *object_class; + GtkWidgetClass *widget_class; parent_class = g_type_class_peek_parent (class); g_type_class_add_private (class, sizeof (EShellSearchbarPrivate)); @@ -545,6 +590,9 @@ shell_searchbar_class_init (EShellSearchbarClass *class) object_class->dispose = shell_searchbar_dispose; object_class->constructed = shell_searchbar_constructed; + widget_class = GTK_WIDGET_CLASS (class); + widget_class->map = shell_searchbar_map; + g_object_class_install_property ( object_class, PROP_FILTER_COMBO_BOX, @@ -654,6 +702,22 @@ shell_searchbar_class_init (EShellSearchbarClass *class) E_TYPE_SHELL_VIEW, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + + /** + * EShellContent:state-group + * + * Key file group name to read and write search bar state. + **/ + g_object_class_install_property ( + object_class, + PROP_STATE_GROUP, + g_param_spec_string ( + "state-group", + NULL, + NULL, + STATE_GROUP_DEFAULT, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); } static void @@ -737,6 +801,11 @@ shell_searchbar_init (EShellSearchbar *searchbar) searchbar); g_signal_connect_swapped ( + widget, "changed", + G_CALLBACK (e_shell_searchbar_set_state_dirty), + searchbar); + + g_signal_connect_swapped ( widget, "icon-press", G_CALLBACK (shell_searchbar_entry_icon_press_cb), searchbar); @@ -777,6 +846,11 @@ shell_searchbar_init (EShellSearchbar *searchbar) gtk_box_pack_start (box, widget, FALSE, FALSE, 0); searchbar->priv->scope_combo_box = widget; gtk_widget_show (widget); + + g_signal_connect_swapped ( + widget, "changed", + G_CALLBACK (e_shell_searchbar_set_state_dirty), + searchbar); } GType @@ -856,7 +930,7 @@ e_shell_searchbar_get_label_visible (EShellSearchbar *searchbar) void e_shell_searchbar_set_label_visible (EShellSearchbar *searchbar, - gboolean label_visible) + gboolean label_visible) { g_return_if_fail (E_IS_SHELL_SEARCHBAR (searchbar)); @@ -1015,7 +1089,7 @@ e_shell_searchbar_get_scope_visible (EShellSearchbar *searchbar) void e_shell_searchbar_set_scope_visible (EShellSearchbar *searchbar, - gboolean scope_visible) + gboolean scope_visible) { g_return_if_fail (E_IS_SHELL_SEARCHBAR (searchbar)); @@ -1025,8 +1099,38 @@ e_shell_searchbar_set_scope_visible (EShellSearchbar *searchbar, } void -e_shell_searchbar_restore_state (EShellSearchbar *searchbar, - const gchar *group_name) +e_shell_searchbar_set_state_dirty (EShellSearchbar *searchbar) +{ + g_return_if_fail (E_IS_SHELL_SEARCHBAR (searchbar)); + + searchbar->priv->state_dirty = TRUE; +} + +const gchar * +e_shell_searchbar_get_state_group (EShellSearchbar *searchbar) +{ + g_return_val_if_fail (E_IS_SHELL_SEARCHBAR (searchbar), NULL); + + return searchbar->priv->state_group; +} + +void +e_shell_searchbar_set_state_group (EShellSearchbar *searchbar, + const gchar *state_group) +{ + g_return_if_fail (E_IS_SHELL_SEARCHBAR (searchbar)); + + if (state_group == NULL) + state_group = STATE_GROUP_DEFAULT; + + g_free (searchbar->priv->state_group); + searchbar->priv->state_group = g_strdup (state_group); + + g_object_notify (G_OBJECT (searchbar), "state-group"); +} + +void +e_shell_searchbar_load_state (EShellSearchbar *searchbar) { EShellView *shell_view; EShellWindow *shell_window; @@ -1034,15 +1138,19 @@ e_shell_searchbar_restore_state (EShellSearchbar *searchbar, GtkAction *action; GtkWidget *widget; const gchar *search_text; + const gchar *state_group; const gchar *key; gchar *string; + gint value = 0; 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); + state_group = e_shell_searchbar_get_state_group (searchbar); + g_return_if_fail (state_group != NULL); + key_file = e_shell_view_get_state_key_file (shell_view); + shell_window = e_shell_view_get_shell_window (shell_view); /* Changing the combo boxes triggers searches, so block * the search action until the state is fully restored. */ @@ -1052,13 +1160,14 @@ e_shell_searchbar_restore_state (EShellSearchbar *searchbar, e_shell_view_block_execute_search (shell_view); e_shell_view_set_search_rule (shell_view, NULL); + key = STATE_KEY_SEARCH_FILTER; - string = g_key_file_get_string (key_file, group_name, key, NULL); + string = g_key_file_get_string (key_file, state_group, key, NULL); if (string != NULL && *string != '\0') action = e_shell_window_get_action (shell_window, string); else action = NULL; - if (action != NULL) + if (GTK_IS_RADIO_ACTION (action)) gtk_action_activate (action); else { /* Pick the first combo box item. */ @@ -1067,23 +1176,26 @@ e_shell_searchbar_restore_state (EShellSearchbar *searchbar, } g_free (string); - key = STATE_KEY_SEARCH_SCOPE; - string = g_key_file_get_string (key_file, group_name, key, NULL); + /* Avoid restoring to the "Advanced Search" option, since we + * don't currently save the search rule (TODO but we should). */ + key = STATE_KEY_SEARCH_OPTION; + string = g_key_file_get_string (key_file, state_group, key, NULL); if (string != NULL && *string != '\0') action = e_shell_window_get_action (shell_window, string); else action = NULL; - if (action != NULL) + if (GTK_IS_RADIO_ACTION (action)) + g_object_get (action, "value", &value, NULL); + else + value = SEARCH_OPTION_ADVANCED; + if (value != SEARCH_OPTION_ADVANCED) 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); + else if (searchbar->priv->search_option != NULL) + gtk_radio_action_set_current_value ( + searchbar->priv->search_option, 0); key = STATE_KEY_SEARCH_TEXT; - string = g_key_file_get_string (key_file, group_name, key, NULL); + string = g_key_file_get_string (key_file, state_group, key, NULL); search_text = e_shell_searchbar_get_search_text (searchbar); if (search_text != NULL && *search_text == '\0') search_text = NULL; @@ -1091,11 +1203,102 @@ e_shell_searchbar_restore_state (EShellSearchbar *searchbar, e_shell_searchbar_set_search_text (searchbar, string); g_free (string); + /* Search scope is hard-coded to the default state group. */ + state_group = STATE_GROUP_DEFAULT; + + key = STATE_KEY_SEARCH_SCOPE; + string = g_key_file_get_string (key_file, state_group, key, NULL); + if (string != NULL && *string != '\0') + action = e_shell_window_get_action (shell_window, string); + else + action = NULL; + if (GTK_IS_RADIO_ACTION (action)) + 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); + 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. */ + searchbar->priv->state_dirty = FALSE; e_shell_view_execute_search (shell_view); } + +void +e_shell_searchbar_save_state (EShellSearchbar *searchbar) +{ + EShellView *shell_view; + GKeyFile *key_file; + GtkRadioAction *radio_action; + EActionComboBox *action_combo_box; + const gchar *action_name; + const gchar *search_text; + const gchar *state_group; + const gchar *key; + + g_return_if_fail (E_IS_SHELL_SEARCHBAR (searchbar)); + + /* Skip saving state if it hasn't changed since it was loaded. */ + if (!searchbar->priv->state_dirty) + return; + + shell_view = e_shell_searchbar_get_shell_view (searchbar); + state_group = e_shell_searchbar_get_state_group (searchbar); + g_return_if_fail (state_group != NULL); + + key_file = e_shell_view_get_state_key_file (shell_view); + + key = STATE_KEY_SEARCH_FILTER; + action_combo_box = e_shell_searchbar_get_filter_combo_box (searchbar); + radio_action = e_action_combo_box_get_action (action_combo_box); + if (radio_action != NULL) + radio_action = e_radio_action_get_current_action (radio_action); + if (radio_action != NULL) { + action_name = gtk_action_get_name (GTK_ACTION (radio_action)); + g_key_file_set_string (key_file, state_group, key, action_name); + } else + g_key_file_remove_key (key_file, state_group, key, NULL); + + key = STATE_KEY_SEARCH_OPTION; + radio_action = e_shell_searchbar_get_search_option (searchbar); + if (radio_action != NULL) + radio_action = e_radio_action_get_current_action (radio_action); + if (radio_action != NULL) { + action_name = gtk_action_get_name (GTK_ACTION (radio_action)); + g_key_file_set_string (key_file, state_group, key, action_name); + } else + g_key_file_remove_key (key_file, state_group, key, NULL); + + key = STATE_KEY_SEARCH_TEXT; + search_text = e_shell_searchbar_get_search_text (searchbar); + if (search_text != NULL && *search_text == '\0') + search_text = NULL; + if (search_text != NULL) + g_key_file_set_string (key_file, state_group, key, search_text); + else + g_key_file_remove_key (key_file, state_group, key, NULL); + + /* Search scope is hard-coded to the default state group. */ + state_group = STATE_GROUP_DEFAULT; + + key = STATE_KEY_SEARCH_SCOPE; + action_combo_box = e_shell_searchbar_get_scope_combo_box (searchbar); + radio_action = e_action_combo_box_get_action (action_combo_box); + if (radio_action != NULL) + radio_action = e_radio_action_get_current_action (radio_action); + if (radio_action != NULL) { + action_name = gtk_action_get_name (GTK_ACTION (radio_action)); + g_key_file_set_string (key_file, state_group, key, action_name); + } else + g_key_file_remove_key (key_file, state_group, key, NULL); + + searchbar->priv->state_dirty = FALSE; + e_shell_view_set_state_dirty (shell_view); +} diff --git a/shell/e-shell-searchbar.h b/shell/e-shell-searchbar.h index 79b593b1cd..23fa480a86 100644 --- a/shell/e-shell-searchbar.h +++ b/shell/e-shell-searchbar.h @@ -83,6 +83,11 @@ gboolean e_shell_searchbar_get_filter_visible void e_shell_searchbar_set_filter_visible (EShellSearchbar *searchbar, gboolean filter_visible); +gboolean e_shell_searchbar_get_label_visible + (EShellSearchbar *searchbar); +void e_shell_searchbar_set_label_visible + (EShellSearchbar *searchbar, + gboolean label_visible); const gchar * e_shell_searchbar_get_search_hint (EShellSearchbar *searchbar); void e_shell_searchbar_set_search_hint @@ -103,11 +108,6 @@ gboolean e_shell_searchbar_get_search_visible void e_shell_searchbar_set_search_visible (EShellSearchbar *searchbar, gboolean search_visible); -gboolean e_shell_searchbar_get_label_visible - (EShellSearchbar *searchbar); -void e_shell_searchbar_set_label_visible - (EShellSearchbar *searchbar, - gboolean label_visible); EActionComboBox * e_shell_searchbar_get_scope_combo_box (EShellSearchbar *searchbar); @@ -116,8 +116,15 @@ gboolean e_shell_searchbar_get_scope_visible void e_shell_searchbar_set_scope_visible (EShellSearchbar *searchbar, gboolean scope_visible); -void e_shell_searchbar_restore_state (EShellSearchbar *searchbar, - const gchar *group_name); +void e_shell_searchbar_set_state_dirty + (EShellSearchbar *searchbar); +const gchar * e_shell_searchbar_get_state_group + (EShellSearchbar *searchbar); +void e_shell_searchbar_set_state_group + (EShellSearchbar *searchbar, + const gchar *state_group); +void e_shell_searchbar_load_state (EShellSearchbar *searchbar); +void e_shell_searchbar_save_state (EShellSearchbar *searchbar); G_END_DECLS diff --git a/shell/e-shell-view.c b/shell/e-shell-view.c index fdffe92fd6..83be139327 100644 --- a/shell/e-shell-view.c +++ b/shell/e-shell-view.c @@ -1402,8 +1402,8 @@ e_shell_view_execute_search (EShellView *shell_view) * e_shell_view_block_execute_search: * @shell_view: an #EShellView * - * Blocks e_shell_view_execute_search in a way it does nothing. - * Pair function for this is e_shell_view_unblock_execute_search. + * Blocks e_shell_view_execute_search() in a way it does nothing. + * Pair function for this is e_shell_view_unblock_execute_search(). **/ void e_shell_view_block_execute_search (EShellView *shell_view) @@ -1418,8 +1418,8 @@ e_shell_view_block_execute_search (EShellView *shell_view) * e_shell_view_unblock_execute_search: * @shell_view: an #EShellView * - * Unblocks previously blocked e_shell_view_execute_search with - * function e_shell_view_block_execute_search. + * Unblocks previously blocked e_shell_view_execute_search() with + * function e_shell_view_block_execute_search(). **/ void e_shell_view_unblock_execute_search (EShellView *shell_view) diff --git a/shell/e-shell-window.c b/shell/e-shell-window.c index d159406e08..5484573079 100644 --- a/shell/e-shell-window.c +++ b/shell/e-shell-window.c @@ -578,9 +578,6 @@ shell_window_create_shell_view (EShellWindow *shell_window, shell_view, "notify::view-id", G_CALLBACK (e_shell_window_update_view_menu), shell_window); - /* Execute an initial search. */ - e_shell_view_execute_search (shell_view); - return shell_view; } diff --git a/widgets/misc/e-action-combo-box.c b/widgets/misc/e-action-combo-box.c index 7010dc048b..2fa376d420 100644 --- a/widgets/misc/e-action-combo-box.c +++ b/widgets/misc/e-action-combo-box.c @@ -502,6 +502,7 @@ e_action_combo_box_set_action (EActionComboBox *combo_box, g_object_get ( g_object_ref (action), "action-group", &combo_box->priv->action_group, NULL); + combo_box->priv->action = action; action_combo_box_update_model (combo_box); @@ -526,6 +527,8 @@ e_action_combo_box_set_action (EActionComboBox *combo_box, action_combo_box_action_group_notify_cb), combo_box); } + + g_object_notify (G_OBJECT (combo_box), "action"); } gint |