diff options
Diffstat (limited to 'shell')
-rw-r--r-- | shell/e-shell-content.c | 79 | ||||
-rw-r--r-- | shell/e-shell-content.h | 2 | ||||
-rw-r--r-- | shell/e-shell-view.c | 125 | ||||
-rw-r--r-- | shell/e-shell-view.h | 2 |
4 files changed, 204 insertions, 4 deletions
diff --git a/shell/e-shell-content.c b/shell/e-shell-content.c index 216520fbb4..2fc9569bd2 100644 --- a/shell/e-shell-content.c +++ b/shell/e-shell-content.c @@ -24,6 +24,7 @@ #include <glib/gi18n.h> #include "e-util/e-binding.h" +#include "e-util/e-util.h" #include "filter/rule-editor.h" #include "widgets/misc/e-action-combo-box.h" #include "widgets/misc/e-hinted-entry.h" @@ -36,6 +37,10 @@ (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 */ @@ -55,8 +60,6 @@ struct _EShellContentPrivate { GtkWidget *search_entry; GtkWidget *scope_label; GtkWidget *scope_combo_box; - - GtkStateType search_state; }; enum { @@ -138,7 +141,10 @@ action_search_execute_cb (GtkAction *action, /* Direct the focus away from the search entry, so that a * focus-in event is required before the text can be changed. * This will reset the entry to the appropriate visual state. */ - gtk_widget_grab_focus (gtk_bin_get_child (GTK_BIN (shell_content))); + 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 @@ -897,7 +903,6 @@ shell_content_init (EShellContent *shell_content) gtk_label_set_mnemonic_widget (label, widget); gtk_box_pack_start (box, widget, TRUE, TRUE, 0); shell_content->priv->search_entry = g_object_ref (widget); - shell_content->priv->search_state = GTK_STATE_NORMAL; gtk_widget_show (widget); g_signal_connect_swapped ( @@ -1486,3 +1491,69 @@ 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 *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_get_action (shell_window, "search-execute"); + gtk_action_block_activate (action); + + 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); + e_shell_content_set_search_text (shell_content, string); + g_free (string); + + action = e_shell_window_get_action (shell_window, "search-execute"); + gtk_action_unblock_activate (action); + + /* Now execute the search. */ + gtk_action_activate (action); +} diff --git a/shell/e-shell-content.h b/shell/e-shell-content.h index af2799c7d4..8e754fff26 100644 --- a/shell/e-shell-content.h +++ b/shell/e-shell-content.h @@ -140,6 +140,8 @@ 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-view.c b/shell/e-shell-view.c index cf89442c7c..d1ab1af4a4 100644 --- a/shell/e-shell-view.c +++ b/shell/e-shell-view.c @@ -33,10 +33,15 @@ (G_TYPE_INSTANCE_GET_PRIVATE \ ((obj), E_TYPE_SHELL_VIEW, EShellViewPrivate)) +#define STATE_SAVE_TIMEOUT_SECONDS 3 + struct _EShellViewPrivate { gpointer shell_window; /* weak pointer */ + GKeyFile *state_key_file; + guint state_save_source_id; + gchar *title; gchar *view_id; gint page_num; @@ -118,6 +123,72 @@ shell_view_update_view_id (EShellView *shell_view, } static void +shell_view_load_state (EShellView *shell_view) +{ + EShellBackend *shell_backend; + GKeyFile *key_file; + const gchar *config_dir; + gchar *filename; + GError *error = NULL; + + shell_backend = e_shell_view_get_shell_backend (shell_view); + config_dir = e_shell_backend_get_config_dir (shell_backend); + filename = g_build_filename (config_dir, "state", NULL); + + /* XXX Should do this asynchronously. */ + key_file = shell_view->priv->state_key_file; + g_key_file_load_from_file (key_file, filename, 0, &error); + + if (error == NULL) + goto exit; + + if (!g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT)) + g_warning ("%s", error->message); + + g_error_free (error); + +exit: + g_free (filename); +} + +static void +shell_view_save_state (EShellView *shell_view) +{ + EShellBackend *shell_backend; + GKeyFile *key_file; + const gchar *config_dir; + gchar *contents; + gchar *filename; + GError *error = NULL; + + shell_backend = e_shell_view_get_shell_backend (shell_view); + config_dir = e_shell_backend_get_config_dir (shell_backend); + filename = g_build_filename (config_dir, "state", NULL); + + /* XXX Should do this asynchronously. */ + key_file = shell_view->priv->state_key_file; + contents = g_key_file_to_data (key_file, NULL, NULL); + g_file_set_contents (filename, contents, -1, &error); + g_free (contents); + + if (error != NULL) { + g_warning ("%s", error->message); + g_error_free (error); + } + + g_free (filename); +} + +static gboolean +shell_view_state_timeout_cb (EShellView *shell_view) +{ + shell_view_save_state (shell_view); + shell_view->priv->state_save_source_id = 0; + + return FALSE; +} + +static void shell_view_emit_toggled (EShellView *shell_view) { g_signal_emit (shell_view, signals[TOGGLED], 0); @@ -267,6 +338,13 @@ shell_view_dispose (GObject *object) priv = E_SHELL_VIEW_GET_PRIVATE (object); + /* Expedite any pending state saves. */ + if (priv->state_save_source_id > 0) { + g_source_remove (priv->state_save_source_id); + priv->state_save_source_id = 0; + shell_view_save_state (E_SHELL_VIEW (object)); + } + if (priv->shell_window != NULL) { g_object_remove_weak_pointer ( G_OBJECT (priv->shell_window), &priv->shell_window); @@ -304,6 +382,8 @@ shell_view_finalize (GObject *object) priv = E_SHELL_VIEW_GET_PRIVATE (object); + g_key_file_free (priv->state_key_file); + g_free (priv->title); g_free (priv->view_id); @@ -330,6 +410,8 @@ shell_view_constructed (GObject *object) e_plugin_ui_register_manager (ui_manager, id, shell_view); + shell_view_load_state (shell_view); + /* Invoke factory methods. */ widget = class->new_shell_content (shell_view); @@ -598,6 +680,7 @@ shell_view_init (EShellView *shell_view, size_group = gtk_size_group_new (GTK_SIZE_GROUP_VERTICAL); shell_view->priv = E_SHELL_VIEW_GET_PRIVATE (shell_view); + shell_view->priv->state_key_file = g_key_file_new (); shell_view->priv->size_group = size_group; } @@ -947,6 +1030,48 @@ e_shell_view_get_shell_taskbar (EShellView *shell_view) } /** + * e_shell_view_get_state_key_file: + * @shell_view: an #EShellView + * + * Returns the #GKeyFile holding widget state data for @shell_view. + * + * Returns: the #GKeyFile for @shell_view + **/ +GKeyFile * +e_shell_view_get_state_key_file (EShellView *shell_view) +{ + g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL); + + return shell_view->priv->state_key_file; +} + +/** + * e_shell_view_set_state_dirty: + * @shell_view: an #EShellView + * + * Marks the widget state data as modified (or "dirty") and schedules it + * to be saved to disk after a short delay. The delay caps the frequency + * of saving to disk. + **/ +void +e_shell_view_set_state_dirty (EShellView *shell_view) +{ + guint source_id; + + g_return_if_fail (E_IS_SHELL_VIEW (shell_view)); + + /* If a timeout is already scheduled, do nothing. */ + if (shell_view->priv->state_save_source_id > 0) + return; + + source_id = g_timeout_add_seconds ( + STATE_SAVE_TIMEOUT_SECONDS, (GSourceFunc) + shell_view_state_timeout_cb, shell_view); + + shell_view->priv->state_save_source_id = source_id; +} + +/** * e_shell_view_update_actions: * @shell_view: an #EShellView * diff --git a/shell/e-shell-view.h b/shell/e-shell-view.h index a3ca595fba..b323839478 100644 --- a/shell/e-shell-view.h +++ b/shell/e-shell-view.h @@ -171,6 +171,8 @@ EShellContent * e_shell_view_get_shell_content (EShellView *shell_view); EShellSidebar * e_shell_view_get_shell_sidebar (EShellView *shell_view); 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_update_actions (EShellView *shell_view); void e_shell_view_show_popup_menu (EShellView *shell_view, const gchar *widget_path, |