aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--addressbook/gui/component/e-book-shell-view-actions.c8
-rw-r--r--calendar/module/e-cal-shell-view-actions.c8
-rw-r--r--calendar/module/e-memo-shell-view-actions.c8
-rw-r--r--calendar/module/e-task-shell-view-actions.c8
-rw-r--r--doc/reference/shell/tmpl/eshell-unused.sgml16
-rw-r--r--e-util/e-util.c35
-rw-r--r--e-util/e-util.h2
-rw-r--r--mail/e-mail-reader.c4
-rw-r--r--mail/e-mail-shell-content.c176
-rw-r--r--mail/e-mail-shell-sidebar.c344
-rw-r--r--mail/e-mail-shell-view-actions.c129
-rw-r--r--mail/e-mail-shell-view-private.c73
-rw-r--r--mail/e-mail-shell-view-private.h2
-rw-r--r--mail/em-composer-utils.c9
-rw-r--r--mail/em-folder-selection-button.c1
-rw-r--r--mail/em-folder-selection.c67
-rw-r--r--mail/em-folder-selection.h24
-rw-r--r--mail/em-folder-tree-model.c445
-rw-r--r--mail/em-folder-tree-model.h22
-rw-r--r--mail/em-folder-tree.c176
-rw-r--r--mail/em-folder-tree.h3
-rw-r--r--mail/em-folder-utils.c16
-rw-r--r--mail/em-folder-utils.h7
-rw-r--r--plugins/groupwise-features/install-shared.c2
-rw-r--r--plugins/groupwise-features/share-folder-common.c2
-rw-r--r--shell/e-shell-content.c79
-rw-r--r--shell/e-shell-content.h2
-rw-r--r--shell/e-shell-view.c125
-rw-r--r--shell/e-shell-view.h2
29 files changed, 1022 insertions, 773 deletions
diff --git a/addressbook/gui/component/e-book-shell-view-actions.c b/addressbook/gui/component/e-book-shell-view-actions.c
index 73766c7df3..773eb3fa7a 100644
--- a/addressbook/gui/component/e-book-shell-view-actions.c
+++ b/addressbook/gui/component/e-book-shell-view-actions.c
@@ -562,7 +562,13 @@ action_search_filter_cb (GtkRadioAction *action,
GtkRadioAction *current,
EBookShellView *book_shell_view)
{
- e_book_shell_view_execute_search (book_shell_view);
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+
+ shell_view = E_SHELL_VIEW (book_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ gtk_action_activate (ACTION (SEARCH_EXECUTE));
}
static GtkActionEntry contact_entries[] = {
diff --git a/calendar/module/e-cal-shell-view-actions.c b/calendar/module/e-cal-shell-view-actions.c
index 5f5380d919..02b7af609e 100644
--- a/calendar/module/e-cal-shell-view-actions.c
+++ b/calendar/module/e-cal-shell-view-actions.c
@@ -599,7 +599,13 @@ action_search_filter_cb (GtkRadioAction *action,
GtkRadioAction *current,
ECalShellView *cal_shell_view)
{
- e_cal_shell_view_execute_search (cal_shell_view);
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+
+ shell_view = E_SHELL_VIEW (cal_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ gtk_action_activate (ACTION (SEARCH_EXECUTE));
}
static GtkActionEntry calendar_entries[] = {
diff --git a/calendar/module/e-memo-shell-view-actions.c b/calendar/module/e-memo-shell-view-actions.c
index 855a7b18b4..1736606abe 100644
--- a/calendar/module/e-memo-shell-view-actions.c
+++ b/calendar/module/e-memo-shell-view-actions.c
@@ -548,7 +548,13 @@ action_search_filter_cb (GtkRadioAction *action,
GtkRadioAction *current,
EMemoShellView *memo_shell_view)
{
- e_memo_shell_view_execute_search (memo_shell_view);
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+
+ shell_view = E_SHELL_VIEW (memo_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ gtk_action_activate (ACTION (SEARCH_EXECUTE));
}
static GtkActionEntry memo_entries[] = {
diff --git a/calendar/module/e-task-shell-view-actions.c b/calendar/module/e-task-shell-view-actions.c
index 8431b64624..4deed9fdf0 100644
--- a/calendar/module/e-task-shell-view-actions.c
+++ b/calendar/module/e-task-shell-view-actions.c
@@ -62,7 +62,13 @@ action_search_filter_cb (GtkRadioAction *action,
GtkRadioAction *current,
ETaskShellView *task_shell_view)
{
- e_task_shell_view_execute_search (task_shell_view);
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+
+ shell_view = E_SHELL_VIEW (task_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ gtk_action_activate (ACTION (SEARCH_EXECUTE));
}
static void
diff --git a/doc/reference/shell/tmpl/eshell-unused.sgml b/doc/reference/shell/tmpl/eshell-unused.sgml
index 72168ee8e2..dcfb2afdde 100644
--- a/doc/reference/shell/tmpl/eshell-unused.sgml
+++ b/doc/reference/shell/tmpl/eshell-unused.sgml
@@ -525,6 +525,22 @@ intelligent
@shutdown:
@migrate:
+<!-- ##### SIGNAL EShellView::capture-state ##### -->
+<para>
+
+</para>
+
+@eshellview: the object which received the signal.
+@arg1:
+
+<!-- ##### SIGNAL EShellView::restore-state ##### -->
+<para>
+
+</para>
+
+@eshellview: the object which received the signal.
+@arg1:
+
<!-- ##### ARG EShellView:shell-module ##### -->
<para>
diff --git a/e-util/e-util.c b/e-util/e-util.c
index 0eaf8c39a4..55eb6eba6b 100644
--- a/e-util/e-util.c
+++ b/e-util/e-util.c
@@ -372,6 +372,41 @@ e_action_group_remove_all_actions (GtkActionGroup *action_group)
}
/**
+ * e_radio_action_get_current_action:
+ * @radio_action: a #GtkRadioAction
+ *
+ * Returns the currently active member of the group to which @radio_action
+ * belongs.
+ *
+ * Returns: the currently active group member
+ **/
+GtkRadioAction *
+e_radio_action_get_current_action (GtkRadioAction *radio_action)
+{
+ GSList *group;
+ gint current_value;
+
+ g_return_val_if_fail (GTK_IS_RADIO_ACTION (radio_action), NULL);
+
+ group = gtk_radio_action_get_group (radio_action);
+ current_value = gtk_radio_action_get_current_value (radio_action);
+
+ while (group != NULL) {
+ gint value;
+
+ radio_action = GTK_RADIO_ACTION (group->data);
+ g_object_get (radio_action, "value", &value, NULL);
+
+ if (value == current_value)
+ return radio_action;
+
+ group = g_slist_next (group);
+ }
+
+ return NULL;
+}
+
+/**
* e_str_without_underscores:
* @s: the string to strip underscores from.
*
diff --git a/e-util/e-util.h b/e-util/e-util.h
index abc76359a6..33bc940df7 100644
--- a/e-util/e-util.h
+++ b/e-util/e-util.h
@@ -57,6 +57,8 @@ gint e_action_compare_by_label (GtkAction *action1,
GtkAction *action2);
void e_action_group_remove_all_actions
(GtkActionGroup *action_group);
+GtkRadioAction *e_radio_action_get_current_action
+ (GtkRadioAction *radio_action);
gchar * e_str_without_underscores (const gchar *s);
gint e_str_compare (gconstpointer x,
diff --git a/mail/e-mail-reader.c b/mail/e-mail-reader.c
index edea7cfa6f..94855ee68b 100644
--- a/mail/e-mail-reader.c
+++ b/mail/e-mail-reader.c
@@ -167,6 +167,8 @@ action_mail_copy_cb (GtkAction *action,
folder = message_list->folder;
+ em_folder_tree_clone_expanded (folder_tree);
+
em_folder_tree_set_excluded (
EM_FOLDER_TREE (folder_tree),
EMFT_EXCLUDE_NOSELECT | EMFT_EXCLUDE_VIRTUAL |
@@ -577,6 +579,8 @@ action_mail_move_cb (GtkAction *action,
folder = message_list->folder;
+ em_folder_tree_clone_expanded (folder_tree);
+
em_folder_tree_set_excluded (
EM_FOLDER_TREE (folder_tree),
EMFT_EXCLUDE_NOSELECT | EMFT_EXCLUDE_VIRTUAL |
diff --git a/mail/e-mail-shell-content.c b/mail/e-mail-shell-content.c
index 203876fcc3..abb7e8fa26 100644
--- a/mail/e-mail-shell-content.c
+++ b/mail/e-mail-shell-content.c
@@ -44,6 +44,9 @@
(G_TYPE_INSTANCE_GET_PRIVATE \
((obj), E_TYPE_MAIL_SHELL_CONTENT, EMailShellContentPrivate))
+#define STATE_KEY_SCROLLBAR_POSITION "ScrollbarPosition"
+#define STATE_KEY_SELECTED_MESSAGE "SelectedMessage"
+
struct _EMailShellContentPrivate {
GtkWidget *paned;
GtkWidget *message_list;
@@ -52,8 +55,6 @@ struct _EMailShellContentPrivate {
EMFormatHTMLDisplay *html_display;
GalViewInstance *view_instance;
- gchar *selected_uid;
-
/* ETable scrolling hack */
gdouble default_scrollbar_position;
@@ -97,52 +98,78 @@ static void
mail_shell_content_message_list_scrolled_cb (EMailShellContent *mail_shell_content,
MessageList *message_list)
{
+ EShellContent *shell_content;
+ EShellView *shell_view;
+ GKeyFile *key_file;
+ const gchar *folder_uri;
const gchar *key;
+ gchar *group_name;
gdouble position;
- gchar *value;
/* Save the scrollbar position for the current folder. */
- if (message_list->folder == NULL)
+ folder_uri = message_list->folder_uri;
+
+ if (folder_uri == NULL)
return;
- key = "evolution:list_scroll_position";
+ shell_content = E_SHELL_CONTENT (mail_shell_content);
+ shell_view = e_shell_content_get_shell_view (shell_content);
+ key_file = e_shell_view_get_state_key_file (shell_view);
+
+ key = STATE_KEY_SCROLLBAR_POSITION;
+ group_name = g_strdup_printf ("Folder %s", folder_uri);
position = message_list_get_scrollbar_position (message_list);
- value = g_strdup_printf ("%f", position);
- if (camel_object_meta_set (message_list->folder, key, value))
- camel_object_state_write (message_list->folder);
+ g_key_file_set_double (key_file, group_name, key, position);
+ e_shell_view_set_state_dirty (shell_view);
- g_free (value);
+ g_free (group_name);
}
static gboolean
mail_shell_content_scroll_timeout_cb (EMailShellContent *mail_shell_content)
{
EMailShellContentPrivate *priv = mail_shell_content->priv;
+ EShellContent *shell_content;
+ EShellView *shell_view;
MessageList *message_list;
EMailReader *reader;
+ GKeyFile *key_file;
+ const gchar *folder_uri;
const gchar *key;
- gdouble position;
- gchar *value;
+ gchar *group_name;
/* Initialize the scrollbar position for the current folder
* and setup a callback to handle scrollbar position changes. */
+ shell_content = E_SHELL_CONTENT (mail_shell_content);
+ shell_view = e_shell_content_get_shell_view (shell_content);
+ key_file = e_shell_view_get_state_key_file (shell_view);
+
reader = E_MAIL_READER (mail_shell_content);
message_list = e_mail_reader_get_message_list (reader);
- position = priv->default_scrollbar_position;
+ folder_uri = message_list->folder_uri;
+
+ if (folder_uri == NULL)
+ goto skip;
+
+ /* Restore the message list scrollbar position. */
- key = "evolution:list_scroll_position";
- value = camel_object_meta_get (message_list->folder, key);
+ key = STATE_KEY_SCROLLBAR_POSITION;
+ group_name = g_strdup_printf ("Folder %s", folder_uri);
- if (value != NULL) {
- position = strtod (value, NULL);
- g_free (value);
+ if (g_key_file_has_key (key_file, group_name, key, NULL)) {
+ gdouble position;
+
+ position = g_key_file_get_double (
+ key_file, group_name, key, NULL);
+ message_list_set_scrollbar_position (message_list, position);
}
- message_list_set_scrollbar_position (message_list, position);
+ g_free (group_name);
+skip:
priv->message_list_scrolled_id = g_signal_connect_swapped (
message_list, "message-list-scrolled",
G_CALLBACK (mail_shell_content_message_list_scrolled_cb),
@@ -158,37 +185,59 @@ mail_shell_content_message_list_built_cb (EMailShellContent *mail_shell_content,
MessageList *message_list)
{
EMailShellContentPrivate *priv = mail_shell_content->priv;
+ EShellContent *shell_content;
+ EShellView *shell_view;
GtkScrolledWindow *scrolled_window;
GtkWidget *vscrollbar;
- gdouble position = 0.0;
+ GKeyFile *key_file;
+ gchar *uid;
g_signal_handler_disconnect (
message_list, priv->message_list_built_id);
priv->message_list_built_id = 0;
- if (message_list->cursor_uid == NULL && priv->selected_uid != NULL) {
+ shell_content = E_SHELL_CONTENT (mail_shell_content);
+ shell_view = e_shell_content_get_shell_view (shell_content);
+ key_file = e_shell_view_get_state_key_file (shell_view);
+
+ if (message_list->cursor_uid != NULL)
+ uid = NULL;
+
+ else if (message_list->folder_uri == NULL)
+ uid = NULL;
+
+ else if (mail_shell_content->priv->suppress_message_selection)
+ uid = NULL;
+
+ else {
+ const gchar *folder_uri;
+ const gchar *key;
+ gchar *group_name;
+
+ key = STATE_KEY_SELECTED_MESSAGE;
+ folder_uri = message_list->folder_uri;
+ group_name = g_strdup_printf ("Folder %s", folder_uri);
+ uid = g_key_file_get_string (key_file, group_name, key, NULL);
+ g_free (group_name);
+ }
+
+ if (uid != NULL) {
+ CamelFolder *folder;
CamelMessageInfo *info;
- /* If the message isn't in the folder yet, keep selected_uid
- * around, as it could be caught by a set_folder() at some
- * later date. */
- info = camel_folder_get_message_info (
- message_list->folder, priv->selected_uid);
+ folder = message_list->folder;
+ info = camel_folder_get_message_info (folder, uid);
if (info != NULL) {
- camel_folder_free_message_info (
- message_list->folder, info);
- e_mail_reader_set_message (
- E_MAIL_READER (mail_shell_content),
- priv->selected_uid, TRUE);
- g_free (priv->selected_uid);
- priv->selected_uid = NULL;
+ EMailReader *reader;
+
+ reader = E_MAIL_READER (mail_shell_content);
+ e_mail_reader_set_message (reader, uid, TRUE);
+ camel_folder_free_message_info (folder, info);
}
- position = message_list_get_scrollbar_position (message_list);
+ g_free (uid);
}
- priv->default_scrollbar_position = position;
-
/* FIXME This is a gross workaround for an ETable bug that I can't
* fix (Ximian bug #55303).
*
@@ -227,25 +276,38 @@ mail_shell_content_display_view_cb (EMailShellContent *mail_shell_content,
static void
mail_shell_content_message_selected_cb (EMailShellContent *mail_shell_content,
- const gchar *selected_uid,
+ const gchar *message_uid,
MessageList *message_list)
{
- const gchar *key = "evolution:selected_uid";
- CamelFolder *folder;
+ EShellContent *shell_content;
+ EShellView *shell_view;
+ GKeyFile *key_file;
+ const gchar *folder_uri;
+ const gchar *key;
+ gchar *group_name;
- folder = message_list->folder;
+ folder_uri = message_list->folder_uri;
/* This also gets triggered when selecting a store name on
* the sidebar such as "On This Computer", in which case
- * 'folder' will be NULL. */
- if (folder == NULL)
+ * 'folder_uri' will be NULL. */
+ if (folder_uri == NULL)
return;
- if (camel_object_meta_set (folder, key, selected_uid))
- camel_object_state_write (folder);
+ shell_content = E_SHELL_CONTENT (mail_shell_content);
+ shell_view = e_shell_content_get_shell_view (shell_content);
+ key_file = e_shell_view_get_state_key_file (shell_view);
+
+ key = STATE_KEY_SELECTED_MESSAGE;
+ group_name = g_strdup_printf ("Folder %s", folder_uri);
+
+ if (message_uid != NULL)
+ g_key_file_set_string (key_file, group_name, key, message_uid);
+ else
+ g_key_file_remove_key (key_file, group_name, key, NULL);
+ e_shell_view_set_state_dirty (shell_view);
- g_free (mail_shell_content->priv->selected_uid);
- mail_shell_content->priv->selected_uid = NULL;
+ g_free (group_name);
}
static void
@@ -345,19 +407,6 @@ mail_shell_content_dispose (GObject *object)
}
static void
-mail_shell_content_finalize (GObject *object)
-{
- EMailShellContentPrivate *priv;
-
- priv = E_MAIL_SHELL_CONTENT_GET_PRIVATE (object);
-
- g_free (priv->selected_uid);
-
- /* Chain up to parent's finalize() method. */
- G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
-static void
mail_shell_content_constructed (GObject *object)
{
EMailShellContentPrivate *priv;
@@ -543,7 +592,6 @@ mail_shell_content_set_folder (EMailReader *reader,
EMailReaderIface *default_iface;
MessageList *message_list;
gboolean different_folder;
- gchar *meta_data;
priv = E_MAIL_SHELL_CONTENT_GET_PRIVATE (reader);
@@ -570,15 +618,6 @@ mail_shell_content_set_folder (EMailReader *reader,
if (different_folder)
priv->suppress_message_selection = FALSE;
- if (!priv->suppress_message_selection)
- meta_data = camel_object_meta_get (
- folder, "evolution:selected_uid");
- else
- meta_data = NULL;
-
- g_free (priv->selected_uid);
- priv->selected_uid = meta_data;
-
/* This is a one-time-only callback. */
if (message_list->cursor_uid == NULL && priv->message_list_built_id == 0)
priv->message_list_built_id = g_signal_connect_swapped (
@@ -613,7 +652,6 @@ mail_shell_content_class_init (EMailShellContentClass *class)
object_class->set_property = mail_shell_content_set_property;
object_class->get_property = mail_shell_content_get_property;
object_class->dispose = mail_shell_content_dispose;
- object_class->finalize = mail_shell_content_finalize;
object_class->constructed = mail_shell_content_constructed;
shell_content_class = E_SHELL_CONTENT_CLASS (class);
diff --git a/mail/e-mail-shell-sidebar.c b/mail/e-mail-shell-sidebar.c
index 1b090fa703..10f0062f26 100644
--- a/mail/e-mail-shell-sidebar.c
+++ b/mail/e-mail-shell-sidebar.c
@@ -33,6 +33,8 @@
(G_TYPE_INSTANCE_GET_PRIVATE \
((obj), E_TYPE_MAIL_SHELL_SIDEBAR, EMailShellSidebarPrivate))
+#define STATE_KEY_EXPANDED "Expanded"
+
struct _EMailShellSidebarPrivate {
GtkWidget *folder_tree;
};
@@ -46,6 +48,301 @@ static gpointer parent_class;
static GType mail_shell_sidebar_type;
static void
+mail_shell_sidebar_restore_state (EMailShellSidebar *mail_shell_sidebar)
+{
+ EShellView *shell_view;
+ EShellSidebar *shell_sidebar;
+ EMFolderTreeModel *folder_tree_model;
+ EMFolderTree *folder_tree;
+ GtkTreeModel *tree_model;
+ GtkTreeView *tree_view;
+ GtkTreeIter iter;
+ GHashTable *hash_table;
+ GKeyFile *key_file;
+ gboolean valid;
+ gchar *selected;
+ gchar **groups;
+ gint ii;
+
+ shell_sidebar = E_SHELL_SIDEBAR (mail_shell_sidebar);
+ shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
+ key_file = e_shell_view_get_state_key_file (shell_view);
+
+ folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);
+ folder_tree_model = em_folder_tree_get_model (folder_tree);
+ hash_table = folder_tree_model->uri_hash;
+
+ tree_view = GTK_TREE_VIEW (folder_tree);
+ tree_model = GTK_TREE_MODEL (folder_tree_model);
+
+ /* Restore selected folder. */
+
+ selected = g_key_file_get_string (
+ key_file, "Folder Tree", "Selected", NULL);
+ if (selected != NULL) {
+ em_folder_tree_set_selected (folder_tree, selected, FALSE);
+ g_free (selected);
+ }
+
+ /* Set the initial folder tree expanded state in two stages:
+ *
+ * 1) Iterate over the "Store" and "Folder" state file groups
+ * and apply the "Expanded" keys where possible.
+ *
+ * 2) Iterate over the top-level nodes in the folder tree
+ * (these are all stores) and expand those that have no
+ * corresponding "Expanded" key in the state file. This
+ * ensures that new stores are expanded by default.
+ *
+ * The expanded state is recorded and maintained in the tree model
+ * so that folder trees in other contexts can duplicate it using
+ * em_folder_tree_clone_expanded().
+ */
+
+ /* Stage 1 */
+
+ groups = g_key_file_get_groups (key_file, NULL);
+
+ for (ii = 0; groups[ii] != NULL; ii++) {
+ GtkTreeRowReference *reference;
+ GtkTreePath *path;
+ GtkTreeIter iter;
+ const gchar *group_name = groups[ii];
+ const gchar *key = STATE_KEY_EXPANDED;
+ const gchar *uri;
+ gboolean expanded;
+
+ if (g_str_has_prefix (group_name, "Store ")) {
+ uri = group_name + 6;
+ expanded = TRUE;
+ } else if (g_str_has_prefix (group_name, "Folder ")) {
+ uri = group_name + 7;
+ expanded = FALSE;
+ } else
+ continue;
+
+ if (g_key_file_has_key (key_file, group_name, key, NULL))
+ expanded = g_key_file_get_boolean (
+ key_file, group_name, key, NULL);
+
+ if (!expanded)
+ continue;
+
+ reference = g_hash_table_lookup (hash_table, uri);
+ if (reference == NULL)
+ continue;
+
+ path = gtk_tree_row_reference_get_path (reference);
+ gtk_tree_model_get_iter (tree_model, &iter, path);
+ gtk_tree_view_expand_row (tree_view, path, FALSE);
+ gtk_tree_path_free (path);
+
+ /* The expanded column is used to clone the sidebar's
+ * expanded state in other EMFolderTree instances. */
+ gtk_tree_store_set (
+ GTK_TREE_STORE (tree_model), &iter,
+ COL_BOOL_EXPANDED, TRUE, -1);
+ }
+
+ g_strfreev (groups);
+
+ /* Stage 2 */
+
+ valid = gtk_tree_model_get_iter_first (tree_model, &iter);
+
+ while (valid) {
+ const gchar *key = STATE_KEY_EXPANDED;
+ gchar *group_name;
+ gchar *uri;
+
+ gtk_tree_model_get (
+ tree_model, &iter, COL_STRING_URI, &uri, -1);
+
+ if (uri == NULL)
+ goto next;
+
+ group_name = g_strdup_printf ("Store %s", uri);
+
+ if (!g_key_file_has_key (key_file, group_name, key, NULL)) {
+ GtkTreePath *path;
+
+ path = gtk_tree_model_get_path (tree_model, &iter);
+ gtk_tree_view_expand_row (tree_view, path, FALSE);
+ gtk_tree_path_free (path);
+
+ /* The expanded column is used to clone the sidebar's
+ * expanded state in other EMFolderTree instances. */
+ gtk_tree_store_set (
+ GTK_TREE_STORE (tree_model), &iter,
+ COL_BOOL_EXPANDED, TRUE, -1);
+ }
+
+ g_free (group_name);
+ g_free (uri);
+
+ next:
+ valid = gtk_tree_model_iter_next (tree_model, &iter);
+ }
+}
+
+static void
+mail_shell_sidebar_row_collapsed_cb (EShellSidebar *shell_sidebar,
+ GtkTreeIter *iter,
+ GtkTreePath *path,
+ GtkTreeView *tree_view)
+{
+ EShellView *shell_view;
+ GtkTreeModel *model;
+ GKeyFile *key_file;
+ const gchar *key;
+ gboolean is_folder;
+ gboolean is_store;
+ gchar *group_name;
+ gchar *uri;
+
+ shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
+ key_file = e_shell_view_get_state_key_file (shell_view);
+
+ model = gtk_tree_view_get_model (tree_view);
+
+ gtk_tree_model_get (
+ model, iter,
+ COL_STRING_URI, &uri,
+ COL_BOOL_IS_STORE, &is_store,
+ COL_BOOL_IS_FOLDER, &is_folder, -1);
+
+ g_return_if_fail (is_store || is_folder);
+
+ /* The expanded column is used to clone the sidebar's
+ * expanded state in other EMFolderTree instances. */
+ gtk_tree_store_set (
+ GTK_TREE_STORE (model), iter,
+ COL_BOOL_EXPANDED, FALSE, -1);
+
+ key = STATE_KEY_EXPANDED;
+ if (is_store)
+ group_name = g_strdup_printf ("Store %s", uri);
+ else
+ group_name = g_strdup_printf ("Folder %s", uri);
+
+ g_key_file_set_boolean (key_file, group_name, key, FALSE);
+ e_shell_view_set_state_dirty (shell_view);
+
+ g_free (group_name);
+ g_free (uri);
+}
+
+static void
+mail_shell_sidebar_row_expanded_cb (EShellSidebar *shell_sidebar,
+ GtkTreeIter *unused,
+ GtkTreePath *path,
+ GtkTreeView *tree_view)
+{
+ EShellView *shell_view;
+ GtkTreeModel *model;
+ GKeyFile *key_file;
+ const gchar *key;
+ gboolean is_folder;
+ gboolean is_store;
+ gchar *group_name;
+ gchar *uri;
+
+ shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
+ key_file = e_shell_view_get_state_key_file (shell_view);
+
+ path = gtk_tree_path_copy (path);
+ model = gtk_tree_view_get_model (tree_view);
+
+ /* Expand the node and all ancestors. */
+ while (gtk_tree_path_get_depth (path) > 0) {
+ GtkTreeIter iter;
+
+ gtk_tree_model_get_iter (model, &iter, path);
+
+ gtk_tree_model_get (
+ model, &iter,
+ COL_STRING_URI, &uri,
+ COL_BOOL_IS_STORE, &is_store,
+ COL_BOOL_IS_FOLDER, &is_folder, -1);
+
+ g_return_if_fail (is_store || is_folder);
+
+ /* The expanded column is used to clone the sidebar's
+ * expanded state in other EMFolderTree instances. */
+ gtk_tree_store_set (
+ GTK_TREE_STORE (model), &iter,
+ COL_BOOL_EXPANDED, TRUE, -1);
+
+ key = STATE_KEY_EXPANDED;
+ if (is_store)
+ group_name = g_strdup_printf ("Store %s", uri);
+ else
+ group_name = g_strdup_printf ("Folder %s", uri);
+
+ g_key_file_set_boolean (key_file, group_name, key, TRUE);
+ e_shell_view_set_state_dirty (shell_view);
+
+ g_free (group_name);
+ g_free (uri);
+
+ gtk_tree_path_up (path);
+ }
+
+ gtk_tree_path_free (path);
+}
+
+static void
+mail_shell_sidebar_model_loaded_row_cb (EMailShellSidebar *mail_shell_sidebar,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ GtkTreeModel *model)
+{
+ EShellSidebar *shell_sidebar;
+ EShellView *shell_view;
+ GtkTreeView *tree_view;
+ GKeyFile *key_file;
+ gboolean is_folder;
+ gboolean is_store;
+ const gchar *key;
+ gchar *group_name;
+ gchar *uri;
+ gboolean expanded;
+
+ shell_sidebar = E_SHELL_SIDEBAR (mail_shell_sidebar);
+ shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
+ key_file = e_shell_view_get_state_key_file (shell_view);
+
+ tree_view = GTK_TREE_VIEW (mail_shell_sidebar->priv->folder_tree);
+
+ gtk_tree_model_get (
+ model, iter,
+ COL_STRING_URI, &uri,
+ COL_BOOL_IS_STORE, &is_store,
+ COL_BOOL_IS_FOLDER, &is_folder, -1);
+
+ g_return_if_fail (is_store || is_folder);
+
+ key = STATE_KEY_EXPANDED;
+ if (is_store) {
+ group_name = g_strdup_printf ("Store %s", uri);
+ expanded = TRUE;
+ } else {
+ group_name = g_strdup_printf ("Folder %s", uri);
+ expanded = FALSE;
+ }
+
+ if (g_key_file_has_key (key_file, group_name, key, NULL))
+ expanded = g_key_file_get_boolean (
+ key_file, group_name, key, NULL);
+
+ if (expanded)
+ gtk_tree_view_expand_row (tree_view, path, FALSE);
+
+ g_free (group_name);
+ g_free (uri);
+}
+
+static void
mail_shell_sidebar_selection_changed_cb (EShellSidebar *shell_sidebar,
GtkTreeSelection *selection)
{
@@ -53,21 +350,34 @@ mail_shell_sidebar_selection_changed_cb (EShellSidebar *shell_sidebar,
EShellViewClass *shell_view_class;
GtkTreeModel *model;
GtkTreeIter iter;
+ GKeyFile *key_file;
const gchar *icon_name;
gchar *display_name = NULL;
+ gchar *uri = NULL;
gboolean is_folder = FALSE;
guint flags = 0;
shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
shell_view_class = E_SHELL_VIEW_GET_CLASS (shell_view);
+ key_file = e_shell_view_get_state_key_file (shell_view);
if (gtk_tree_selection_get_selected (selection, &model, &iter))
gtk_tree_model_get (
model, &iter,
COL_STRING_DISPLAY_NAME, &display_name,
+ COL_STRING_URI, &uri,
COL_BOOL_IS_FOLDER, &is_folder,
COL_UINT_FLAGS, &flags, -1);
+ if (uri != NULL)
+ g_key_file_set_string (
+ key_file, "Folder Tree", "Selected", uri);
+ else
+ g_key_file_remove_key (
+ key_file, "Folder Tree", "Selected", NULL);
+
+ e_shell_view_set_state_dirty (shell_view);
+
if (is_folder)
icon_name = em_folder_utils_get_icon_name (flags);
else {
@@ -79,6 +389,7 @@ mail_shell_sidebar_selection_changed_cb (EShellSidebar *shell_sidebar,
e_shell_sidebar_set_primary_text (shell_sidebar, display_name);
g_free (display_name);
+ g_free (uri);
}
static void
@@ -128,8 +439,9 @@ mail_shell_sidebar_finalize (GObject *object)
static void
mail_shell_sidebar_constructed (GObject *object)
{
- EMailShellSidebarPrivate *priv;
EMailShellBackend *mail_shell_backend;
+ EMailShellSidebar *mail_shell_sidebar;
+ EMFolderTreeModel *folder_tree_model;
EShellSidebar *shell_sidebar;
EShellBackend *shell_backend;
EShellView *shell_view;
@@ -138,15 +450,18 @@ mail_shell_sidebar_constructed (GObject *object)
GtkWidget *container;
GtkWidget *widget;
- priv = E_MAIL_SHELL_SIDEBAR_GET_PRIVATE (object);
-
/* Chain up to parent's constructed method. */
G_OBJECT_CLASS (parent_class)->constructed (object);
shell_sidebar = E_SHELL_SIDEBAR (object);
shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
shell_backend = e_shell_view_get_shell_backend (shell_view);
+
mail_shell_backend = E_MAIL_SHELL_BACKEND (shell_backend);
+ mail_shell_sidebar = E_MAIL_SHELL_SIDEBAR (object);
+
+ folder_tree_model = e_mail_shell_backend_get_folder_tree_model (
+ mail_shell_backend);
/* Build sidebar widgets. */
@@ -163,16 +478,33 @@ mail_shell_sidebar_constructed (GObject *object)
container = widget;
- widget = em_folder_tree_new (mail_shell_backend);
+ widget = em_folder_tree_new_with_model (folder_tree_model);
em_folder_tree_set_excluded (EM_FOLDER_TREE (widget), 0);
em_folder_tree_enable_drag_and_drop (EM_FOLDER_TREE (widget));
gtk_container_add (GTK_CONTAINER (container), widget);
- priv->folder_tree = g_object_ref (widget);
+ mail_shell_sidebar->priv->folder_tree = g_object_ref (widget);
gtk_widget_show (widget);
- tree_view = GTK_TREE_VIEW (priv->folder_tree);
+ tree_view = GTK_TREE_VIEW (mail_shell_sidebar->priv->folder_tree);
selection = gtk_tree_view_get_selection (tree_view);
+ mail_shell_sidebar_restore_state (mail_shell_sidebar);
+
+ g_signal_connect_swapped (
+ tree_view, "row-collapsed",
+ G_CALLBACK (mail_shell_sidebar_row_collapsed_cb),
+ shell_sidebar);
+
+ g_signal_connect_swapped (
+ tree_view, "row-expanded",
+ G_CALLBACK (mail_shell_sidebar_row_expanded_cb),
+ shell_sidebar);
+
+ g_signal_connect_swapped (
+ folder_tree_model, "loaded-row",
+ G_CALLBACK (mail_shell_sidebar_model_loaded_row_cb),
+ shell_sidebar);
+
g_signal_connect_swapped (
selection, "changed",
G_CALLBACK (mail_shell_sidebar_selection_changed_cb),
diff --git a/mail/e-mail-shell-view-actions.c b/mail/e-mail-shell-view-actions.c
index 6e4e7fdc8c..e9cba33117 100644
--- a/mail/e-mail-shell-view-actions.c
+++ b/mail/e-mail-shell-view-actions.c
@@ -21,6 +21,10 @@
#include "e-mail-shell-view-private.h"
+#define STATE_KEY_SEARCH_FILTER "SearchFilter"
+#define STATE_KEY_SEARCH_SCOPE "SearchScope"
+#define STATE_KEY_SEARCH_TEXT "SearchText"
+
static void
action_gal_save_custom_view_cb (GtkAction *action,
EMailShellView *mail_shell_view)
@@ -135,6 +139,7 @@ action_mail_folder_copy_cb (GtkAction *action,
EMailShellSidebar *mail_shell_sidebar;
CamelFolderInfo *folder_info;
EMFolderTree *folder_tree;
+ EMFolderTreeModel *model;
mail_shell_sidebar = mail_shell_view->priv->mail_shell_sidebar;
folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);
@@ -142,7 +147,8 @@ action_mail_folder_copy_cb (GtkAction *action,
g_return_if_fail (folder_info != NULL);
/* XXX Leaking folder_info? */
- em_folder_utils_copy_folder (folder_info, FALSE);
+ model = em_folder_tree_get_model (folder_tree);
+ em_folder_utils_copy_folder (model, folder_info, FALSE);
}
static void
@@ -230,6 +236,7 @@ action_mail_folder_move_cb (GtkAction *action,
EMailShellSidebar *mail_shell_sidebar;
CamelFolderInfo *folder_info;
EMFolderTree *folder_tree;
+ EMFolderTreeModel *model;
mail_shell_sidebar = mail_shell_view->priv->mail_shell_sidebar;
folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);
@@ -237,7 +244,8 @@ action_mail_folder_move_cb (GtkAction *action,
g_return_if_fail (folder_info != NULL);
/* XXX Leaking folder_info? */
- em_folder_utils_copy_folder (folder_info, TRUE);
+ model = em_folder_tree_get_model (folder_tree);
+ em_folder_utils_copy_folder (model, folder_info, TRUE);
}
static void
@@ -600,19 +608,6 @@ action_mail_label_none_cb (GtkAction *action,
}
static void
-action_mail_preview_cb (GtkToggleAction *action,
- EMailShellView *mail_shell_view)
-{
- EMailShellContent *mail_shell_content;
- gboolean active;
-
- mail_shell_content = mail_shell_view->priv->mail_shell_content;
- active = gtk_toggle_action_get_active (action);
-
- e_mail_shell_content_set_preview_visible (mail_shell_content, active);
-}
-
-static void
action_mail_search_cb (GtkRadioAction *action,
GtkRadioAction *current,
EMailShellView *mail_shell_view)
@@ -883,14 +878,46 @@ action_search_execute_cb (GtkAction *action,
EMailShellView *mail_shell_view)
{
EShellView *shell_view;
+ EShellContent *shell_content;
+ EMailReader *reader;
+ MessageList *message_list;
+ GKeyFile *key_file;
+ const gchar *folder_uri;
+
+ shell_view = E_SHELL_VIEW (mail_shell_view);
+ shell_content = e_shell_view_get_shell_content (shell_view);
+ key_file = e_shell_view_get_state_key_file (shell_view);
/* All shell views respond to the activation of this action,
* which is defined by EShellWindow. But only the currently
* active shell view proceeds with executing the search. */
- shell_view = E_SHELL_VIEW (mail_shell_view);
if (!e_shell_view_is_active (shell_view))
return;
+ reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
+ message_list = e_mail_reader_get_message_list (reader);
+ folder_uri = message_list->folder_uri;
+
+ if (folder_uri != NULL) {
+ const gchar *key;
+ const gchar *string;
+ gchar *group_name;
+
+ key = STATE_KEY_SEARCH_TEXT;
+ string = e_shell_content_get_search_text (shell_content);
+ 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);
+ }
+
e_mail_shell_view_execute_search (mail_shell_view);
}
@@ -899,7 +926,37 @@ action_search_filter_cb (GtkRadioAction *action,
GtkRadioAction *current,
EMailShellView *mail_shell_view)
{
- e_mail_shell_view_execute_search (mail_shell_view);
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ EMailReader *reader;
+ MessageList *message_list;
+ GKeyFile *key_file;
+ const gchar *folder_uri;
+
+ shell_view = E_SHELL_VIEW (mail_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ key_file = e_shell_view_get_state_key_file (shell_view);
+
+ reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
+ message_list = e_mail_reader_get_message_list (reader);
+ folder_uri = message_list->folder_uri;
+
+ 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);
+ }
+
+ gtk_action_activate (ACTION (SEARCH_EXECUTE));
}
static void
@@ -907,7 +964,37 @@ action_search_scope_cb (GtkRadioAction *action,
GtkRadioAction *current,
EMailShellView *mail_shell_view)
{
- e_mail_shell_view_execute_search (mail_shell_view);
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ EMailReader *reader;
+ MessageList *message_list;
+ GKeyFile *key_file;
+ const gchar *folder_uri;
+
+ shell_view = E_SHELL_VIEW (mail_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ key_file = e_shell_view_get_state_key_file (shell_view);
+
+ reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
+ message_list = e_mail_reader_get_message_list (reader);
+ folder_uri = message_list->folder_uri;
+
+ 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);
+ }
+
+ gtk_action_activate (ACTION (SEARCH_EXECUTE));
}
static GtkActionEntry mail_entries[] = {
@@ -1205,7 +1292,7 @@ static GtkToggleActionEntry mail_toggle_entries[] = {
N_("Show Message _Preview"),
"<Control>m",
N_("Show message preview pane"),
- G_CALLBACK (action_mail_preview_cb),
+ NULL, /* Handled by property bindings */
TRUE },
{ "mail-threads-group-by",
@@ -1468,6 +1555,10 @@ e_mail_shell_view_actions_init (EMailShellView *mail_shell_view)
dst_object = G_OBJECT (ACTION (MAIL_THREADS_EXPAND_ALL));
e_binding_new (src_object, "active", dst_object, "sensitive");
+ e_mutual_binding_new (
+ G_OBJECT (ACTION (MAIL_PREVIEW)), "active",
+ G_OBJECT (shell_content), "preview-visible");
+
/* XXX The boolean sense of the GConf key is the inverse of
* the menu item, so we have to maintain two properties. */
e_mutual_binding_new_with_negation (
diff --git a/mail/e-mail-shell-view-private.c b/mail/e-mail-shell-view-private.c
index 9026c8ed60..d4fd3c7564 100644
--- a/mail/e-mail-shell-view-private.c
+++ b/mail/e-mail-shell-view-private.c
@@ -30,27 +30,23 @@ mail_shell_view_folder_tree_selected_cb (EMailShellView *mail_shell_view,
guint32 flags,
EMFolderTree *folder_tree)
{
+ EShellView *shell_view;
EMailReader *reader;
gboolean folder_selected;
+ shell_view = E_SHELL_VIEW (mail_shell_view);
reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
folder_selected =
!(flags & CAMEL_FOLDER_NOSELECT) &&
full_name != NULL;
- if (folder_selected) {
- EMFolderTreeModel *model;
-
- model = em_folder_tree_get_model (folder_tree);
- em_folder_tree_model_set_selected (model, uri);
- em_folder_tree_model_save_state (model);
-
+ if (folder_selected)
e_mail_reader_set_folder_uri (reader, uri);
- } else
+ else
e_mail_reader_set_folder (reader, NULL, NULL);
- e_shell_view_update_actions (E_SHELL_VIEW (mail_shell_view));
+ e_shell_view_update_actions (shell_view);
}
static void
@@ -122,7 +118,8 @@ mail_shell_view_message_list_right_click_cb (EShellView *shell_view,
}
static void
-mail_shell_view_reader_changed_cb (EMailShellView *mail_shell_view)
+mail_shell_view_reader_changed_cb (EMailShellView *mail_shell_view,
+ EMailReader *reader)
{
EMailShellContent *mail_shell_content;
@@ -218,7 +215,6 @@ e_mail_shell_view_private_constructed (EMailShellView *mail_shell_view)
EShellSidebar *shell_sidebar;
EShellWindow *shell_window;
EMFormatHTMLDisplay *html_display;
- EMFolderTreeModel *folder_tree_model;
EMFolderTree *folder_tree;
RuleContext *context;
FilterRule *rule = NULL;
@@ -229,7 +225,6 @@ e_mail_shell_view_private_constructed (EMailShellView *mail_shell_view)
GtkHTML *html;
const gchar *source;
guint merge_id;
- gchar *uri;
gint ii = 0;
shell_view = E_SHELL_VIEW (mail_shell_view);
@@ -298,6 +293,11 @@ e_mail_shell_view_private_constructed (EMailShellView *mail_shell_view)
mail_shell_view);
g_signal_connect_swapped (
+ reader, "folder-loaded",
+ G_CALLBACK (e_mail_shell_view_restore_state),
+ mail_shell_view);
+
+ g_signal_connect_swapped (
tree_model, "row-changed",
G_CALLBACK (e_mail_shell_view_update_search_filter),
mail_shell_view);
@@ -336,24 +336,6 @@ e_mail_shell_view_private_constructed (EMailShellView *mail_shell_view)
priv->search_rules[ii++] = g_object_ref (rule);
}
g_assert (ii == MAIL_NUM_SEARCH_RULES);
-
- /* Restore the previously selected folder. */
- folder_tree_model = em_folder_tree_get_model (folder_tree);
- uri = em_folder_tree_model_get_selected (folder_tree_model);
- if (uri != NULL) {
- gboolean expanded;
-
- expanded = em_folder_tree_model_get_expanded_uri (
- folder_tree_model, uri);
- em_folder_tree_set_selected (folder_tree, uri, FALSE);
- e_mail_reader_set_folder_uri (reader, uri);
-
- if (!expanded)
- em_folder_tree_model_set_expanded_uri (
- folder_tree_model, uri, expanded);
-
- g_free (uri);
- }
}
void
@@ -377,6 +359,33 @@ e_mail_shell_view_private_finalize (EMailShellView *mail_shell_view)
}
void
+e_mail_shell_view_restore_state (EMailShellView *mail_shell_view)
+{
+ EShellView *shell_view;
+ EShellContent *shell_content;
+ EMailReader *reader;
+ MessageList *message_list;
+ const gchar *folder_uri;
+ gchar *group_name;
+
+ /* XXX Move this to EMailShellContent. */
+
+ g_return_if_fail (E_IS_MAIL_SHELL_VIEW (mail_shell_view));
+
+ shell_view = E_SHELL_VIEW (mail_shell_view);
+ shell_content = e_shell_view_get_shell_content (shell_view);
+
+ reader = E_MAIL_READER (shell_content);
+ message_list = e_mail_reader_get_message_list (reader);
+ folder_uri = message_list->folder_uri;
+ g_return_if_fail (folder_uri != NULL);
+
+ group_name = g_strdup_printf ("Folder %s", folder_uri);
+ e_shell_content_restore_state (shell_content, group_name);
+ g_free (group_name);
+}
+
+void
e_mail_shell_view_execute_search (EMailShellView *mail_shell_view)
{
EShell *shell;
@@ -538,7 +547,7 @@ filter:
temp = g_strdup_printf (
"(and %s (match-all "
"(> (get-received-date) "
- "(- (get_current_date) 86400))))",
+ "(- (get-current-date) 86400))))",
query);
g_free (query);
query = temp;
@@ -555,7 +564,7 @@ filter:
temp = g_strdup_printf (
"(and %s (match-all "
"(> (get-received-date) "
- "(- (get_current_date) 432000))))",
+ "(- (get-current-date) 432000))))",
query);
g_free (query);
query = temp;
diff --git a/mail/e-mail-shell-view-private.h b/mail/e-mail-shell-view-private.h
index 13c76c7cfe..f6646cabc2 100644
--- a/mail/e-mail-shell-view-private.h
+++ b/mail/e-mail-shell-view-private.h
@@ -149,6 +149,8 @@ void e_mail_shell_view_private_finalize
void e_mail_shell_view_actions_init
(EMailShellView *mail_shell_view);
+void e_mail_shell_view_restore_state
+ (EMailShellView *mail_shell_view);
void e_mail_shell_view_execute_search
(EMailShellView *mail_shell_view);
void e_mail_shell_view_create_filter_from_selected
diff --git a/mail/em-composer-utils.c b/mail/em-composer-utils.c
index 74438b2043..6c35a4e7e8 100644
--- a/mail/em-composer-utils.c
+++ b/mail/em-composer-utils.c
@@ -117,8 +117,6 @@ emcs_set_drafts_info (struct emcs_t *emcs,
camel_object_ref (drafts_folder);
emcs->drafts_folder = drafts_folder;
emcs->drafts_uid = g_strdup (drafts_uid);
-
- g_debug ("%s", G_STRFUNC);
}
static void
@@ -141,8 +139,6 @@ emcs_set_folder_info (struct emcs_t *emcs,
emcs->uid = g_strdup (uid);
emcs->flags = flags;
emcs->set = set;
-
- g_debug ("%s", G_STRFUNC);
}
static void
@@ -2412,8 +2408,9 @@ post_header_clicked_cb (EComposerPostHeader *header,
model = e_mail_shell_backend_get_folder_tree_model (mail_shell_backend);
folder_tree = em_folder_tree_new_with_model (model);
- em_folder_tree_set_multiselect (
- EM_FOLDER_TREE (folder_tree), TRUE);
+ em_folder_tree_clone_expanded (EM_FOLDER_TREE (folder_tree));
+ em_folder_tree_set_multiselect (EM_FOLDER_TREE (folder_tree), TRUE);
+
em_folder_tree_set_excluded (
EM_FOLDER_TREE (folder_tree),
EMFT_EXCLUDE_NOSELECT |
diff --git a/mail/em-folder-selection-button.c b/mail/em-folder-selection-button.c
index 933393ae80..ecdccc0af7 100644
--- a/mail/em-folder-selection-button.c
+++ b/mail/em-folder-selection-button.c
@@ -256,6 +256,7 @@ folder_selection_button_clicked (GtkButton *button)
emft = (EMFolderTree *) em_folder_tree_new_with_model (priv->model);
+ em_folder_tree_clone_expanded (emft);
em_folder_tree_set_multiselect (emft, priv->multiple_select);
em_folder_tree_set_excluded (
emft, EMFT_EXCLUDE_NOSELECT |
diff --git a/mail/em-folder-selection.c b/mail/em-folder-selection.c
index a0528554d6..56c11bcfdf 100644
--- a/mail/em-folder-selection.c
+++ b/mail/em-folder-selection.c
@@ -33,53 +33,48 @@
#include "em-folder-selector.h"
#include "em-folder-selection.h"
-#include "e-mail-shell-backend.h"
-
/* TODO: rmeove this file, it could just go on em-folder-selection or em-utils */
-struct _select_folder_data {
- void (*done) (const gchar *uri, gpointer data);
- gpointer data;
-};
-
-static void
-emfs_selector_response(EMFolderSelector *emfs, gint response, struct _select_folder_data *d)
-{
- if (response == GTK_RESPONSE_OK) {
- const gchar *uri = em_folder_selector_get_selected_uri(emfs);
-
- d->done(uri, d->data);
- }
-
- gtk_widget_destroy((GtkWidget *)emfs);
-}
-
void
-em_select_folder (GtkWindow *parent_window, const gchar *title, const gchar *oklabel, const gchar *default_uri,
- EMFTExcludeFunc exclude,
- void (*done) (const gchar *uri, gpointer user_data), gpointer user_data)
+em_select_folder (EMFolderTreeModel *model,
+ const gchar *title,
+ const gchar *oklabel,
+ const gchar *default_uri,
+ EMFTExcludeFunc exclude,
+ void (*done) (const gchar *uri, gpointer user_data),
+ gpointer user_data)
{
- struct _select_folder_data *d;
- EMFolderTreeModel *model;
GtkWidget *dialog;
EMFolderTree *emft;
- model = e_mail_shell_backend_get_folder_tree_model (global_mail_shell_backend);
+ g_return_if_fail (EM_IS_FOLDER_TREE_MODEL (model));
+ g_return_if_fail (done != NULL);
+
+ /* XXX Do we leak this reference? */
emft = (EMFolderTree *) em_folder_tree_new_with_model (model);
+ em_folder_tree_clone_expanded (emft);
+
if (exclude)
- em_folder_tree_set_excluded_func(emft, exclude, user_data);
+ em_folder_tree_set_excluded_func (emft, exclude, user_data);
else
- em_folder_tree_set_excluded (emft, EMFT_EXCLUDE_NOSELECT|EMFT_EXCLUDE_VIRTUAL|EMFT_EXCLUDE_VTRASH);
+ em_folder_tree_set_excluded (
+ emft, EMFT_EXCLUDE_NOSELECT |
+ EMFT_EXCLUDE_VIRTUAL | EMFT_EXCLUDE_VTRASH);
- dialog = em_folder_selector_new(emft, EM_FOLDER_SELECTOR_CAN_CREATE, title, NULL, oklabel);
+ dialog = em_folder_selector_new (
+ emft, EM_FOLDER_SELECTOR_CAN_CREATE, title, NULL, oklabel);
- d = g_malloc0(sizeof(*d));
- d->data = user_data;
- d->done = done;
- g_signal_connect(dialog, "response", G_CALLBACK (emfs_selector_response), d);
- g_object_set_data_full((GObject *)dialog, "e-select-data", d, (GDestroyNotify)g_free);
- gtk_widget_show(dialog);
+ if (default_uri != NULL)
+ em_folder_selector_set_selected (
+ EM_FOLDER_SELECTOR (dialog), default_uri);
+
+ if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
+ const gchar *uri;
+
+ uri = em_folder_selector_get_selected_uri (
+ EM_FOLDER_SELECTOR (dialog));
+ done (uri, user_data);
+ }
- if (default_uri)
- em_folder_selector_set_selected((EMFolderSelector *)dialog, default_uri);
+ gtk_widget_destroy (dialog);
}
diff --git a/mail/em-folder-selection.h b/mail/em-folder-selection.h
index 098fa2b227..96d14cbc19 100644
--- a/mail/em-folder-selection.h
+++ b/mail/em-folder-selection.h
@@ -24,22 +24,18 @@
#ifndef EM_FOLDER_SELECTION_H
#define EM_FOLDER_SELECTION_H
-#ifdef __cplusplus
-extern "C" {
-#pragma }
-#endif /* __cplusplus */
+#include <mail/em-folder-tree-model.h>
-#include "em-folder-tree.h"
+G_BEGIN_DECLS
-struct _GtkWindow;
+void em_select_folder (EMFolderTreeModel *model,
+ const gchar *title,
+ const gchar *oklabel,
+ const gchar *default_uri,
+ EMFTExcludeFunc exclude,
+ void (*done)(const gchar *uri, gpointer data),
+ gpointer data);
-void em_select_folder (struct _GtkWindow *parent_window, const gchar *title, const gchar *oklabel, const gchar *default_uri,
- EMFTExcludeFunc exclude,
- void (*done)(const gchar *uri, gpointer data),
- gpointer data);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
+G_END_DECLS
#endif /* EM_FOLDER_SELECTION_H */
diff --git a/mail/em-folder-tree-model.c b/mail/em-folder-tree-model.c
index f78405a7c7..f1a667b9f4 100644
--- a/mail/em-folder-tree-model.c
+++ b/mail/em-folder-tree-model.c
@@ -107,38 +107,6 @@ store_info_free (EMFolderTreeModelStoreInfo *si)
g_free (si);
}
-static void
-folder_tree_model_load_state (EMFolderTreeModel *model,
- const gchar *filename)
-{
- xmlNodePtr root, node;
-
- if (model->state)
- xmlFreeDoc (model->state);
-
- if ((model->state = e_xml_parse_file (filename)) != NULL) {
- node = xmlDocGetRootElement (model->state);
- if (!node || strcmp ((gchar *)node->name, "tree-state") != 0) {
- /* it is not expected XML file, thus free it and use the default */
- xmlFreeDoc (model->state);
- } else
- return;
- }
-
- /* setup some defaults - expand "Local Folders" and "Search Folders" */
- model->state = xmlNewDoc ((const guchar *)"1.0");
- root = xmlNewDocNode (model->state, NULL, (const guchar *)"tree-state", NULL);
- xmlDocSetRootElement (model->state, root);
-
- node = xmlNewChild (root, NULL, (const guchar *)"node", NULL);
- xmlSetProp (node, (const guchar *)"name", (const guchar *)"local");
- xmlSetProp (node, (const guchar *)"expand", (const guchar *)"true");
-
- node = xmlNewChild (root, NULL, (const guchar *)"node", NULL);
- xmlSetProp (node, (const guchar *)"name", (const guchar *)"vfolder");
- xmlSetProp (node, (const guchar *)"expand", (const guchar *)"true");
-}
-
static gint
folder_tree_model_sort (GtkTreeModel *model,
GtkTreeIter *a,
@@ -256,10 +224,6 @@ folder_tree_model_finalize (GObject *object)
{
EMFolderTreeModel *model = (EMFolderTreeModel *) object;
- g_free (model->filename);
- if (model->state)
- xmlFreeDoc (model->state);
-
g_hash_table_destroy (model->store_hash);
g_hash_table_destroy (model->uri_hash);
@@ -272,23 +236,6 @@ folder_tree_model_finalize (GObject *object)
}
static void
-folder_tree_model_constructed (GObject *object)
-{
- EMFolderTreeModel *model = EM_FOLDER_TREE_MODEL (object);
- EShellBackend *shell_backend;
- const gchar *config_dir;
- gchar *filename;
-
- shell_backend = model->priv->shell_backend;
- config_dir = e_shell_backend_get_config_dir (shell_backend);
-
- filename = g_build_filename (
- config_dir, "folder-tree-expand-state.xml", NULL);
- folder_tree_model_load_state (model, filename);
- model->filename = filename;
-}
-
-static void
folder_tree_model_class_init (EMFolderTreeModelClass *class)
{
GObjectClass *object_class;
@@ -300,7 +247,6 @@ folder_tree_model_class_init (EMFolderTreeModelClass *class)
object_class->set_property = folder_tree_model_set_property;
object_class->get_property = folder_tree_model_get_property;
object_class->finalize = folder_tree_model_finalize;
- object_class->constructed = folder_tree_model_constructed;
g_object_class_install_property (
object_class,
@@ -361,6 +307,7 @@ folder_tree_model_init (EMFolderTreeModel *model)
G_TYPE_STRING, /* uri */
G_TYPE_UINT, /* unread count */
G_TYPE_UINT, /* flags */
+ G_TYPE_BOOLEAN, /* is expanded in sidebar */
G_TYPE_BOOLEAN, /* is a store node */
G_TYPE_BOOLEAN, /* is a folder node */
G_TYPE_BOOLEAN, /* has not-yet-loaded subfolders */
@@ -399,19 +346,6 @@ folder_tree_model_init (EMFolderTreeModel *model)
model->account_removed_id = g_signal_connect (
model->accounts, "account-removed",
G_CALLBACK (account_removed), model);
- //g_signal_connect (
- // model, "row-changed",
- // G_CALLBACK (emft_model_unread_count_changed), NULL);
-}
-
-static void
-tree_model_iface_init (GtkTreeModelIface *iface)
-{
-}
-
-static void
-tree_sortable_iface_init (GtkTreeSortableIface *iface)
-{
}
GType
@@ -433,41 +367,20 @@ em_folder_tree_model_get_type (void)
NULL /* value_table */
};
- static const GInterfaceInfo tree_model_info = {
- (GInterfaceInitFunc) tree_model_iface_init,
- NULL,
- NULL
- };
-
- static const GInterfaceInfo sortable_info = {
- (GInterfaceInitFunc) tree_sortable_iface_init,
- NULL,
- NULL
- };
-
type = g_type_register_static (
GTK_TYPE_TREE_STORE, "EMFolderTreeModel",
&type_info, 0);
-
- g_type_add_interface_static (
- type, GTK_TYPE_TREE_MODEL, &tree_model_info);
- g_type_add_interface_static (
- type, GTK_TYPE_TREE_SORTABLE, &sortable_info);
}
return type;
}
-
static void
emft_model_unread_count_changed (GtkTreeModel *model, GtkTreeIter *iter)
{
GtkTreeIter parent_iter;
GtkTreeIter child_iter = *iter;
- g_signal_handlers_block_by_func (
- model, emft_model_unread_count_changed, NULL);
-
/* Folders are displayed with a bold weight to indicate that
they contain unread messages. We signal that parent rows
have changed here to update them. */
@@ -480,14 +393,8 @@ emft_model_unread_count_changed (GtkTreeModel *model, GtkTreeIter *iter)
gtk_tree_path_free (parent_path);
child_iter = parent_iter;
}
-
- g_signal_handlers_unblock_by_func (
- model, emft_model_unread_count_changed, NULL);
}
-
-
-
EMFolderTreeModel *
em_folder_tree_model_new (EMailShellBackend *mail_shell_backend)
{
@@ -1012,7 +919,7 @@ em_folder_tree_model_add_store (EMFolderTreeModel *model, CamelStore *store, con
camel_object_ref (store);
si->store = store;
si->account = account;
- si->row = row;
+ si->row = gtk_tree_row_reference_copy (row);
si->full_hash = g_hash_table_new_full (
g_str_hash, g_str_equal,
(GDestroyNotify) g_free,
@@ -1020,6 +927,9 @@ em_folder_tree_model_add_store (EMFolderTreeModel *model, CamelStore *store, con
g_hash_table_insert (model->store_hash, store, si);
g_hash_table_insert (model->account_hash, account, si);
+ /* Transfer ownership of the URI and GtkTreeRowReference. */
+ g_hash_table_insert (model->uri_hash, uri, row);
+
/* each store has folders... but we don't load them until the user demands them */
root = iter;
gtk_tree_store_append ((GtkTreeStore *) model, &iter, &root);
@@ -1034,8 +944,6 @@ em_folder_tree_model_add_store (EMFolderTreeModel *model, CamelStore *store, con
COL_UINT_UNREAD_LAST_SEL, 0,
-1);
- g_free (uri);
-
/* listen to store events */
#define CAMEL_CALLBACK(func) ((CamelObjectEventHookFunc) func)
si->created_id = camel_object_hook_event (store, "folder_created", CAMEL_CALLBACK (folder_created_cb), model);
@@ -1133,275 +1041,6 @@ em_folder_tree_model_remove_store (EMFolderTreeModel *model, CamelStore *store)
em_folder_tree_model_remove_folders (model, si, &iter);
}
-
-static xmlNodePtr
-find_xml_node (xmlNodePtr root, const gchar *name)
-{
- xmlNodePtr node;
- gchar *nname;
-
- node = root->children;
- while (node != NULL) {
- if (!strcmp ((gchar *)node->name, "node")) {
- nname = (gchar *)xmlGetProp (node, (const guchar *)"name");
- if (nname && !strcmp (nname, name)) {
- xmlFree (nname);
- return node;
- }
-
- xmlFree (nname);
- }
-
- node = node->next;
- }
-
- return node;
-}
-
-gboolean
-em_folder_tree_model_get_expanded (EMFolderTreeModel *model, const gchar *key)
-{
- xmlNodePtr node;
- const gchar *name;
- gchar *buf, *p;
-
- /* This code needs to be rewritten.
- First it doesn't belong on the model
- Second, it shouldn't use an xml tree to store a bit table in memory! */
-
- node = model->state ? model->state->children : NULL;
- if (!node || strcmp ((gchar *)node->name, "tree-state") != 0)
- return FALSE;
-
- name = buf = g_alloca (strlen (key) + 1);
- p = g_stpcpy (buf, key);
- if (p[-1] == '/')
- p[-1] = '\0';
- p = NULL;
-
- do {
- if ((p = strchr (name, '/')))
- *p = '\0';
-
- if ((node = find_xml_node (node, name))) {
- gboolean expanded;
-
- buf = (gchar *)xmlGetProp (node, (const guchar *)"expand");
- expanded = buf && !strcmp ((gchar *)buf, "true");
- xmlFree (buf);
-
- if (!expanded || p == NULL)
- return expanded;
- }
-
- name = p ? p + 1 : NULL;
- } while (name && node);
-
- return FALSE;
-}
-
-
-void
-em_folder_tree_model_set_expanded (EMFolderTreeModel *model, const gchar *key, gboolean expanded)
-{
- xmlNodePtr node, parent;
- const gchar *name;
- gchar *buf, *p;
-
- if (model->state == NULL)
- model->state = xmlNewDoc ((const guchar *)"1.0");
-
- if (!model->state->children) {
- node = xmlNewDocNode (model->state, NULL, (const guchar *)"tree-state", NULL);
- xmlDocSetRootElement (model->state, node);
- } else {
- node = model->state->children;
- }
-
- name = buf = g_alloca (strlen (key) + 1);
- p = g_stpcpy (buf, key);
- if (p[-1] == '/')
- p[-1] = '\0';
- p = NULL;
-
- do {
- parent = node;
- if ((p = strchr (name, '/')))
- *p = '\0';
-
- if (!(node = find_xml_node (node, name))) {
- if (!expanded) {
- /* node doesn't exist, so we don't need to set expanded to FALSE */
- return;
- }
-
- /* node (or parent node) doesn't exist, need to add it */
- node = xmlNewChild (parent, NULL, (const guchar *)"node", NULL);
- xmlSetProp (node, (const guchar *)"name", (guchar *)name);
- }
-
- xmlSetProp (node, (const guchar *)"expand", (const guchar *)(expanded || p ? "true" : "false"));
-
- name = p ? p + 1 : NULL;
- } while (name);
-}
-
-/**
- * emftm_uri_to_key
- * Converts uri to key used in functions like em_folder_tree_model_[s/g]et_expanded.
- * @param uri Uri to be converted.
- * @return Key of the uri or NULL, if failed. Returned value should be clear by g_free.
- **/
-static gchar *
-emftm_uri_to_key (const gchar *uri)
-{
- CamelException ex = { 0 };
- CamelStore *store;
- CamelURL *url;
- gchar *key;
-
- if (!uri)
- return NULL;
-
- store = (CamelStore *)camel_session_get_service (session, uri, CAMEL_PROVIDER_STORE, &ex);
- camel_exception_clear(&ex);
-
- url = camel_url_new (uri, NULL);
-
- if (store == NULL || url == NULL) {
- key = NULL;
- } else {
- const gchar *path;
- EAccount *account;
-
- if (((CamelService *)store)->provider->url_flags & CAMEL_URL_FRAGMENT_IS_PATH)
- path = url->fragment;
- else
- path = url->path && url->path[0]=='/' ? url->path+1:url->path;
-
- if (path == NULL)
- path = "";
-
- if ( (account = mail_config_get_account_by_source_url (uri)) )
- key = g_strdup_printf ("%s/%s", account->uid, path);
- else if (CAMEL_IS_VEE_STORE (store))
- key = g_strdup_printf ("vfolder/%s", path);
- else
- key = g_strdup_printf ("local/%s", path);
- }
-
- if (url)
- camel_url_free (url);
-
- if (store)
- camel_object_unref (store);
-
- return key;
-}
-
-/**
- * em_folder_tree_model_get_expanded_uri
- * Same as @ref em_folder_tree_model_get_expanded, but here we use uri, not key for node.
- **/
-gboolean
-em_folder_tree_model_get_expanded_uri (EMFolderTreeModel *model, const gchar *uri)
-{
- gchar *key;
- gboolean expanded;
-
- g_return_val_if_fail (model != NULL, FALSE);
- g_return_val_if_fail (uri != NULL, FALSE);
-
- key = emftm_uri_to_key (uri);
- expanded = key && em_folder_tree_model_get_expanded (model, key);
-
- g_free (key);
-
- return expanded;
-}
-
-/**
- * em_folder_tree_model_set_expanded_uri
- * Same as @ref em_folder_tree_model_set_expanded, but here we use uri, not key for node.
- **/
-void
-em_folder_tree_model_set_expanded_uri (EMFolderTreeModel *model, const gchar *uri, gboolean expanded)
-{
- gchar *key;
-
- g_return_if_fail (model != NULL);
- g_return_if_fail (uri != NULL);
-
- key = emftm_uri_to_key (uri);
- if (key)
- em_folder_tree_model_set_expanded (model, key, expanded);
-
- g_free (key);
-}
-
-void
-em_folder_tree_model_save_state (EMFolderTreeModel *model)
-{
- gchar *dirname;
-
- if (model->state == NULL)
- return;
-
- dirname = g_path_get_dirname (model->filename);
- if (g_mkdir_with_parents (dirname, 0777) == -1 && errno != EEXIST) {
- g_free (dirname);
- return;
- }
-
- g_free (dirname);
-
- e_xml_save_file (model->filename, model->state);
-}
-
-
-static void
-expand_foreach_r (EMFolderTreeModel *model, xmlNodePtr parent, const gchar *dirname, EMFTModelExpandFunc func, gpointer user_data)
-{
- xmlNodePtr node = parent->children;
- gchar *path, *name, *expand;
-
- while (node != NULL) {
- if (!strcmp ((gchar *)node->name, "node")) {
- name = (gchar *)xmlGetProp (node, (const guchar *)"name");
- expand = (gchar *)xmlGetProp (node, (const guchar *)"expand");
-
- if (expand && name && !strcmp ((gchar *)expand, "true")) {
- if (dirname)
- path = g_strdup_printf ("%s/%s", dirname, name);
- else
- path = g_strdup (name);
-
- func (model, path, user_data);
- if (node->children)
- expand_foreach_r (model, node, path, func, user_data);
- g_free (path);
- }
-
- xmlFree (expand);
- xmlFree (name);
- }
-
- node = node->next;
- }
-}
-
-void
-em_folder_tree_model_expand_foreach (EMFolderTreeModel *model, EMFTModelExpandFunc func, gpointer user_data)
-{
- xmlNodePtr root;
-
- root = model->state ? model->state->children : NULL;
- if (!root || !root->children || strcmp ((gchar *)root->name, "tree-state") != 0)
- return;
-
- expand_foreach_r (model, root, NULL, func, user_data);
-}
-
gboolean
em_folder_tree_model_is_type_inbox (EMFolderTreeModel *model, CamelStore *store, const gchar *full)
{
@@ -1487,7 +1126,6 @@ em_folder_tree_model_set_unread_count (EMFolderTreeModel *model, CamelStore *sto
GtkTreePath *tree_path;
GtkTreeIter iter;
guint old_unread = 0;
- gchar *uri, *sel_uri;
g_return_if_fail (EM_IS_FOLDER_TREE_MODEL (model));
g_return_if_fail (CAMEL_IS_STORE (store));
@@ -1516,82 +1154,15 @@ em_folder_tree_model_set_unread_count (EMFolderTreeModel *model, CamelStore *sto
gtk_tree_path_free (tree_path);
- sel_uri = em_folder_tree_model_get_selected (model);
gtk_tree_model_get (
GTK_TREE_MODEL (model), &iter,
- COL_UINT_UNREAD_LAST_SEL, &old_unread,
- COL_STRING_URI, &uri, -1);
- if (!(g_strcmp0 (sel_uri, uri) != 0 && unread > old_unread))
- old_unread = unread;
+ COL_UINT_UNREAD_LAST_SEL, &old_unread, -1);
+
gtk_tree_store_set (
GTK_TREE_STORE (model), &iter,
COL_UINT_UNREAD, unread,
- COL_UINT_UNREAD_LAST_SEL, old_unread, -1);
-
- g_free (uri);
- g_free (sel_uri);
+ COL_UINT_UNREAD_LAST_SEL, MIN (old_unread, unread), -1);
/* May be this is from where we should propagate unread count to parents etc. */
emft_model_unread_count_changed (GTK_TREE_MODEL (model), &iter);
}
-
-
-gchar *
-em_folder_tree_model_get_selected (EMFolderTreeModel *model)
-{
- xmlNodePtr node;
- gchar *buf, *uri;
-
- node = model->state ? model->state->children : NULL;
- if (!node || strcmp ((gchar *)node->name, "tree-state") != 0)
- return NULL;
-
- node = node->children;
- while (node != NULL) {
- if (!strcmp ((gchar *)node->name, "selected"))
- break;
- node = node->next;
- }
-
- if (node == NULL)
- return NULL;
-
- buf = (gchar *)xmlGetProp (node, (guchar *)"uri");
- uri = g_strdup (buf);
- xmlFree (buf);
-
- if (uri && !*uri) {
- g_free (uri);
- return NULL;
- }
- return uri;
-}
-
-
-void
-em_folder_tree_model_set_selected (EMFolderTreeModel *model, const gchar *uri)
-{
- xmlNodePtr root, node;
-
- if (model->state == NULL)
- model->state = xmlNewDoc ((guchar *)"1.0");
-
- if (!model->state->children) {
- root = xmlNewDocNode (model->state, NULL, (const guchar *)"tree-state", NULL);
- xmlDocSetRootElement (model->state, root);
- } else {
- root = model->state->children;
- }
-
- node = root->children;
- while (node != NULL) {
- if (!strcmp ((gchar *)node->name, "selected"))
- break;
- node = node->next;
- }
-
- if (node == NULL)
- node = xmlNewChild (root, NULL, (const guchar *)"selected", NULL);
-
- xmlSetProp (node, (const guchar *)"uri", (guchar *)uri);
-}
diff --git a/mail/em-folder-tree-model.h b/mail/em-folder-tree-model.h
index 418248acd6..f8952d0982 100644
--- a/mail/em-folder-tree-model.h
+++ b/mail/em-folder-tree-model.h
@@ -24,7 +24,6 @@
#define EM_FOLDER_TREE_MODEL_H
#include <gtk/gtk.h>
-#include <libxml/tree.h>
#include <camel/camel-store.h>
#include <libedataserver/e-account-list.h>
#include <mail/e-mail-shell-backend.h>
@@ -64,6 +63,7 @@ enum {
COL_UINT_UNREAD, /* unread count */
COL_UINT_FLAGS, /* FolderInfo.flags */
+ COL_BOOL_EXPANDED, /* node is expanded in sidebar */
COL_BOOL_IS_STORE, /* toplevel store node? */
COL_BOOL_IS_FOLDER, /* folder (not a store) */
COL_BOOL_LOAD_SUBDIRS, /* %TRUE only if the store/folder
@@ -93,9 +93,6 @@ struct _EMFolderTreeModel {
GtkTreeStore parent;
EMFolderTreeModelPrivate *priv;
- gchar *filename; /* state filename */
- xmlDocPtr state; /* saved expanded state from previous session */
-
GHashTable *store_hash; /* maps CamelStore's to store-info's */
GHashTable *uri_hash; /* maps URI's to GtkTreeRowReferences */
@@ -120,9 +117,6 @@ struct _EMFolderTreeModelClass {
void (* folder_added) (EMFolderTreeModel *model,
const gchar *path,
const gchar *uri);
-
- void (* store_added) (EMFolderTreeModel *model,
- const gchar *uri);
};
@@ -142,20 +136,6 @@ void em_folder_tree_model_remove_store (EMFolderTreeModel *model, CamelStore *st
void em_folder_tree_model_remove_folders (EMFolderTreeModel *model, struct _EMFolderTreeModelStoreInfo *si,
GtkTreeIter *toplevel);
-gchar *em_folder_tree_model_get_selected (EMFolderTreeModel *model);
-void em_folder_tree_model_set_selected (EMFolderTreeModel *model, const gchar *uri);
-
-gboolean em_folder_tree_model_get_expanded (EMFolderTreeModel *model, const gchar *key);
-void em_folder_tree_model_set_expanded (EMFolderTreeModel *model, const gchar *key, gboolean expanded);
-
-gboolean em_folder_tree_model_get_expanded_uri (EMFolderTreeModel *model, const gchar *uri);
-void em_folder_tree_model_set_expanded_uri (EMFolderTreeModel *model, const gchar *uri, gboolean expanded);
-
-void em_folder_tree_model_save_state (EMFolderTreeModel *model);
-
-typedef void (* EMFTModelExpandFunc) (EMFolderTreeModel *model, const gchar *path, gpointer user_data);
-void em_folder_tree_model_expand_foreach (EMFolderTreeModel *model, EMFTModelExpandFunc func, gpointer user_data);
-
void em_folder_tree_model_set_unread_count (EMFolderTreeModel *model, CamelStore *store, const gchar *path, gint unread);
gboolean em_folder_tree_model_is_type_inbox (EMFolderTreeModel *model, CamelStore *store, const gchar *full);
gchar * em_folder_tree_model_get_folder_name (EMFolderTreeModel *model, CamelStore *store, const gchar *full);
diff --git a/mail/em-folder-tree.c b/mail/em-folder-tree.c
index e6abb53c9a..de488c7258 100644
--- a/mail/em-folder-tree.c
+++ b/mail/em-folder-tree.c
@@ -104,8 +104,6 @@ struct _EMFolderTreePrivate {
* we need to set it when we set the
* selection */
- guint save_state_id;
-
guint autoscroll_id;
guint autoexpand_id;
GtkTreeRowReference *autoexpand_row;
@@ -159,11 +157,6 @@ static guint signals[LAST_SIGNAL] = { 0 };
extern CamelSession *session;
extern CamelStore *vfolder_store;
-static gboolean emft_save_state (EMFolderTree *emft);
-static void emft_queue_save_state (EMFolderTree *emft);
-
-static void emft_update_model_expanded_state (struct _EMFolderTreePrivate *priv, GtkTreeIter *iter, gboolean expanded);
-
static void emft_tree_row_activated (GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *column, EMFolderTree *emft);
static gboolean emft_tree_test_collapse_row (GtkTreeView *treeview, GtkTreeIter *root, GtkTreePath *path, EMFolderTree *emft);
static void emft_tree_row_expanded (GtkTreeView *treeview, GtkTreeIter *root, GtkTreePath *path, EMFolderTree *emft);
@@ -230,11 +223,6 @@ em_folder_tree_destroy (GtkObject *object)
priv->loaded_row_id = 0;
}
- if (priv->save_state_id != 0) {
- g_source_remove (priv->save_state_id);
- emft_save_state (EM_FOLDER_TREE (object));
- }
-
if (priv->autoscroll_id != 0) {
g_source_remove (priv->autoscroll_id);
priv->autoscroll_id = 0;
@@ -418,10 +406,13 @@ render_icon (GtkTreeViewColumn *column,
GtkTreeModel *model,
GtkTreeIter *iter)
{
+ GtkTreeSelection *selection;
+ GtkWidget *tree_view;
GIcon *icon;
guint unread;
guint old_unread;
gchar *icon_name;
+ gboolean row_selected;
gtk_tree_model_get (
model, iter,
@@ -434,8 +425,12 @@ render_icon (GtkTreeViewColumn *column,
icon = g_themed_icon_new (icon_name);
+ tree_view = gtk_tree_view_column_get_tree_view (column);
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
+ row_selected = gtk_tree_selection_iter_is_selected (selection, iter);
+
/* Show an emblem if there's new mail. */
- if (unread > old_unread) {
+ if (!row_selected && unread > old_unread) {
GIcon *temp_icon;
GEmblem *emblem;
@@ -547,22 +542,6 @@ em_folder_tree_construct (EMFolderTree *emft, EMFolderTreeModel *model)
g_signal_connect (selection, "changed", G_CALLBACK (emft_tree_selection_changed), emft);
}
-GtkWidget *
-em_folder_tree_new (EMailShellBackend *mail_shell_backend)
-{
- EMFolderTreeModel *model;
- EMFolderTree *emft;
-
- g_return_val_if_fail (
- E_IS_MAIL_SHELL_BACKEND (mail_shell_backend), NULL);
-
- model = e_mail_shell_backend_get_folder_tree_model (mail_shell_backend);
- emft = (EMFolderTree *) em_folder_tree_new_with_model (model);
- g_object_unref (model);
-
- return (GtkWidget *) emft;
-}
-
/* NOTE: Removes and frees the selected uri structure */
static void
emft_select_uri(EMFolderTree *emft, GtkTreePath *path, struct _selected_uri *u)
@@ -670,7 +649,6 @@ emft_maybe_expand_row (EMFolderTreeModel *model, GtkTreePath *tree_path, GtkTree
gchar *full_name;
gchar *key;
struct _selected_uri *u;
- gboolean is_expanded;
tree_view = GTK_TREE_VIEW (emft);
@@ -691,21 +669,14 @@ emft_maybe_expand_row (EMFolderTreeModel *model, GtkTreePath *tree_path, GtkTree
key = g_strdup_printf ("local/%s", full_name ? full_name : "");
}
- is_expanded = em_folder_tree_model_get_expanded (model, key);
u = g_hash_table_lookup(priv->select_uris_table, key);
- if (is_expanded || u) {
- if (is_expanded) {
- gtk_tree_view_expand_to_path (tree_view, tree_path);
- gtk_tree_view_expand_row (tree_view, tree_path, FALSE);
- } else {
- gchar *c = strrchr (key, '/');
+ if (u) {
+ gchar *c = strrchr (key, '/');
- *c = '\0';
- emft_expand_node (model, key, emft);
- }
+ *c = '\0';
+ emft_expand_node (model, key, emft);
- if (u)
- emft_select_uri(emft, tree_path, u);
+ emft_select_uri(emft, tree_path, u);
}
g_free (full_name);
@@ -722,8 +693,6 @@ em_folder_tree_new_with_model (EMFolderTreeModel *model)
em_folder_tree_construct (emft, model);
g_object_ref (model);
- em_folder_tree_model_expand_foreach (model, (EMFTModelExpandFunc)emft_expand_node, emft);
-
emft->priv->loading_row_id = g_signal_connect (model, "loading-row", G_CALLBACK (emft_maybe_expand_row), emft);
emft->priv->loaded_row_id = g_signal_connect (model, "loaded-row", G_CALLBACK (emft_maybe_expand_row), emft);
@@ -733,6 +702,38 @@ em_folder_tree_new_with_model (EMFolderTreeModel *model)
return (GtkWidget *) emft;
}
+static gboolean
+folder_tree_clone_expanded (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ GtkTreeView *tree_view)
+{
+ gboolean expanded;
+
+ gtk_tree_model_get (model, iter, COL_BOOL_EXPANDED, &expanded, -1);
+
+ if (expanded)
+ gtk_tree_view_expand_row (tree_view, path, FALSE);
+ else
+ gtk_tree_view_collapse_row (tree_view, path);
+
+ return FALSE;
+}
+
+void
+em_folder_tree_clone_expanded (EMFolderTree *emft)
+{
+ GtkTreeModel *model;
+
+ g_return_if_fail (EM_IS_FOLDER_TREE (emft));
+
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (emft));
+
+ gtk_tree_model_foreach (
+ model, (GtkTreeModelForeachFunc)
+ folder_tree_clone_expanded, emft);
+}
+
static void
tree_drag_begin (GtkWidget *widget, GdkDragContext *context, EMFolderTree *emft)
{
@@ -1532,11 +1533,14 @@ em_folder_tree_enable_drag_and_drop (EMFolderTree *emft)
}
void
-em_folder_tree_set_multiselect (EMFolderTree *tree, gboolean mode)
+em_folder_tree_set_multiselect (EMFolderTree *tree,
+ gboolean mode)
{
GtkTreeSelection *sel;
GtkTreeView *tree_view;
+ g_return_if_fail (EM_IS_FOLDER_TREE (tree));
+
tree_view = GTK_TREE_VIEW (tree);
sel = gtk_tree_view_get_selection (tree_view);
@@ -1544,13 +1548,22 @@ em_folder_tree_set_multiselect (EMFolderTree *tree, gboolean mode)
gtk_tree_selection_set_mode (sel, mode ? GTK_SELECTION_MULTIPLE : GTK_SELECTION_SINGLE);
}
-void em_folder_tree_set_excluded(EMFolderTree *emft, guint32 flags)
+void
+em_folder_tree_set_excluded (EMFolderTree *emft, guint32 flags)
{
+ g_return_if_fail (EM_IS_FOLDER_TREE (emft));
+
emft->priv->excluded = flags;
}
-void em_folder_tree_set_excluded_func(EMFolderTree *emft, EMFTExcludeFunc exclude, gpointer data)
+void
+em_folder_tree_set_excluded_func (EMFolderTree *emft,
+ EMFTExcludeFunc exclude,
+ gpointer data)
{
+ g_return_if_fail (EM_IS_FOLDER_TREE (emft));
+ g_return_if_fail (exclude != NULL);
+
emft->priv->excluded_func = exclude;
emft->priv->excluded_data = data;
}
@@ -1684,7 +1697,6 @@ em_folder_tree_set_selected_list (EMFolderTree *emft, GList *list, gboolean expa
end = strrchr(expand_key, '/');
do {
emft_expand_node(priv->model, expand_key, emft);
- em_folder_tree_model_set_expanded(priv->model, expand_key, TRUE);
*end = 0;
end = strrchr(expand_key, '/');
} while (end);
@@ -1816,14 +1828,11 @@ emft_get_folder_info__done (struct _EMFolderTreeGetFolderInfo *m)
if (fi == NULL) {
/* no children afterall... remove the "Loading..." placeholder node */
- emft_update_model_expanded_state (priv, &root, FALSE);
-
gtk_tree_store_remove (model, &iter);
if (is_store) {
path = gtk_tree_model_get_path ((GtkTreeModel *) model, &root);
gtk_tree_view_collapse_row (tree_view, path);
- emft_queue_save_state (m->emft);
gtk_tree_path_free (path);
return;
}
@@ -1842,7 +1851,6 @@ emft_get_folder_info__done (struct _EMFolderTreeGetFolderInfo *m)
}
gtk_tree_store_set (model, &root, COL_BOOL_LOAD_SUBDIRS, FALSE, -1);
- emft_queue_save_state (m->emft);
}
static void
@@ -1865,41 +1873,8 @@ static MailMsgInfo get_folder_info_info = {
};
static void
-emft_update_model_expanded_state (struct _EMFolderTreePrivate *priv, GtkTreeIter *iter, gboolean expanded)
-{
- struct _EMFolderTreeModelStoreInfo *si;
- gboolean is_store;
- CamelStore *store;
- EAccount *account;
- gchar *full_name;
- gchar *key;
-
- gtk_tree_model_get ((GtkTreeModel *) priv->model, iter,
- COL_STRING_FULL_NAME, &full_name,
- COL_POINTER_CAMEL_STORE, &store,
- COL_BOOL_IS_STORE, &is_store,
- -1);
-
- si = g_hash_table_lookup (priv->model->store_hash, store);
- if ((account = e_get_account_by_name (si->display_name))) {
- key = g_strdup_printf ("%s/%s", account->uid, full_name ? full_name : "");
- } else if (CAMEL_IS_VEE_STORE (store)) {
- /* vfolder store */
- key = g_strdup_printf ("vfolder/%s", full_name ? full_name : "");
- } else {
- /* local store */
- key = g_strdup_printf ("local/%s", full_name ? full_name : "");
- }
-
- em_folder_tree_model_set_expanded (priv->model, key, expanded);
- g_free (full_name);
- g_free (key);
-}
-
-static void
emft_tree_row_expanded (GtkTreeView *treeview, GtkTreeIter *root, GtkTreePath *tree_path, EMFolderTree *emft)
{
- struct _EMFolderTreePrivate *priv = emft->priv;
struct _EMFolderTreeGetFolderInfo *m;
GtkTreeModel *model;
CamelStore *store;
@@ -1914,10 +1889,7 @@ emft_tree_row_expanded (GtkTreeView *treeview, GtkTreeIter *root, GtkTreePath *t
COL_BOOL_LOAD_SUBDIRS, &load,
-1);
- emft_update_model_expanded_state (priv, root, TRUE);
-
if (!load) {
- emft_queue_save_state (emft);
g_free (full_name);
return;
}
@@ -1950,9 +1922,6 @@ emft_tree_test_collapse_row (GtkTreeView *treeview, GtkTreeIter *root, GtkTreePa
gtk_tree_view_set_cursor (treeview, tree_path, NULL, FALSE);
}
- emft_update_model_expanded_state (emft->priv, root, FALSE);
- emft_queue_save_state (emft);
-
return FALSE;
}
@@ -2081,9 +2050,7 @@ emft_tree_selection_changed (GtkTreeSelection *selection, EMFolderTree *emft)
guint old_unread = 0;
if (!emft_selection_get_selected (selection, &model, &iter)) {
- em_folder_tree_model_set_selected (emft->priv->model, NULL);
g_signal_emit (emft, signals[FOLDER_SELECTED], 0, NULL, NULL, 0);
- emft_queue_save_state (emft);
return;
}
@@ -2401,29 +2368,6 @@ em_folder_tree_get_model_storeinfo (EMFolderTree *emft, CamelStore *store)
return si;
}
-static gboolean
-emft_save_state (EMFolderTree *emft)
-{
- struct _EMFolderTreePrivate *priv = emft->priv;
-
- em_folder_tree_model_save_state (priv->model);
- priv->save_state_id = 0;
-
- return FALSE;
-}
-
-
-static void
-emft_queue_save_state (EMFolderTree *emft)
-{
- struct _EMFolderTreePrivate *priv = emft->priv;
-
- if (priv->save_state_id != 0)
- return;
-
- priv->save_state_id = g_timeout_add_seconds (1, (GSourceFunc) emft_save_state, emft);
-}
-
void
em_folder_tree_set_skip_double_click (EMFolderTree *emft, gboolean skip)
{
diff --git a/mail/em-folder-tree.h b/mail/em-folder-tree.h
index bcbac54b8d..4d32f00787 100644
--- a/mail/em-folder-tree.h
+++ b/mail/em-folder-tree.h
@@ -83,9 +83,8 @@ struct _EMFolderTreeClass {
};
GType em_folder_tree_get_type (void);
-
-GtkWidget *em_folder_tree_new (EMailShellBackend *mail_shell_backend);
GtkWidget *em_folder_tree_new_with_model (EMFolderTreeModel *model);
+void em_folder_tree_clone_expanded (EMFolderTree *emft);
void em_folder_tree_enable_drag_and_drop (EMFolderTree *emft);
diff --git a/mail/em-folder-utils.c b/mail/em-folder-utils.c
index f92e8e3115..4ab00e237e 100644
--- a/mail/em-folder-utils.c
+++ b/mail/em-folder-utils.c
@@ -355,17 +355,24 @@ emfu_copy_folder_exclude(EMFolderTree *tree, GtkTreeModel *model, GtkTreeIter *i
/* FIXME: this interface references the folderinfo without copying it */
/* FIXME: these functions must be documented */
void
-em_folder_utils_copy_folder(CamelFolderInfo *folderinfo, gint delete)
+em_folder_utils_copy_folder (EMFolderTreeModel *model,
+ CamelFolderInfo *folderinfo,
+ gint delete)
{
struct _copy_folder_data *cfd;
+ g_return_if_fail (EM_IS_FOLDER_TREE_MODEL (model));
+ g_return_if_fail (folderinfo != NULL);
+
cfd = g_malloc (sizeof (*cfd));
cfd->fi = folderinfo;
cfd->delete = delete;
- em_select_folder (NULL, _("Select folder"), delete?_("_Move"):_("C_opy"),
- NULL, emfu_copy_folder_exclude,
- emfu_copy_folder_selected, cfd);
+ em_select_folder (
+ model, _("Select folder"),
+ delete ? _("_Move") : _("C_opy"),
+ NULL, emfu_copy_folder_exclude,
+ emfu_copy_folder_selected, cfd);
}
static void
@@ -696,6 +703,7 @@ em_folder_utils_create_folder (CamelFolderInfo *folderinfo, EMFolderTree *emft,
model = e_mail_shell_backend_get_folder_tree_model (global_mail_shell_backend);
folder_tree = (EMFolderTree *) em_folder_tree_new_with_model (model);
+ em_folder_tree_clone_expanded (folder_tree);
dialog = em_folder_selector_create_new (folder_tree, 0, _("Create Folder"), _("Specify where to create the folder:"));
if (folderinfo != NULL)
diff --git a/mail/em-folder-utils.h b/mail/em-folder-utils.h
index db7ddb82fd..5d1333e9d0 100644
--- a/mail/em-folder-utils.h
+++ b/mail/em-folder-utils.h
@@ -40,14 +40,15 @@ gint em_folder_utils_copy_folders (CamelStore *fromstore,
/* FIXME These API's are really busted. There is no consistency and
* most rely on the wrong data. */
-void em_folder_utils_copy_folder (CamelFolderInfo *folderinfo,
- gint delete);
+void em_folder_utils_copy_folder (EMFolderTreeModel *model,
+ CamelFolderInfo *folderinfo,
+ gboolean delete);
void em_folder_utils_delete_folder (CamelFolder *folder);
void em_folder_utils_rename_folder (CamelFolder *folder);
void em_folder_utils_create_folder (CamelFolderInfo *folderinfo,
- EMFolderTree * emft,
+ EMFolderTree *emft,
GtkWindow *parent);
const gchar * em_folder_utils_get_icon_name (guint32 flags);
diff --git a/plugins/groupwise-features/install-shared.c b/plugins/groupwise-features/install-shared.c
index 67b1b5bdee..e9fd927894 100644
--- a/plugins/groupwise-features/install-shared.c
+++ b/plugins/groupwise-features/install-shared.c
@@ -166,6 +166,8 @@ accept_clicked(GnomeDruidPage *page, GtkWidget *druid, CamelMimeMessage *msg)
accept_data = g_new0(struct AcceptData, 1);
model = mail_component_peek_tree_model (NULL);
folder_tree = (EMFolderTree *) em_folder_tree_new_with_model (model);
+ em_folder_tree_clone_expanded (folder_tree);
+
dialog = em_folder_selector_create_new (folder_tree, 0, _("Create folder"), _("Specify where to create the folder:"));
uri = em_folder_tree_get_selected_uri(folder_tree);
em_folder_selector_set_selected ((EMFolderSelector *) dialog, uri);
diff --git a/plugins/groupwise-features/share-folder-common.c b/plugins/groupwise-features/share-folder-common.c
index 50bb6fccf3..900d949251 100644
--- a/plugins/groupwise-features/share-folder-common.c
+++ b/plugins/groupwise-features/share-folder-common.c
@@ -383,6 +383,8 @@ create_shared_folder(EPopup *ep, EPopupItem *p, gpointer data)
model = mail_component_peek_tree_model (mail_component_peek ());
folder_tree = (EMFolderTree *) em_folder_tree_new_with_model (model);
+ em_folder_tree_clone_expanded (folder_tree);
+
dialog = em_folder_selector_create_new (folder_tree, 0, _("Create folder"), _("Specify where to create the folder:"));
uri = em_folder_tree_get_selected_uri(folder_tree);
em_folder_selector_set_selected ((EMFolderSelector *) dialog, uri);
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,