aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--mail/e-mail-backend.c35
-rw-r--r--mail/e-mail-backend.h7
-rw-r--r--mail/e-mail-reader.c6
-rw-r--r--mail/e-mail-sidebar.c2
-rw-r--r--mail/e-mail-store.c36
-rw-r--r--mail/em-composer-utils.c2
-rw-r--r--mail/em-folder-selection-button.c4
-rw-r--r--mail/em-folder-tree-model.c367
-rw-r--r--mail/em-folder-tree-model.h11
-rw-r--r--mail/em-folder-tree.c2
-rw-r--r--mail/em-folder-utils.c19
-rw-r--r--mail/em-subscription-editor.c2
-rw-r--r--mail/em-utils.c168
-rw-r--r--mail/em-utils.h4
-rw-r--r--mail/em-vfolder-rule.c2
-rw-r--r--mail/evolution-mail.schemas.in35
-rw-r--r--mail/message-list.c2
-rw-r--r--modules/mail/e-mail-shell-settings.c8
-rw-r--r--modules/mail/e-mail-shell-view.c2
-rw-r--r--modules/mail/em-account-prefs.c95
-rw-r--r--plugins/mark-all-read/mark-all-read.c6
-rw-r--r--widgets/misc/e-account-manager.c103
-rw-r--r--widgets/misc/e-account-tree-view.c772
-rw-r--r--widgets/misc/e-account-tree-view.h46
24 files changed, 1628 insertions, 108 deletions
diff --git a/mail/e-mail-backend.c b/mail/e-mail-backend.c
index c9ee133bb0..ff37b7a93a 100644
--- a/mail/e-mail-backend.c
+++ b/mail/e-mail-backend.c
@@ -71,9 +71,16 @@ enum {
PROP_SESSION
};
+enum {
+ ACCOUNT_SORT_ORDER_CHANGED,
+ LAST_SIGNAL
+};
+
/* FIXME Kill this thing. It's a horrible hack. */
extern gint camel_application_is_exiting;
+static guint signals[LAST_SIGNAL];
+
G_DEFINE_ABSTRACT_TYPE (
EMailBackend,
e_mail_backend,
@@ -538,7 +545,7 @@ mail_backend_folder_changed_cb (MailFolderCache *folder_cache,
const gchar *msg_uid,
const gchar *msg_sender,
const gchar *msg_subject,
- EShell *shell)
+ EMailBackend *mail_backend)
{
CamelFolder *folder = NULL;
EMEvent *event = em_event_peek ();
@@ -565,12 +572,12 @@ mail_backend_folder_changed_cb (MailFolderCache *folder_cache,
folder_type = (flags & CAMEL_FOLDER_TYPE_MASK);
target->is_inbox = (folder_type == CAMEL_FOLDER_TYPE_INBOX);
- model = em_folder_tree_model_get_default ();
+ model = em_folder_tree_model_get_default (mail_backend);
target->display_name = em_folder_tree_model_get_folder_name (
model, store, folder_name);
if (target->new > 0)
- e_shell_event (shell, "mail-icon", (gpointer) "mail-unread");
+ e_shell_event (e_shell_backend_get_shell (E_SHELL_BACKEND (mail_backend)), "mail-icon", (gpointer) "mail-unread");
/** @Event: folder.changed
* @Title: Folder changed
@@ -766,7 +773,7 @@ mail_backend_constructed (GObject *object)
e_account_combo_box_set_session (CAMEL_SESSION (priv->session));
/* FIXME EMailBackend should own the default EMFolderTreeModel. */
- folder_tree_model = em_folder_tree_model_get_default ();
+ folder_tree_model = em_folder_tree_model_get_default (E_MAIL_BACKEND (shell_backend));
em_folder_tree_model_set_session (folder_tree_model, priv->session);
g_signal_connect (
@@ -801,7 +808,7 @@ mail_backend_constructed (GObject *object)
g_signal_connect (
folder_cache, "folder-changed",
- G_CALLBACK (mail_backend_folder_changed_cb), shell);
+ G_CALLBACK (mail_backend_folder_changed_cb), shell_backend);
mail_config_init (priv->session);
mail_msg_init ();
@@ -838,6 +845,15 @@ e_mail_backend_class_init (EMailBackendClass *class)
NULL,
E_TYPE_MAIL_SESSION,
G_PARAM_READABLE));
+
+ signals[ACCOUNT_SORT_ORDER_CHANGED] = g_signal_new (
+ "account-sort-order-changed",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EMailBackendClass, account_sort_order_changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
}
static void
@@ -934,3 +950,12 @@ e_mail_backend_submit_alert (EMailBackend *backend,
e_alert_submit_valist (E_ALERT_SINK (shell_content), tag, va);
va_end (va);
}
+
+void
+e_mail_backend_account_sort_order_changed (EMailBackend *backend)
+{
+ g_return_if_fail (backend != NULL);
+ g_return_if_fail (E_IS_MAIL_BACKEND (backend));
+
+ g_signal_emit (backend, signals[ACCOUNT_SORT_ORDER_CHANGED], 0);
+}
diff --git a/mail/e-mail-backend.h b/mail/e-mail-backend.h
index 6d425197f3..4d3cc10799 100644
--- a/mail/e-mail-backend.h
+++ b/mail/e-mail-backend.h
@@ -67,6 +67,10 @@ struct _EMailBackendClass {
(EMailBackend *backend);
gboolean (*empty_trash_policy_decision)
(EMailBackend *backend);
+
+ /* Signals */
+ void (*account_sort_order_changed)
+ (EMailBackend *backend);
};
GType e_mail_backend_get_type (void);
@@ -79,6 +83,9 @@ void e_mail_backend_submit_alert (EMailBackend *backend,
const gchar *tag,
...) G_GNUC_NULL_TERMINATED;
+void e_mail_backend_account_sort_order_changed
+ (EMailBackend *backend);
+
G_END_DECLS
#endif /* E_MAIL_BACKEND_H */
diff --git a/mail/e-mail-reader.c b/mail/e-mail-reader.c
index 430f71dc4f..a8e3899ace 100644
--- a/mail/e-mail-reader.c
+++ b/mail/e-mail-reader.c
@@ -300,7 +300,7 @@ action_mail_copy_cb (GtkAction *action,
window = e_mail_reader_get_window (reader);
uids = e_mail_reader_get_selected_uids (reader);
- model = em_folder_tree_model_get_default ();
+ model = em_folder_tree_model_get_default (backend);
dialog = em_folder_selector_new (
window, backend, model,
@@ -732,7 +732,7 @@ action_mail_mark_unread_cb (GtkAction *action,
/* Notify the tree model that the user has marked messages as
* unread so it doesn't mistake the event as new mail arriving. */
- model = em_folder_tree_model_get_default ();
+ model = em_folder_tree_model_get_default (e_mail_reader_get_backend (reader));
folder = e_mail_reader_get_folder (reader);
em_folder_tree_model_user_marked_unread (model, folder, n_marked);
}
@@ -806,7 +806,7 @@ action_mail_move_cb (GtkAction *action,
uids = e_mail_reader_get_selected_uids (reader);
window = e_mail_reader_get_window (reader);
- model = em_folder_tree_model_get_default ();
+ model = em_folder_tree_model_get_default (backend);
dialog = em_folder_selector_new (
window, backend, model,
diff --git a/mail/e-mail-sidebar.c b/mail/e-mail-sidebar.c
index 35048f8293..6a971ea51f 100644
--- a/mail/e-mail-sidebar.c
+++ b/mail/e-mail-sidebar.c
@@ -471,7 +471,7 @@ e_mail_sidebar_new (EMailBackend *backend,
g_return_val_if_fail (E_IS_MAIL_BACKEND (backend), NULL);
g_return_val_if_fail (E_IS_ALERT_SINK (alert_sink), NULL);
- model = em_folder_tree_model_get_default ();
+ model = em_folder_tree_model_get_default (backend);
return g_object_new (
E_TYPE_MAIL_SIDEBAR,
diff --git a/mail/e-mail-store.c b/mail/e-mail-store.c
index ea44e4238b..7b7774399d 100644
--- a/mail/e-mail-store.c
+++ b/mail/e-mail-store.c
@@ -39,6 +39,9 @@
#include "mail/mail-mt.h"
#include "mail/mail-ops.h"
+#include "shell/e-shell.h"
+#include "shell/e-shell-settings.h"
+
typedef struct _StoreInfo StoreInfo;
typedef void (*AddStoreCallback) (MailFolderCache *folder_cache,
@@ -152,6 +155,32 @@ mail_store_note_store_cb (MailFolderCache *folder_cache,
return TRUE;
}
+static gboolean
+special_mail_store_is_enabled (CamelStore *store)
+{
+ CamelService *service;
+ EShell *shell;
+ EShellSettings *shell_settings;
+ const gchar *uid, *prop = NULL;
+
+ service = CAMEL_SERVICE (store);
+ g_return_val_if_fail (service, FALSE);
+
+ uid = camel_service_get_uid (service);
+ if (g_strcmp0 (uid, "local") == 0)
+ prop = "mail-enable-local-folders";
+ else if (g_strcmp0 (uid, "vfolder") == 0)
+ prop = "mail-enable-search-folders";
+
+ if (!prop)
+ return TRUE;
+
+ shell = e_shell_get_default ();
+ shell_settings = e_shell_get_shell_settings (shell);
+
+ return e_shell_settings_get_boolean (shell_settings, prop);
+}
+
static void
mail_store_add (EMailSession *session,
CamelStore *store,
@@ -165,7 +194,7 @@ mail_store_add (EMailSession *session,
g_return_if_fail (store != NULL);
g_return_if_fail (CAMEL_IS_STORE (store));
- default_model = em_folder_tree_model_get_default ();
+ default_model = em_folder_tree_model_get_default (NULL);
folder_cache = e_mail_session_get_folder_cache (session);
store_info = store_info_new (store);
@@ -173,7 +202,8 @@ mail_store_add (EMailSession *session,
g_hash_table_insert (store_table, store, store_info);
- em_folder_tree_model_add_store (default_model, store);
+ if (special_mail_store_is_enabled (store))
+ em_folder_tree_model_add_store (default_model, store);
mail_folder_cache_note_store (
folder_cache, CAMEL_SESSION (session), store, NULL,
@@ -387,7 +417,7 @@ e_mail_store_remove (EMailSession *session,
folder_cache = e_mail_session_get_folder_cache (session);
mail_folder_cache_note_store_remove (folder_cache, store);
- default_model = em_folder_tree_model_get_default ();
+ default_model = em_folder_tree_model_get_default (NULL);
em_folder_tree_model_remove_store (default_model, store);
mail_disconnect_store (store);
diff --git a/mail/em-composer-utils.c b/mail/em-composer-utils.c
index 8c98040ada..e42559ab3b 100644
--- a/mail/em-composer-utils.c
+++ b/mail/em-composer-utils.c
@@ -2989,7 +2989,7 @@ post_header_clicked_cb (EComposerPostHeader *header,
shell_backend = e_shell_get_backend_by_name (shell, "mail");
/* FIXME Limit the folder tree to the NNTP account? */
- model = em_folder_tree_model_get_default ();
+ model = em_folder_tree_model_get_default (E_MAIL_BACKEND (shell_backend));
dialog = em_folder_selector_new (
GTK_WINDOW (composer),
diff --git a/mail/em-folder-selection-button.c b/mail/em-folder-selection-button.c
index 3f05147078..26a3c9c2b0 100644
--- a/mail/em-folder-selection-button.c
+++ b/mail/em-folder-selection-button.c
@@ -272,13 +272,13 @@ folder_selection_button_clicked (GtkButton *button)
session = e_mail_backend_get_session (priv->backend);
- model = em_folder_tree_model_new ();
+ model = em_folder_tree_model_new (priv->backend);
em_folder_tree_model_set_session (model, session);
em_folder_tree_model_add_store (model, priv->store);
}
if (model == NULL)
- model = g_object_ref (em_folder_tree_model_get_default ());
+ model = g_object_ref (em_folder_tree_model_get_default (priv->backend));
dialog = em_folder_selector_new (
parent, priv->backend, model,
diff --git a/mail/em-folder-tree-model.c b/mail/em-folder-tree-model.c
index eb26ad5fff..2116faf854 100644
--- a/mail/em-folder-tree-model.c
+++ b/mail/em-folder-tree-model.c
@@ -69,6 +69,7 @@ struct _EMFolderTreeModelPrivate {
EAccountList *accounts;
EMailSession *session;
+ EMailBackend *backend;
/* CamelStore -> EMFolderTreeStoreInfo */
GHashTable *store_index;
@@ -84,7 +85,8 @@ struct _EMFolderTreeModelPrivate {
enum {
PROP_0,
PROP_SELECTION,
- PROP_SESSION
+ PROP_SESSION,
+ PROP_BACKEND
};
enum {
@@ -124,55 +126,69 @@ folder_tree_model_sort (GtkTreeModel *model,
GtkTreeIter *b,
gpointer user_data)
{
- EShell *shell;
+ EShell *shell = user_data;
gchar *aname, *bname;
CamelStore *store;
gboolean is_store;
guint32 aflags, bflags;
+ guint asortorder, bsortorder;
gint rv = -2;
- /* XXX Pass the EShell in as user_data. */
- shell = e_shell_get_default ();
-
gtk_tree_model_get (
model, a,
COL_BOOL_IS_STORE, &is_store,
COL_POINTER_CAMEL_STORE, &store,
COL_STRING_DISPLAY_NAME, &aname,
- COL_UINT_FLAGS, &aflags, -1);
+ COL_UINT_FLAGS, &aflags,
+ COL_UINT_SORTORDER, &asortorder,
+ -1);
gtk_tree_model_get (
model, b,
COL_STRING_DISPLAY_NAME, &bname,
- COL_UINT_FLAGS, &bflags, -1);
+ COL_UINT_FLAGS, &bflags,
+ COL_UINT_SORTORDER, &bsortorder,
+ -1);
if (is_store) {
- /* On This Computer is always first, and Search Folders
- * is always last. */
- if (e_shell_get_express_mode (shell)) {
- if (!strcmp (aname, _("On This Computer")) &&
- !strcmp (bname, _("Search Folders")))
- rv = -1;
- else if (!strcmp (bname, _("On This Computer")) &&
- !strcmp (aname, _("Search Folders")))
- rv = 1;
- else if (!strcmp (aname, _("On This Computer")))
- rv = 1;
- else if (!strcmp (bname, _("On This Computer")))
- rv = -1;
- else if (!strcmp (aname, _("Search Folders")))
- rv = 1;
- else if (!strcmp (bname, _("Search Folders")))
- rv = -1;
- } else {
- if (!strcmp (aname, _("On This Computer")))
+ if (e_shell_settings_get_boolean (e_shell_get_shell_settings (shell), "mail-sort-accounts-alpha")) {
+ const gchar *on_this_computer = _("On This Computer");
+ const gchar *search_folders = _("Search Folders");
+
+ /* On This Computer is always first, and Search Folders
+ * is always last. */
+ if (e_shell_get_express_mode (shell)) {
+ if (g_str_equal (aname, on_this_computer) &&
+ g_str_equal (bname, search_folders))
+ rv = -1;
+ else if (g_str_equal (bname, on_this_computer) &&
+ g_str_equal (aname, search_folders))
+ rv = 1;
+ else if (g_str_equal (aname, on_this_computer))
+ rv = 1;
+ else if (g_str_equal (bname, on_this_computer))
+ rv = -1;
+ else if (g_str_equal (aname, search_folders))
+ rv = 1;
+ else if (g_str_equal (bname, search_folders))
+ rv = -1;
+ } else {
+ if (g_str_equal (aname, on_this_computer))
+ rv = -1;
+ else if (g_str_equal (bname, on_this_computer))
+ rv = 1;
+ else if (g_str_equal (aname, search_folders))
+ rv = 1;
+ else if (g_str_equal (bname, search_folders))
+ rv = -1;
+ }
+ } else if (asortorder || bsortorder) {
+ if (asortorder < bsortorder)
rv = -1;
- else if (!strcmp (bname, _("On This Computer")))
- rv = 1;
- else if (!strcmp (aname, _("Search Folders")))
+ else if (asortorder > bsortorder)
rv = 1;
- else if (!strcmp (bname, _("Search Folders")))
- rv = -1;
+ else
+ rv = 0;
}
} else if (store == vfolder_store) {
/* UNMATCHED is always last. */
@@ -191,6 +207,8 @@ folder_tree_model_sort (GtkTreeModel *model,
if (aname == NULL) {
if (bname == NULL)
rv = 0;
+ else
+ rv = -1;
} else if (bname == NULL)
rv = 1;
@@ -260,6 +278,106 @@ account_added_cb (EAccountList *accounts,
}
static void
+folder_tree_model_sort_changed (EMFolderTreeModel *tree_model)
+{
+ GtkTreeModel *model;
+ EShellBackend *shell_backend;
+
+ g_return_if_fail (tree_model != NULL);
+ g_return_if_fail (EM_IS_FOLDER_TREE_MODEL (tree_model));
+
+ model = GTK_TREE_MODEL (tree_model);
+ if (!model)
+ return;
+
+ shell_backend = E_SHELL_BACKEND (em_folder_tree_model_get_backend (tree_model));
+
+ /* this invokes also sort on a GtkTreeStore */
+ gtk_tree_sortable_set_default_sort_func (
+ GTK_TREE_SORTABLE (model),
+ folder_tree_model_sort, e_shell_backend_get_shell (shell_backend), NULL);
+}
+
+static void
+account_sort_order_changed_cb (EMFolderTreeModel *folder_tree_model)
+{
+ EMailBackend *mail_backend;
+ GtkTreeModel *model;
+ GtkTreeStore *tree_store;
+ GtkTreeIter iter;
+
+ g_return_if_fail (folder_tree_model != NULL);
+
+ model = GTK_TREE_MODEL (folder_tree_model);
+ g_return_if_fail (model != NULL);
+
+ tree_store = GTK_TREE_STORE (folder_tree_model);
+ g_return_if_fail (tree_store != NULL);
+
+ if (!gtk_tree_model_get_iter_first (model, &iter))
+ return;
+
+ mail_backend = em_folder_tree_model_get_backend (folder_tree_model);
+
+ do {
+ CamelStore *store = NULL;
+
+ gtk_tree_model_get (model, &iter, COL_POINTER_CAMEL_STORE, &store, -1);
+
+ if (store) {
+ const gchar *account_uid;
+ guint sortorder;
+
+ account_uid = camel_service_get_uid (CAMEL_SERVICE (store));
+ sortorder = em_utils_get_account_sort_order (mail_backend, account_uid);
+
+ gtk_tree_store_set (tree_store, &iter, COL_UINT_SORTORDER, sortorder, -1);
+ }
+ } while (gtk_tree_model_iter_next (model, &iter));
+
+ folder_tree_model_sort_changed (folder_tree_model);
+}
+
+static void
+add_remove_special_folder (EMFolderTreeModel *model, const gchar *account_uid, gboolean add)
+{
+ EMailSession *session;
+ CamelService *service;
+
+ session = em_folder_tree_model_get_session (model);
+
+ service = camel_session_get_service (CAMEL_SESSION (session), account_uid);
+
+ if (!CAMEL_IS_STORE (service))
+ return;
+
+ if (add)
+ em_folder_tree_model_add_store (model, CAMEL_STORE (service));
+ else
+ em_folder_tree_model_remove_store (model, CAMEL_STORE (service));
+}
+
+static void
+enable_local_folders_changed_cb (EMFolderTreeModel *model, GParamSpec *spec, EShellSettings *shell_settings)
+{
+ g_return_if_fail (model != NULL);
+ g_return_if_fail (shell_settings != NULL);
+
+ add_remove_special_folder (model, "local",
+ e_shell_settings_get_boolean (shell_settings, "mail-enable-local-folders"));
+}
+
+static void
+enable_search_folders_changed_cb (EMFolderTreeModel *model, GParamSpec *spec, EShellSettings *shell_settings)
+{
+ g_return_if_fail (model != NULL);
+ g_return_if_fail (shell_settings != NULL);
+
+ add_remove_special_folder (model, "vfolder",
+ e_shell_settings_get_boolean (shell_settings, "mail-enable-search-folders"));
+}
+
+static void
folder_tree_model_selection_finalized_cb (EMFolderTreeModel *model)
{
model->priv->selection = NULL;
@@ -285,6 +403,11 @@ folder_tree_model_set_property (GObject *object,
EM_FOLDER_TREE_MODEL (object),
g_value_get_object (value));
return;
+ case PROP_BACKEND:
+ em_folder_tree_model_set_backend (
+ EM_FOLDER_TREE_MODEL (object),
+ g_value_get_object (value));
+ return;
}
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -310,11 +433,74 @@ folder_tree_model_get_property (GObject *object,
em_folder_tree_model_get_session (
EM_FOLDER_TREE_MODEL (object)));
return;
+ case PROP_BACKEND:
+ g_value_set_object (
+ value,
+ em_folder_tree_model_get_backend (
+ EM_FOLDER_TREE_MODEL (object)));
+ return;
}
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
+
+static void
+folder_tree_model_constructed (GObject *object)
+{
+ EShell *shell;
+ EShellSettings *shell_settings;
+ EMFolderTreeModel *model;
+
+ GType col_types[] = {
+ G_TYPE_STRING, /* display name */
+ G_TYPE_POINTER, /* store object */
+ G_TYPE_STRING, /* full name */
+ G_TYPE_STRING, /* icon name */
+ G_TYPE_STRING, /* uri */
+ G_TYPE_UINT, /* unread count */
+ G_TYPE_UINT, /* flags */
+ G_TYPE_BOOLEAN, /* is a store node */
+ G_TYPE_BOOLEAN, /* is a folder node */
+ G_TYPE_BOOLEAN, /* has not-yet-loaded subfolders */
+ G_TYPE_UINT, /* last known unread count */
+ G_TYPE_BOOLEAN, /* folder is a draft folder */
+ G_TYPE_UINT /* user's sortorder */
+ };
+
+ model = EM_FOLDER_TREE_MODEL (object);
+ shell = e_shell_backend_get_shell (E_SHELL_BACKEND (model->priv->backend));
+ shell_settings = e_shell_get_shell_settings (shell);
+
+ gtk_tree_store_set_column_types (
+ GTK_TREE_STORE (model), NUM_COLUMNS, col_types);
+ gtk_tree_sortable_set_default_sort_func (
+ GTK_TREE_SORTABLE (model),
+ folder_tree_model_sort, shell, NULL);
+ gtk_tree_sortable_set_sort_column_id (
+ GTK_TREE_SORTABLE (model),
+ GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
+ GTK_SORT_ASCENDING);
+
+ model->priv->accounts = e_get_account_list ();
+ model->priv->account_changed_id = g_signal_connect (
+ model->priv->accounts, "account-changed",
+ G_CALLBACK (account_changed_cb), model);
+ model->priv->account_removed_id = g_signal_connect (
+ model->priv->accounts, "account-removed",
+ G_CALLBACK (account_removed_cb), model);
+ model->priv->account_added_id = g_signal_connect (
+ model->priv->accounts, "account-added",
+ G_CALLBACK (account_added_cb), model);
+
+ g_signal_connect_swapped (model->priv->backend, "account-sort-order-changed", G_CALLBACK (account_sort_order_changed_cb), model);
+ g_signal_connect_swapped (shell_settings, "notify::mail-sort-accounts-alpha", G_CALLBACK (account_sort_order_changed_cb), model);
+ g_signal_connect_swapped (shell_settings, "notify::mail-enable-local-folders", G_CALLBACK (enable_local_folders_changed_cb), model);
+ g_signal_connect_swapped (shell_settings, "notify::mail-enable-search-folders", G_CALLBACK (enable_search_folders_changed_cb), model);
+
+ G_OBJECT_CLASS (parent_class)->constructed (object);
+}
+
static void
folder_tree_model_dispose (GObject *object)
{
@@ -334,6 +520,24 @@ folder_tree_model_dispose (GObject *object)
priv->session = NULL;
}
+ if (priv->backend) {
+ EShell *shell;
+ EShellSettings *shell_settings;
+ EMFolderTreeModel *model;
+
+ model = EM_FOLDER_TREE_MODEL (object);
+ shell = e_shell_backend_get_shell (E_SHELL_BACKEND (priv->backend));
+ shell_settings = e_shell_get_shell_settings (shell);
+
+ g_signal_handlers_disconnect_by_func (priv->backend, G_CALLBACK (account_sort_order_changed_cb), model);
+ g_signal_handlers_disconnect_by_func (shell_settings, G_CALLBACK (account_sort_order_changed_cb), model);
+ g_signal_handlers_disconnect_by_func (shell_settings, G_CALLBACK (enable_local_folders_changed_cb), model);
+ g_signal_handlers_disconnect_by_func (shell_settings, G_CALLBACK (enable_search_folders_changed_cb), model);
+
+ g_object_unref (priv->backend);
+ priv->backend = NULL;
+ }
+
/* Chain up to parent's dispose() method. */
G_OBJECT_CLASS (parent_class)->dispose (object);
}
@@ -370,6 +574,7 @@ em_folder_tree_model_class_init (EMFolderTreeModelClass *class)
object_class = G_OBJECT_CLASS (class);
object_class->set_property = folder_tree_model_set_property;
object_class->get_property = folder_tree_model_get_property;
+ object_class->constructed = folder_tree_model_constructed;
object_class->dispose = folder_tree_model_dispose;
object_class->finalize = folder_tree_model_finalize;
@@ -393,6 +598,16 @@ em_folder_tree_model_class_init (EMFolderTreeModelClass *class)
E_TYPE_MAIL_SESSION,
G_PARAM_READWRITE));
+ g_object_class_install_property (
+ object_class,
+ PROP_BACKEND,
+ g_param_spec_object (
+ "backend",
+ NULL,
+ NULL,
+ E_TYPE_MAIL_BACKEND,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
signals[LOADING_ROW] = g_signal_new (
"loading-row",
G_OBJECT_CLASS_TYPE (object_class),
@@ -477,21 +692,6 @@ em_folder_tree_model_init (EMFolderTreeModel *model)
GHashTable *store_index;
GHashTable *uri_index;
- GType col_types[] = {
- G_TYPE_STRING, /* display name */
- G_TYPE_POINTER, /* store object */
- G_TYPE_STRING, /* full name */
- G_TYPE_STRING, /* icon name */
- G_TYPE_STRING, /* uri */
- G_TYPE_UINT, /* unread count */
- G_TYPE_UINT, /* flags */
- G_TYPE_BOOLEAN, /* is a store node */
- G_TYPE_BOOLEAN, /* is a folder node */
- G_TYPE_BOOLEAN, /* has not-yet-loaded subfolders */
- G_TYPE_UINT, /* last known unread count */
- G_TYPE_BOOLEAN /* folder is a draft folder */
- };
-
store_index = g_hash_table_new_full (
g_direct_hash, g_direct_equal,
(GDestroyNotify) NULL,
@@ -505,42 +705,29 @@ em_folder_tree_model_init (EMFolderTreeModel *model)
model->priv = EM_FOLDER_TREE_MODEL_GET_PRIVATE (model);
model->priv->store_index = store_index;
model->priv->uri_index = uri_index;
-
- gtk_tree_store_set_column_types (
- GTK_TREE_STORE (model), NUM_COLUMNS, col_types);
- gtk_tree_sortable_set_default_sort_func (
- GTK_TREE_SORTABLE (model),
- folder_tree_model_sort, NULL, NULL);
- gtk_tree_sortable_set_sort_column_id (
- GTK_TREE_SORTABLE (model),
- GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
- GTK_SORT_ASCENDING);
-
- model->priv->accounts = e_get_account_list ();
- model->priv->account_changed_id = g_signal_connect (
- model->priv->accounts, "account-changed",
- G_CALLBACK (account_changed_cb), model);
- model->priv->account_removed_id = g_signal_connect (
- model->priv->accounts, "account-removed",
- G_CALLBACK (account_removed_cb), model);
- model->priv->account_added_id = g_signal_connect (
- model->priv->accounts, "account-added",
- G_CALLBACK (account_added_cb), model);
}
EMFolderTreeModel *
-em_folder_tree_model_new (void)
+em_folder_tree_model_new (EMailBackend *mail_backend)
{
- return g_object_new (EM_TYPE_FOLDER_TREE_MODEL, NULL);
+ return g_object_new (EM_TYPE_FOLDER_TREE_MODEL, "backend", mail_backend, NULL);
}
EMFolderTreeModel *
-em_folder_tree_model_get_default (void)
+em_folder_tree_model_get_default (EMailBackend *mail_backend)
{
static EMFolderTreeModel *default_folder_tree_model;
- if (G_UNLIKELY (default_folder_tree_model == NULL))
- default_folder_tree_model = em_folder_tree_model_new ();
+ if (G_UNLIKELY (default_folder_tree_model == NULL)) {
+ if (!mail_backend) {
+ EShell *shell;
+
+ shell = e_shell_get_default ();
+ mail_backend = E_MAIL_BACKEND (e_shell_get_backend_by_name (shell, "mail"));
+ }
+
+ default_folder_tree_model = em_folder_tree_model_new (mail_backend);
+ }
return default_folder_tree_model;
}
@@ -620,6 +807,33 @@ em_folder_tree_model_set_session (EMFolderTreeModel *model,
g_object_notify (G_OBJECT (model), "session");
}
+EMailBackend *
+em_folder_tree_model_get_backend (EMFolderTreeModel *model)
+{
+ g_return_val_if_fail (EM_IS_FOLDER_TREE_MODEL (model), NULL);
+
+ return model->priv->backend;
+}
+
+void
+em_folder_tree_model_set_backend (EMFolderTreeModel *model,
+ EMailBackend *backend)
+{
+ g_return_if_fail (EM_IS_FOLDER_TREE_MODEL (model));
+
+ if (backend != NULL) {
+ g_return_if_fail (E_IS_MAIL_BACKEND (backend));
+ g_object_ref (backend);
+ }
+
+ if (model->priv->backend != NULL)
+ g_object_unref (model->priv->backend);
+
+ model->priv->backend = backend;
+
+ g_object_notify (G_OBJECT (model), "backend");
+}
+
void
em_folder_tree_model_set_folder_info (EMFolderTreeModel *model,
GtkTreeIter *iter,
@@ -1002,6 +1216,7 @@ void
em_folder_tree_model_add_store (EMFolderTreeModel *model,
CamelStore *store)
{
+ EMailBackend *mail_backend;
EMFolderTreeModelStoreInfo *si;
GtkTreeRowReference *reference;
GtkTreeStore *tree_store;
@@ -1011,6 +1226,7 @@ em_folder_tree_model_add_store (EMFolderTreeModel *model,
CamelProvider *provider;
CamelURL *service_url;
const gchar *display_name;
+ const gchar *account_uid;
gchar *uri;
g_return_if_fail (EM_IS_FOLDER_TREE_MODEL (model));
@@ -1022,6 +1238,7 @@ em_folder_tree_model_add_store (EMFolderTreeModel *model,
provider = camel_service_get_provider (service);
service_url = camel_service_get_camel_url (service);
display_name = camel_service_get_display_name (service);
+ account_uid = camel_service_get_uid (service);
/* Ignore stores that should not be added to the tree model. */
@@ -1040,6 +1257,8 @@ em_folder_tree_model_add_store (EMFolderTreeModel *model,
uri = camel_url_to_string (service_url, CAMEL_URL_HIDE_ALL);
+ mail_backend = em_folder_tree_model_get_backend (model);
+
/* Add the store to the tree. */
gtk_tree_store_append (tree_store, &iter, NULL);
gtk_tree_store_set (
@@ -1049,7 +1268,9 @@ em_folder_tree_model_add_store (EMFolderTreeModel *model,
COL_STRING_FULL_NAME, NULL,
COL_BOOL_LOAD_SUBDIRS, TRUE,
COL_BOOL_IS_STORE, TRUE,
- COL_STRING_URI, uri, -1);
+ COL_STRING_URI, uri,
+ COL_UINT_SORTORDER, em_utils_get_account_sort_order (mail_backend, account_uid),
+ -1);
path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter);
reference = gtk_tree_row_reference_new (GTK_TREE_MODEL (model), path);
diff --git a/mail/em-folder-tree-model.h b/mail/em-folder-tree-model.h
index 1bf5483367..3765cfea11 100644
--- a/mail/em-folder-tree-model.h
+++ b/mail/em-folder-tree-model.h
@@ -26,6 +26,7 @@
#include <gtk/gtk.h>
#include <camel/camel.h>
+#include <mail/e-mail-backend.h>
#include <mail/e-mail-session.h>
/* Standard GObject macros */
@@ -72,6 +73,7 @@ enum {
* been added to the tree */
COL_UINT_UNREAD_LAST_SEL, /* last known unread count */
COL_BOOL_IS_DRAFT, /* %TRUE for a draft folder */
+ COL_UINT_SORTORDER, /* user sort-order for the node */
NUM_COLUMNS
};
@@ -109,9 +111,9 @@ struct _EMFolderTreeModelClass {
GType em_folder_tree_model_get_type (void);
EMFolderTreeModel *
- em_folder_tree_model_new (void);
+ em_folder_tree_model_new (EMailBackend *mail_backend);
EMFolderTreeModel *
- em_folder_tree_model_get_default (void);
+ em_folder_tree_model_get_default (EMailBackend *mail_backend);
GtkTreeSelection *
em_folder_tree_model_get_selection
(EMFolderTreeModel *model);
@@ -123,6 +125,11 @@ EMailSession * em_folder_tree_model_get_session
void em_folder_tree_model_set_session
(EMFolderTreeModel *model,
EMailSession *session);
+EMailBackend * em_folder_tree_model_get_backend
+ (EMFolderTreeModel *model);
+void em_folder_tree_model_set_backend
+ (EMFolderTreeModel *model,
+ EMailBackend *backend);
void em_folder_tree_model_set_folder_info
(EMFolderTreeModel *model,
GtkTreeIter *iter,
diff --git a/mail/em-folder-tree.c b/mail/em-folder-tree.c
index 061c3540f7..6212f8a8ca 100644
--- a/mail/em-folder-tree.c
+++ b/mail/em-folder-tree.c
@@ -1770,7 +1770,7 @@ em_folder_tree_new (EMailBackend *backend,
g_return_val_if_fail (E_IS_MAIL_BACKEND (backend), NULL);
g_return_val_if_fail (E_IS_ALERT_SINK (alert_sink), NULL);
- model = em_folder_tree_model_get_default ();
+ model = em_folder_tree_model_get_default (backend);
return em_folder_tree_new_with_model (backend, alert_sink, model);
}
diff --git a/mail/em-folder-utils.c b/mail/em-folder-utils.c
index 775dfbb663..54586ad763 100644
--- a/mail/em-folder-utils.c
+++ b/mail/em-folder-utils.c
@@ -487,7 +487,7 @@ em_folder_utils_copy_folder (GtkWindow *parent,
label = delete ? _("_Move") : _("C_opy");
title = delete ? _("Move Folder To") : _("Copy Folder To");
- model = em_folder_tree_model_get_default ();
+ model = em_folder_tree_model_get_default (backend);
dialog = em_folder_selector_new (
parent, backend, model,
@@ -547,6 +547,8 @@ em_folder_utils_create_folder (GtkWindow *parent,
EMFolderTree *emft,
const gchar *initial_uri)
{
+ EShell *shell;
+ EShellSettings *shell_settings;
EMailSession *session;
EMFolderSelector *selector;
EMFolderTree *folder_tree;
@@ -560,7 +562,10 @@ em_folder_utils_create_folder (GtkWindow *parent,
g_return_if_fail (GTK_IS_WINDOW (parent));
g_return_if_fail (E_IS_MAIL_BACKEND (backend));
- model = em_folder_tree_model_new ();
+ shell = e_shell_backend_get_shell (E_SHELL_BACKEND (backend));
+ shell_settings = e_shell_get_shell_settings (shell);
+
+ model = em_folder_tree_model_new (backend);
session = e_mail_backend_get_session (backend);
em_folder_tree_model_set_session (model, session);
@@ -569,6 +574,7 @@ em_folder_utils_create_folder (GtkWindow *parent,
for (link = list; link != NULL; link = g_list_next (link)) {
CamelService *service;
CamelStore *store;
+ const gchar *uid, *prop = NULL;
service = CAMEL_SERVICE (link->data);
@@ -580,6 +586,15 @@ em_folder_utils_create_folder (GtkWindow *parent,
if ((store->flags & CAMEL_STORE_CAN_EDIT_FOLDERS) == 0)
continue;
+ uid = camel_service_get_uid (service);
+ if (g_strcmp0 (uid, "local") == 0)
+ prop = "mail-enable-local-folders";
+ else if (g_strcmp0 (uid, "vfolder") == 0)
+ prop = "mail-enable-search-folders";
+
+ if (prop && !e_shell_settings_get_boolean (shell_settings, prop))
+ continue;
+
em_folder_tree_model_add_store (model, store);
}
diff --git a/mail/em-subscription-editor.c b/mail/em-subscription-editor.c
index e2452d70bf..2dca93b51a 100644
--- a/mail/em-subscription-editor.c
+++ b/mail/em-subscription-editor.c
@@ -1077,7 +1077,7 @@ subscription_editor_realize (GtkWidget *widget)
/* Find stores to display, and watch for the initial store. */
- model = em_folder_tree_model_get_default ();
+ model = em_folder_tree_model_get_default (NULL);
list = em_folder_tree_model_list_stores (model);
for (link = list; link != NULL; link = g_list_next (link)) {
diff --git a/mail/em-utils.c b/mail/em-utils.c
index 968165385a..5ff93887a2 100644
--- a/mail/em-utils.c
+++ b/mail/em-utils.c
@@ -84,6 +84,8 @@ extern const gchar *shell_builtin_backend;
#define d(x)
+static void free_account_sort_order_cache (void);
+
gboolean
em_utils_ask_open_many (GtkWindow *parent,
gint how_many)
@@ -2014,6 +2016,8 @@ emu_free_mail_cache (void)
photos_cache = NULL;
G_UNLOCK (photos_cache);
+
+ free_account_sort_order_cache ();
}
void
@@ -2369,3 +2373,167 @@ em_utils_disconnect_service_sync (CamelService *service,
return res;
}
+
+G_LOCK_DEFINE_STATIC (accounts_sort_order_cache);
+static GHashTable *accounts_sort_order_cache = NULL; /* account_uid string to sort order uint */
+
+static void
+free_account_sort_order_cache (void)
+{
+ G_LOCK (accounts_sort_order_cache);
+
+ if (accounts_sort_order_cache) {
+ g_hash_table_destroy (accounts_sort_order_cache);
+ accounts_sort_order_cache = NULL;
+ }
+
+ G_UNLOCK (accounts_sort_order_cache);
+}
+
+static void
+fill_accounts_sort_order_cache (EMailBackend *backend, gboolean force_reload)
+{
+ GSList *account_uids;
+
+ G_LOCK (accounts_sort_order_cache);
+
+ if (!force_reload && accounts_sort_order_cache) {
+ G_UNLOCK (accounts_sort_order_cache);
+ return;
+ }
+
+ if (!accounts_sort_order_cache)
+ accounts_sort_order_cache = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+ else
+ g_hash_table_remove_all (accounts_sort_order_cache);
+
+ account_uids = em_utils_load_accounts_sort_order (backend);
+ if (account_uids) {
+ GSList *iter;
+ guint index;
+
+ for (index = 1, iter = account_uids; iter; index++, iter = iter->next) {
+ if (iter->data)
+ g_hash_table_insert (accounts_sort_order_cache, iter->data, GUINT_TO_POINTER (index));
+ }
+
+ /* items are stolen into the cache */
+ /* g_slist_foreach (account_uids, (GFunc) g_free, NULL); */
+ g_slist_free (account_uids);
+ }
+
+ G_UNLOCK (accounts_sort_order_cache);
+}
+
+static gchar *
+emu_get_sort_order_filename (EMailBackend *backend)
+{
+ g_return_val_if_fail (backend != NULL, NULL);
+
+ return g_build_filename (
+ e_shell_backend_get_config_dir (E_SHELL_BACKEND (backend)),
+ "sortorder.ini", NULL);
+}
+
+static GKeyFile *
+emu_get_sort_order_key_file (EMailBackend *backend)
+{
+ gchar *filename;
+ GKeyFile *key_file;
+
+ g_return_val_if_fail (backend != NULL, NULL);
+
+ filename = emu_get_sort_order_filename (backend);
+ g_return_val_if_fail (filename != NULL, NULL);
+
+ key_file = g_key_file_new ();
+ g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, NULL);
+
+ g_free (filename);
+
+ return key_file;
+}
+
+void
+em_utils_save_accounts_sort_order (EMailBackend *backend, const GSList *account_uids)
+{
+ gchar *filename;
+ GKeyFile *key_file;
+ gint ii;
+ gchar key[32];
+ gchar *content;
+ gsize length = 0;
+
+ key_file = emu_get_sort_order_key_file (backend);
+ g_return_if_fail (key_file != NULL);
+
+ filename = emu_get_sort_order_filename (backend);
+ g_return_if_fail (filename != NULL);
+
+ g_key_file_remove_group (key_file, "accounts", NULL);
+
+ for (ii = 0; account_uids; ii++, account_uids = account_uids->next) {
+ sprintf (key, "%d", ii);
+
+ g_key_file_set_string (key_file, "accounts", key, account_uids->data);
+ }
+
+ content = g_key_file_to_data (key_file, &length, NULL);
+ if (content)
+ g_file_set_contents (filename, content, length, NULL);
+
+ g_free (content);
+ g_free (filename);
+ g_key_file_free (key_file);
+
+ fill_accounts_sort_order_cache (backend, TRUE);
+ e_mail_backend_account_sort_order_changed (backend);
+}
+
+GSList *
+em_utils_load_accounts_sort_order (EMailBackend *backend)
+{
+ GKeyFile *key_file;
+ GSList *account_uids = NULL;
+ gchar key[32];
+ gchar *value;
+ gint ii;
+
+ key_file = emu_get_sort_order_key_file (backend);
+ g_return_val_if_fail (key_file != NULL, NULL);
+
+ ii = 0;
+ do {
+ sprintf (key, "%d", ii);
+ ii++;
+
+ value = g_key_file_get_string (key_file, "accounts", key, NULL);
+ if (!value)
+ break;
+
+ account_uids = g_slist_prepend (account_uids, value);
+ } while (*key);
+
+ g_key_file_free (key_file);
+
+ return g_slist_reverse (account_uids);
+}
+
+guint
+em_utils_get_account_sort_order (EMailBackend *backend, const gchar *account_uid)
+{
+ guint res;
+
+ g_return_val_if_fail (backend != NULL, 0);
+ g_return_val_if_fail (account_uid != NULL, 0);
+
+ fill_accounts_sort_order_cache (backend, FALSE);
+
+ G_LOCK (accounts_sort_order_cache);
+
+ res = GPOINTER_TO_UINT (g_hash_table_lookup (accounts_sort_order_cache, account_uid));
+
+ G_UNLOCK (accounts_sort_order_cache);
+
+ return res;
+}
diff --git a/mail/em-utils.h b/mail/em-utils.h
index e8ffd190d6..e6ebe8ca4b 100644
--- a/mail/em-utils.h
+++ b/mail/em-utils.h
@@ -99,6 +99,10 @@ gboolean em_utils_is_local_delivery_mbox_file (CamelURL *url);
gboolean em_utils_connect_service_sync (CamelService *service, GCancellable *cancellable, GError **error);
gboolean em_utils_disconnect_service_sync (CamelService *service, gboolean clean, GCancellable *cancellable, GError **error);
+void em_utils_save_accounts_sort_order (EMailBackend *backend, const GSList *account_uids);
+GSList *em_utils_load_accounts_sort_order (EMailBackend *backend);
+guint em_utils_get_account_sort_order (EMailBackend *backend, const gchar *account_uid);
+
G_END_DECLS
#endif /* __EM_UTILS_H__ */
diff --git a/mail/em-vfolder-rule.c b/mail/em-vfolder-rule.c
index be18f2c248..fbb711738f 100644
--- a/mail/em-vfolder-rule.c
+++ b/mail/em-vfolder-rule.c
@@ -610,7 +610,7 @@ source_add (GtkWidget *widget,
backend = em_vfolder_rule_get_backend (data->vr);
- model = em_folder_tree_model_get_default ();
+ model = em_folder_tree_model_get_default (backend);
dialog = em_folder_selector_new (
parent, backend, model,
diff --git a/mail/evolution-mail.schemas.in b/mail/evolution-mail.schemas.in
index f1dcd73ea6..82be1319c8 100644
--- a/mail/evolution-mail.schemas.in
+++ b/mail/evolution-mail.schemas.in
@@ -678,6 +678,20 @@
</schema>
<schema>
+ <key>/schemas/apps/evolution/mail/display/enable_local</key>
+ <applyto>/apps/evolution/mail/display/enable_local</applyto>
+ <owner>evolution-mail</owner>
+ <type>bool</type>
+ <default>true</default>
+ <locale name="C">
+ <short>Enable local folders</short>
+ <long>
+ Whether to show local folders (On This Computer) in a folder tree.
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
<key>/schemas/apps/evolution/mail/display/safe_list</key>
<applyto>/apps/evolution/mail/display/safe_list</applyto>
<owner>evolution-mail</owner>
@@ -885,7 +899,7 @@
</long>
</locale>
</schema>
-
+
<schema>
<key>/schemas/apps/evolution/mail/display/paned_view_headers_state</key>
<applyto>/apps/evolution/mail/display/paned_view_headers_state</applyto>
@@ -901,7 +915,24 @@
</long>
</locale>
</schema>
-
+
+ <schema>
+ <key>/schemas/apps/evolution/mail/display/sort_accounts_alpha</key>
+ <applyto>/apps/evolution/mail/display/sort_accounts_alpha</applyto>
+ <owner>evolution-mail</owner>
+ <type>bool</type>
+ <default>true</default>
+ <locale name="C">
+ <short>Sort accounts alphabetically in a folder tree</short>
+ <long>
+ Tells how to sort accounts in a folder tree used in a Mail view.
+ When set to true accounts are sorted alphabetically, with an exception
+ of On This Computer and Search folders, otherwise accounts are
+ sorted based on an order given by a user.
+ </long>
+ </locale>
+ </schema>
+
<!-- Mail Browser -->
<schema>
diff --git a/mail/message-list.c b/mail/message-list.c
index d98f860f8c..cd44b9506a 100644
--- a/mail/message-list.c
+++ b/mail/message-list.c
@@ -4191,7 +4191,7 @@ on_click (ETree *tree,
if (col == COL_MESSAGE_STATUS && (flags & CAMEL_MESSAGE_SEEN)) {
EMFolderTreeModel *model;
- model = em_folder_tree_model_get_default ();
+ model = em_folder_tree_model_get_default (list->priv->backend);
em_folder_tree_model_user_marked_unread (
model, list->folder, 1);
}
diff --git a/modules/mail/e-mail-shell-settings.c b/modules/mail/e-mail-shell-settings.c
index 99402d5f29..b0d5f1eed8 100644
--- a/modules/mail/e-mail-shell-settings.c
+++ b/modules/mail/e-mail-shell-settings.c
@@ -142,6 +142,10 @@ e_mail_shell_settings_init (EShellBackend *shell_backend)
"/apps/evolution/mail/display/enable_vfolders");
e_shell_settings_install_property_for_key (
+ "mail-enable-local-folders",
+ "/apps/evolution/mail/display/enable_local");
+
+ e_shell_settings_install_property_for_key (
"mail-font-monospace",
"/apps/evolution/mail/display/fonts/monospace");
@@ -201,6 +205,10 @@ e_mail_shell_settings_init (EShellBackend *shell_backend)
"/apps/evolution/mail/display/show_real_date");
e_shell_settings_install_property_for_key (
+ "mail-sort-accounts-alpha",
+ "/apps/evolution/mail/display/sort_accounts_alpha");
+
+ e_shell_settings_install_property_for_key (
"mail-prompt-delete-in-vfolder",
"/apps/evolution/mail/prompts/delete_in_vfolder");
diff --git a/modules/mail/e-mail-shell-view.c b/modules/mail/e-mail-shell-view.c
index 5759b5830f..3a92ce284b 100644
--- a/modules/mail/e-mail-shell-view.c
+++ b/modules/mail/e-mail-shell-view.c
@@ -868,7 +868,7 @@ mail_shell_view_update_actions (EShellView *shell_view)
shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
state = e_shell_sidebar_check_state (shell_sidebar);
- model = em_folder_tree_model_get_default ();
+ model = em_folder_tree_model_get_default (e_mail_reader_get_backend (reader));
folder_allows_children =
(state & E_MAIL_SIDEBAR_FOLDER_ALLOWS_CHILDREN);
diff --git a/modules/mail/em-account-prefs.c b/modules/mail/em-account-prefs.c
index b43f1fbe35..1b11b41b68 100644
--- a/modules/mail/em-account-prefs.c
+++ b/modules/mail/em-account-prefs.c
@@ -40,6 +40,8 @@
#include "e-mail-store.h"
#include "em-config.h"
#include "em-account-editor.h"
+#include "em-utils.h"
+#include "mail-vfolder.h"
#include "shell/e-shell.h"
#include "capplet/settings/mail-capplet-shell.h"
@@ -59,6 +61,36 @@ G_DEFINE_TYPE (
em_account_prefs,
E_TYPE_ACCOUNT_MANAGER)
+static gboolean
+account_prefs_toggle_enable_special (EMAccountPrefs *prefs, EAccountTreeViewSelectedType type, gboolean enabled)
+{
+ const gchar *prop = NULL;
+ EShell *shell;
+ EShellSettings *shell_settings;
+
+ g_return_val_if_fail (prefs != NULL, FALSE);
+ g_return_val_if_fail (prefs->priv != NULL, FALSE);
+
+ if (type == E_ACCOUNT_TREE_VIEW_SELECTED_LOCAL)
+ prop = "mail-enable-local-folders";
+ else if (type == E_ACCOUNT_TREE_VIEW_SELECTED_VFOLDER)
+ prop = "mail-enable-search-folders";
+
+ if (!prop)
+ return FALSE;
+
+ shell = e_shell_backend_get_shell (E_SHELL_BACKEND (prefs->priv->backend));
+ shell_settings = e_shell_get_shell_settings (shell);
+
+ e_shell_settings_set_boolean (shell_settings, prop, enabled);
+
+ /* make sure "Search Folders" are loaded when enabled */
+ if (enabled && type == E_ACCOUNT_TREE_VIEW_SELECTED_VFOLDER)
+ vfolder_load_storage (prefs->priv->backend);
+
+ return TRUE;
+}
+
static void
account_prefs_enable_account_cb (EAccountTreeView *tree_view,
EMAccountPrefs *prefs)
@@ -67,6 +99,11 @@ account_prefs_enable_account_cb (EAccountTreeView *tree_view,
EMailSession *session;
account = e_account_tree_view_get_selected (tree_view);
+ if (!account) {
+ if (account_prefs_toggle_enable_special (prefs, e_account_tree_view_get_selected_type (tree_view), TRUE))
+ return;
+ }
+
g_return_if_fail (account != NULL);
session = e_mail_backend_get_session (prefs->priv->backend);
@@ -84,6 +121,11 @@ account_prefs_disable_account_cb (EAccountTreeView *tree_view,
gint response;
account = e_account_tree_view_get_selected (tree_view);
+ if (!account) {
+ if (account_prefs_toggle_enable_special (prefs, e_account_tree_view_get_selected_type (tree_view), FALSE))
+ return;
+ }
+
g_return_if_fail (account != NULL);
account_list = e_account_tree_view_get_account_list (tree_view);
@@ -380,14 +422,35 @@ em_account_prefs_init (EMAccountPrefs *prefs)
G_CALLBACK (account_prefs_disable_account_cb), prefs);
}
+static void
+account_tree_view_sort_order_changed_cb (EAccountTreeView *tree_view, EMailBackend *backend)
+{
+ GSList *account_uids;
+
+ g_return_if_fail (tree_view != NULL);
+ g_return_if_fail (backend != NULL);
+
+ account_uids = e_account_tree_view_get_sort_order (tree_view);
+ if (!account_uids)
+ return;
+
+ em_utils_save_accounts_sort_order (backend, account_uids);
+
+ g_slist_foreach (account_uids, (GFunc) g_free, NULL);
+ g_slist_free (account_uids);
+}
+
GtkWidget *
em_account_prefs_new (EPreferencesWindow *window)
{
EShell *shell;
EShellBackend *shell_backend;
EAccountList *account_list;
+ EAccountTreeView *tree_view;
EMailSession *session;
const gchar *data_dir;
+ GtkWidget *res;
+ GSList *account_uids;
account_list = e_get_account_list ();
g_return_val_if_fail (E_IS_ACCOUNT_LIST (account_list), NULL);
@@ -402,10 +465,40 @@ em_account_prefs_new (EPreferencesWindow *window)
/* Make sure the e-mail-local is initialized. */
e_mail_local_init (session, data_dir);
- return g_object_new (
+ res = g_object_new (
EM_TYPE_ACCOUNT_PREFS,
"account-list", account_list,
"backend", shell_backend, NULL);
+
+ tree_view = e_account_manager_get_tree_view (E_ACCOUNT_MANAGER (res));
+ e_account_tree_view_set_express_mode (tree_view, e_shell_get_express_mode (shell));
+
+ g_object_bind_property (
+ e_shell_get_shell_settings (shell), "mail-sort-accounts-alpha",
+ tree_view, "sort-alpha",
+ G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
+
+ g_object_bind_property (
+ e_shell_get_shell_settings (shell), "mail-enable-local-folders",
+ tree_view, "enable-local-folders",
+ G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
+
+ g_object_bind_property (
+ e_shell_get_shell_settings (shell), "mail-enable-search-folders",
+ tree_view, "enable-search-folders",
+ G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
+
+ account_uids = em_utils_load_accounts_sort_order (E_MAIL_BACKEND (shell_backend));
+ if (account_uids) {
+ e_account_tree_view_set_sort_order (tree_view, account_uids);
+ g_slist_foreach (account_uids, (GFunc) g_free, NULL);
+ g_slist_free (account_uids);
+ }
+
+ g_signal_connect (tree_view, "sort-order-changed",
+ G_CALLBACK (account_tree_view_sort_order_changed_cb), shell_backend);
+
+ return res;
}
EMailBackend *
diff --git a/plugins/mark-all-read/mark-all-read.c b/plugins/mark-all-read/mark-all-read.c
index 4fe19cf71b..ab8549495b 100644
--- a/plugins/mark-all-read/mark-all-read.c
+++ b/plugins/mark-all-read/mark-all-read.c
@@ -318,7 +318,7 @@ scan_folder_tree_for_unread_helper (GtkTreeModel *model,
}
static gint
-scan_folder_tree_for_unread (const gchar *folder_uri)
+scan_folder_tree_for_unread (EMailBackend *backend, const gchar *folder_uri)
{
GtkTreeRowReference *reference;
EMFolderTreeModel *model;
@@ -338,7 +338,7 @@ scan_folder_tree_for_unread (const gchar *folder_uri)
if (folder_uri == NULL)
return 0;
- model = em_folder_tree_model_get_default ();
+ model = em_folder_tree_model_get_default (backend);
reference = em_folder_tree_model_lookup_uri (model, folder_uri);
if (gtk_tree_row_reference_valid (reference)) {
@@ -602,7 +602,7 @@ update_actions_cb (EShellView *shell_view,
g_object_get (shell_sidebar, "folder-tree", &folder_tree, NULL);
folder_uri = em_folder_tree_get_selected_uri (folder_tree);
- visible = (scan_folder_tree_for_unread (folder_uri) > 0);
+ visible = (scan_folder_tree_for_unread (E_MAIL_BACKEND (e_shell_view_get_shell_backend (shell_view)), folder_uri) > 0);
gtk_action_set_visible (action, visible);
g_object_unref (folder_tree);
diff --git a/widgets/misc/e-account-manager.c b/widgets/misc/e-account-manager.c
index e4ee68736a..b2c0583b8b 100644
--- a/widgets/misc/e-account-manager.c
+++ b/widgets/misc/e-account-manager.c
@@ -37,6 +37,9 @@ struct _EAccountManagerPrivate {
GtkWidget *edit_button;
GtkWidget *delete_button;
GtkWidget *default_button;
+ GtkWidget *sort_toggle;
+ GtkWidget *sort_up_button;
+ GtkWidget *sort_down_button;
};
enum {
@@ -96,16 +99,22 @@ account_manager_selection_changed_cb (EAccountManager *manager,
EAccountList *account_list;
EAccount *default_account;
EAccount *account;
+ GtkTreeModel *model = NULL;
+ GtkTreeIter iter1, iter2;
GtkWidget *add_button;
GtkWidget *edit_button;
GtkWidget *delete_button;
GtkWidget *default_button;
+ GtkWidget *sort_up_button;
+ GtkWidget *sort_down_button;
gboolean sensitive;
add_button = manager->priv->add_button;
edit_button = manager->priv->edit_button;
delete_button = manager->priv->delete_button;
default_button = manager->priv->default_button;
+ sort_up_button = manager->priv->sort_up_button;
+ sort_down_button = manager->priv->sort_down_button;
tree_view = e_account_manager_get_tree_view (manager);
account = e_account_tree_view_get_selected (tree_view);
@@ -126,6 +135,50 @@ account_manager_selection_changed_cb (EAccountManager *manager,
sensitive = (account != NULL && account != default_account);
gtk_widget_set_sensitive (default_button, sensitive);
+
+ sensitive = !gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (manager->priv->sort_toggle)) &&
+ gtk_tree_selection_get_selected (selection, &model, &iter1);
+ iter2 = iter1;
+ gtk_widget_set_sensitive (sort_up_button, sensitive && gtk_tree_model_iter_previous (model, &iter1));
+ gtk_widget_set_sensitive (sort_down_button, sensitive && gtk_tree_model_iter_next (model, &iter2));
+}
+
+static void
+account_manager_sort_toggled_cb (EAccountManager *manager)
+{
+ GtkTreeView *tree_view;
+ GtkTreeSelection *selection;
+
+ tree_view = GTK_TREE_VIEW (e_account_manager_get_tree_view (manager));
+ selection = gtk_tree_view_get_selection (tree_view);
+
+ account_manager_selection_changed_cb (manager, selection);
+}
+
+static void
+account_manager_sort_up_cb (EAccountManager *manager)
+{
+ GtkTreeView *tree_view;
+ GtkTreeSelection *selection;
+
+ tree_view = GTK_TREE_VIEW (e_account_manager_get_tree_view (manager));
+ selection = gtk_tree_view_get_selection (tree_view);
+
+ e_account_tree_view_move_up (e_account_manager_get_tree_view (manager));
+ account_manager_selection_changed_cb (manager, selection);
+}
+
+static void
+account_manager_sort_down_cb (EAccountManager *manager)
+{
+ GtkTreeView *tree_view;
+ GtkTreeSelection *selection;
+
+ tree_view = GTK_TREE_VIEW (e_account_manager_get_tree_view (manager));
+ selection = gtk_tree_view_get_selection (tree_view);
+
+ e_account_tree_view_move_down (e_account_manager_get_tree_view (manager));
+ account_manager_selection_changed_cb (manager, selection);
}
static void
@@ -195,6 +248,21 @@ account_manager_dispose (GObject *object)
priv->delete_button = NULL;
}
+ if (priv->sort_toggle != NULL) {
+ g_object_unref (priv->sort_toggle);
+ priv->sort_toggle = NULL;
+ }
+
+ if (priv->sort_up_button != NULL) {
+ g_object_unref (priv->sort_up_button);
+ priv->sort_up_button = NULL;
+ }
+
+ if (priv->sort_down_button != NULL) {
+ g_object_unref (priv->sort_down_button);
+ priv->sort_down_button = NULL;
+ }
+
/* Chain up to parent's dispose() method. */
G_OBJECT_CLASS (e_account_manager_parent_class)->dispose (object);
}
@@ -312,6 +380,23 @@ e_account_manager_init (EAccountManager *manager)
container = GTK_WIDGET (manager);
+ widget = gtk_check_button_new_with_mnemonic (_("Use default Evolution _sort order for accounts"));
+ manager->priv->sort_toggle = g_object_ref (widget);
+ gtk_widget_show (widget);
+ gtk_table_attach (
+ GTK_TABLE (container), widget, 0, 1, 1, 2,
+ GTK_EXPAND | GTK_FILL, 0, 4, 0);
+
+ g_object_bind_property (
+ manager->priv->tree_view, "sort-alpha",
+ widget, "active",
+ G_BINDING_BIDIRECTIONAL |
+ G_BINDING_SYNC_CREATE);
+
+ g_signal_connect_swapped (
+ widget, "toggled",
+ G_CALLBACK (account_manager_sort_toggled_cb), manager);
+
widget = gtk_vbutton_box_new ();
gtk_button_box_set_layout (
GTK_BUTTON_BOX (widget), GTK_BUTTONBOX_START);
@@ -361,6 +446,24 @@ e_account_manager_init (EAccountManager *manager)
g_signal_connect_swapped (
widget, "clicked",
G_CALLBACK (account_manager_default_clicked_cb), manager);
+
+ widget = gtk_button_new_from_stock (GTK_STOCK_GO_UP);
+ gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
+ manager->priv->sort_up_button = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ g_signal_connect_swapped (
+ widget, "clicked",
+ G_CALLBACK (account_manager_sort_up_cb), manager);
+
+ widget = gtk_button_new_from_stock (GTK_STOCK_GO_DOWN);
+ gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
+ manager->priv->sort_down_button = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ g_signal_connect_swapped (
+ widget, "clicked",
+ G_CALLBACK (account_manager_sort_down_cb), manager);
}
GtkWidget *
diff --git a/widgets/misc/e-account-tree-view.c b/widgets/misc/e-account-tree-view.c
index 18c39dccec..a2136433d4 100644
--- a/widgets/misc/e-account-tree-view.c
+++ b/widgets/misc/e-account-tree-view.c
@@ -33,25 +33,35 @@ enum {
COLUMN_DEFAULT,
COLUMN_ENABLED,
COLUMN_NAME,
- COLUMN_PROTOCOL
+ COLUMN_PROTOCOL,
+ COLUMN_SORTORDER
};
enum {
PROP_0,
PROP_ACCOUNT_LIST,
- PROP_SELECTED
+ PROP_SELECTED,
+ PROP_SORT_ALPHA,
+ PROP_EXPRESS_MODE,
+ PROP_ENABLE_LOCAL_FOLDERS,
+ PROP_ENABLE_SEARCH_FOLDERS
};
enum {
ENABLE_ACCOUNT,
DISABLE_ACCOUNT,
REFRESHED,
+ SORT_ORDER_CHANGED,
LAST_SIGNAL
};
struct _EAccountTreeViewPrivate {
EAccountList *account_list;
GHashTable *index;
+ gboolean sort_alpha;
+ gboolean express_mode;
+ gboolean enable_local_folders;
+ gboolean enable_search_folders;
};
static guint signals[LAST_SIGNAL];
@@ -61,10 +71,124 @@ G_DEFINE_TYPE (
e_account_tree_view,
GTK_TYPE_TREE_VIEW)
+static gint
+account_tree_view_sort (GtkTreeModel *model,
+ GtkTreeIter *a,
+ GtkTreeIter *b,
+ gpointer user_data)
+{
+ gint rv = -2;
+ gchar *aname = NULL, *bname = NULL;
+ EAccount *aaccount = NULL, *baccount = NULL;
+ guint asortorder = 0, bsortorder = 0;
+
+ gtk_tree_model_get (model, a,
+ COLUMN_ACCOUNT, &aaccount,
+ COLUMN_NAME, &aname,
+ COLUMN_SORTORDER, &asortorder,
+ -1);
+
+ gtk_tree_model_get (model, b,
+ COLUMN_ACCOUNT, &baccount,
+ COLUMN_NAME, &bname,
+ COLUMN_SORTORDER, &bsortorder,
+ -1);
+
+ if ((!aaccount || !baccount || !e_account_tree_view_get_sort_alpha (user_data)) && aname && bname) {
+ if (e_account_tree_view_get_sort_alpha (user_data)) {
+ const gchar *on_this_computer = _("On This Computer");
+ const gchar *search_folders = _("Search Folders");
+
+ if (e_account_tree_view_get_express_mode (user_data)) {
+ if (g_str_equal (aname, on_this_computer) &&
+ g_str_equal (bname, search_folders))
+ rv = -1;
+ else if (g_str_equal (bname, on_this_computer) &&
+ g_str_equal (aname, search_folders))
+ rv = 1;
+ else if (g_str_equal (aname, on_this_computer))
+ rv = 1;
+ else if (g_str_equal (bname, on_this_computer))
+ rv = -1;
+ else if (g_str_equal (aname, search_folders))
+ rv = 1;
+ else if (g_str_equal (bname, search_folders))
+ rv = -1;
+ } else {
+ if (g_str_equal (aname, on_this_computer))
+ rv = -1;
+ else if (g_str_equal (bname, on_this_computer))
+ rv = 1;
+ else if (g_str_equal (aname, search_folders))
+ rv = 1;
+ else if (g_str_equal (bname, search_folders))
+ rv = -1;
+ }
+ } else {
+ if (asortorder < bsortorder)
+ rv = -1;
+ else if (asortorder > bsortorder)
+ rv = 1;
+ else
+ rv = 0;
+ }
+ }
+
+ if (rv == -2) {
+ if (aname == NULL) {
+ if (bname == NULL)
+ rv = 0;
+ else
+ rv = -1;
+ } else if (bname == NULL)
+ rv = 1;
+
+ if (rv == -2)
+ rv = g_utf8_collate (aname, bname);
+ }
+
+ g_free (aname);
+ g_free (bname);
+
+ if (aaccount)
+ g_object_unref (aaccount);
+ if (baccount)
+ g_object_unref (baccount);
+
+ return rv;
+}
+
+static void
+account_tree_view_normalize_sortorder_column (EAccountTreeView *tree_view)
+{
+ GtkListStore *list_store;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ guint index;
+
+ g_return_if_fail (tree_view != NULL);
+ g_return_if_fail (E_IS_ACCOUNT_TREE_VIEW (tree_view));
+
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_view));
+ if (!model || !gtk_tree_model_get_iter_first (model, &iter))
+ return;
+
+ list_store = GTK_LIST_STORE (model);
+ g_return_if_fail (list_store != NULL);
+
+ index = 1;
+ do {
+ gtk_list_store_set (list_store, &iter, COLUMN_SORTORDER, index, -1);
+
+ index++;
+ } while (gtk_tree_model_iter_next (model, &iter));
+}
+
static gboolean
account_tree_view_refresh_timeout_cb (gpointer ptree_view)
{
EAccountTreeView *tree_view;
+ EAccountTreeViewSelectedType selected;
EAccountList *account_list;
EAccount *account;
GtkListStore *store;
@@ -73,18 +197,28 @@ account_tree_view_refresh_timeout_cb (gpointer ptree_view)
EIterator *account_iter;
EAccount *default_account;
GHashTable *index;
+ GSList *sort_order;
GList *list = NULL;
GList *iter;
tree_view = ptree_view;
account_list = e_account_tree_view_get_account_list (tree_view);
+ sort_order = e_account_tree_view_get_sort_order (tree_view);
store = gtk_list_store_new (
- 5, E_TYPE_ACCOUNT, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
- G_TYPE_STRING, G_TYPE_STRING);
+ 6, E_TYPE_ACCOUNT, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
+ G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT);
model = GTK_TREE_MODEL (store);
index = tree_view->priv->index;
+ gtk_tree_sortable_set_default_sort_func (
+ GTK_TREE_SORTABLE (model),
+ account_tree_view_sort, tree_view, NULL);
+ gtk_tree_sortable_set_sort_column_id (
+ GTK_TREE_SORTABLE (model),
+ GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
+ GTK_SORT_ASCENDING);
+
g_hash_table_remove_all (index);
if (account_list == NULL)
@@ -148,8 +282,28 @@ account_tree_view_refresh_timeout_cb (gpointer ptree_view)
camel_url_free (url);
}
-skip:
+ gtk_list_store_append (store, &tree_iter);
+ gtk_list_store_set (
+ store, &tree_iter,
+ COLUMN_ACCOUNT, NULL,
+ COLUMN_DEFAULT, FALSE,
+ COLUMN_ENABLED, tree_view->priv->enable_local_folders,
+ COLUMN_NAME, _("On This Computer"),
+ COLUMN_PROTOCOL, NULL,
+ -1);
+
+ gtk_list_store_append (store, &tree_iter);
+ gtk_list_store_set (
+ store, &tree_iter,
+ COLUMN_ACCOUNT, NULL,
+ COLUMN_DEFAULT, FALSE,
+ COLUMN_ENABLED, tree_view->priv->enable_search_folders,
+ COLUMN_NAME, _("Search Folders"),
+ COLUMN_PROTOCOL, NULL,
+ -1);
+ skip:
/* Restore the previously selected account. */
+ selected = e_account_tree_view_get_selected_type (tree_view);
account = e_account_tree_view_get_selected (tree_view);
if (account != NULL)
g_object_ref (account);
@@ -157,6 +311,13 @@ skip:
e_account_tree_view_set_selected (tree_view, account);
if (account != NULL)
g_object_unref (account);
+ else if (selected == E_ACCOUNT_TREE_VIEW_SELECTED_LOCAL ||
+ selected == E_ACCOUNT_TREE_VIEW_SELECTED_VFOLDER)
+ e_account_tree_view_set_selected_type (tree_view, selected);
+
+ e_account_tree_view_set_sort_order (tree_view, sort_order);
+ g_slist_foreach (sort_order, (GFunc) g_free, NULL);
+ g_slist_free (sort_order);
g_signal_emit (tree_view, signals[REFRESHED], 0);
@@ -302,6 +463,26 @@ account_tree_view_set_property (GObject *object,
E_ACCOUNT_TREE_VIEW (object),
g_value_get_object (value));
return;
+ case PROP_SORT_ALPHA:
+ e_account_tree_view_set_sort_alpha (
+ E_ACCOUNT_TREE_VIEW (object),
+ g_value_get_boolean (value));
+ return;
+ case PROP_EXPRESS_MODE:
+ e_account_tree_view_set_express_mode (
+ E_ACCOUNT_TREE_VIEW (object),
+ g_value_get_boolean (value));
+ return;
+ case PROP_ENABLE_LOCAL_FOLDERS:
+ e_account_tree_view_set_enable_local_folders (
+ E_ACCOUNT_TREE_VIEW (object),
+ g_value_get_boolean (value));
+ return;
+ case PROP_ENABLE_SEARCH_FOLDERS:
+ e_account_tree_view_set_enable_search_folders (
+ E_ACCOUNT_TREE_VIEW (object),
+ g_value_get_boolean (value));
+ return;
}
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -327,6 +508,30 @@ account_tree_view_get_property (GObject *object,
e_account_tree_view_get_selected (
E_ACCOUNT_TREE_VIEW (object)));
return;
+ case PROP_SORT_ALPHA:
+ g_value_set_boolean (
+ value,
+ e_account_tree_view_get_sort_alpha (
+ E_ACCOUNT_TREE_VIEW (object)));
+ return;
+ case PROP_EXPRESS_MODE:
+ g_value_set_boolean (
+ value,
+ e_account_tree_view_get_express_mode (
+ E_ACCOUNT_TREE_VIEW (object)));
+ return;
+ case PROP_ENABLE_LOCAL_FOLDERS:
+ g_value_set_boolean (
+ value,
+ e_account_tree_view_get_enable_local_folders (
+ E_ACCOUNT_TREE_VIEW (object)));
+ return;
+ case PROP_ENABLE_SEARCH_FOLDERS:
+ g_value_set_boolean (
+ value,
+ e_account_tree_view_get_enable_search_folders (
+ E_ACCOUNT_TREE_VIEW (object)));
+ return;
}
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -442,6 +647,46 @@ e_account_tree_view_class_init (EAccountTreeViewClass *class)
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
+ g_object_class_install_property (
+ object_class,
+ PROP_SORT_ALPHA,
+ g_param_spec_boolean (
+ "sort-alpha",
+ "Sort alphabetically",
+ NULL,
+ TRUE,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_EXPRESS_MODE,
+ g_param_spec_boolean (
+ "express-mode",
+ "Express Mode sorting",
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_ENABLE_LOCAL_FOLDERS,
+ g_param_spec_boolean (
+ "enable-local-folders",
+ "Enable Local Folders",
+ NULL,
+ TRUE,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_ENABLE_SEARCH_FOLDERS,
+ g_param_spec_boolean (
+ "enable-search-folders",
+ "Enable Search Folders",
+ NULL,
+ TRUE,
+ G_PARAM_READWRITE));
+
signals[ENABLE_ACCOUNT] = g_signal_new (
"enable-account",
G_TYPE_FROM_CLASS (class),
@@ -468,6 +713,15 @@ e_account_tree_view_class_init (EAccountTreeViewClass *class)
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
+
+ signals[SORT_ORDER_CHANGED] = g_signal_new (
+ "sort-order-changed",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EAccountTreeViewClass, sort_order_changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
}
static void
@@ -485,6 +739,10 @@ e_account_tree_view_init (EAccountTreeView *tree_view)
tree_view->priv = G_TYPE_INSTANCE_GET_PRIVATE (
tree_view, E_TYPE_ACCOUNT_TREE_VIEW, EAccountTreeViewPrivate);
tree_view->priv->index = index;
+ tree_view->priv->sort_alpha = TRUE;
+ tree_view->priv->express_mode = FALSE;
+ tree_view->priv->enable_local_folders = TRUE;
+ tree_view->priv->enable_search_folders = TRUE;
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
@@ -622,3 +880,507 @@ e_account_tree_view_set_selected (EAccountTreeView *tree_view,
return TRUE;
}
+
+/**
+ * e_account_tree_view_get_selected_type:
+ * @tree_view: an #EAccountTreeView
+ *
+ * Returns: What node type is selected. This is useful for virtual
+ * nodes "On This Computer" and "Search Folders", which doesn't have
+ * their #EAccount representations. if the function returns
+ * #E_ACCOUNT_TREE_VIEW_SELECTED_ACCOUNT, then the selected account
+ * can be obtained with e_account_tree_view_get_selected().
+ *
+ * Since: 3.4
+ **/
+EAccountTreeViewSelectedType
+e_account_tree_view_get_selected_type (EAccountTreeView *tree_view)
+{
+ EAccountTreeViewSelectedType res = E_ACCOUNT_TREE_VIEW_SELECTED_NONE;
+ EAccount *account = NULL;
+ gchar *name = NULL;
+ GtkTreeSelection *selection;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+
+ g_return_val_if_fail (tree_view != NULL, E_ACCOUNT_TREE_VIEW_SELECTED_NONE);
+ g_return_val_if_fail (E_IS_ACCOUNT_TREE_VIEW (tree_view), E_ACCOUNT_TREE_VIEW_SELECTED_NONE);
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
+ if (!gtk_tree_selection_get_selected (selection, &model, &iter))
+ return E_ACCOUNT_TREE_VIEW_SELECTED_NONE;
+
+ gtk_tree_model_get (model, &iter,
+ COLUMN_ACCOUNT, &account,
+ COLUMN_NAME, &name,
+ -1);
+
+ if (account) {
+ res = E_ACCOUNT_TREE_VIEW_SELECTED_ACCOUNT;
+ g_object_unref (account);
+ } else if (name) {
+ if (g_str_equal (name, _("On This Computer")))
+ res = E_ACCOUNT_TREE_VIEW_SELECTED_LOCAL;
+ else if (g_str_equal (name, _("Search Folders")))
+ res = E_ACCOUNT_TREE_VIEW_SELECTED_VFOLDER;
+ }
+
+ g_free (name);
+
+ return res;
+}
+
+/**
+ * e_account_tree_view_set_selected_type:
+ * @tree_view: an #EAccountTreeView
+ * @select: what to select; see below what can be used here
+ *
+ * Selects special nodes in a view. Can be only either #E_ACCOUNT_TREE_VIEW_SELECTED_LOCAL
+ * or #E_ACCOUNT_TREE_VIEW_SELECTED_VFOLDER.
+ *
+ * Since: 3.4
+ **/
+void
+e_account_tree_view_set_selected_type (EAccountTreeView *tree_view, EAccountTreeViewSelectedType select)
+{
+ GtkTreeSelection *selection;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ gboolean found;
+
+ g_return_if_fail (tree_view != NULL);
+ g_return_if_fail (E_IS_ACCOUNT_TREE_VIEW (tree_view));
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_view));
+
+ if (!model || !gtk_tree_model_get_iter_first (model, &iter))
+ return;
+
+ if (select != E_ACCOUNT_TREE_VIEW_SELECTED_LOCAL &&
+ select != E_ACCOUNT_TREE_VIEW_SELECTED_VFOLDER)
+ return;
+
+ found = FALSE;
+ do {
+ gchar *name = NULL;
+ EAccount *account = NULL;
+
+ gtk_tree_model_get (model, &iter,
+ COLUMN_ACCOUNT, &account,
+ COLUMN_NAME, &name,
+ -1);
+
+ if (account) {
+ g_object_unref (account);
+ } else {
+ switch (select) {
+ case E_ACCOUNT_TREE_VIEW_SELECTED_LOCAL:
+ found = g_strcmp0 (name, _("On This Computer")) == 0;
+ break;
+ case E_ACCOUNT_TREE_VIEW_SELECTED_VFOLDER:
+ found = g_strcmp0 (name, _("Search Folders")) == 0;
+ break;
+ default:
+ break;
+ }
+ }
+
+ g_free (name);
+ } while (!found && gtk_tree_model_iter_next (model, &iter));
+
+ if (found)
+ gtk_tree_selection_select_iter (selection, &iter);
+}
+
+static guint
+account_tree_view_get_slist_index (const GSList *account_uids, const gchar *uid)
+{
+ guint res = 0;
+
+ while (account_uids) {
+ if (g_strcmp0 (uid, account_uids->data) == 0)
+ return res;
+
+ account_uids = account_uids->next;
+ res++;
+ }
+
+ return -1;
+}
+
+/**
+ * e_account_tree_view_set_sort_order:
+ * @tree_view: an #EAccountTreeView
+ * @account_uids: a #GSList of account uids as string
+ *
+ * Sets user sort order for accounts based on the order
+ * in @account_uids. This is used only when sort
+ * alphabetically is set to #FALSE.
+ *
+ * Since: 3.4
+ **/
+void
+e_account_tree_view_set_sort_order (EAccountTreeView *tree_view, const GSList *account_uids)
+{
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+
+ g_return_if_fail (tree_view != NULL);
+ g_return_if_fail (E_IS_ACCOUNT_TREE_VIEW (tree_view));
+
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_view));
+
+ if (!model || !gtk_tree_model_get_iter_first (model, &iter))
+ return;
+
+ do {
+ gchar *name = NULL;
+ EAccount *account = NULL;
+ guint sort_order = 0;
+
+ gtk_tree_model_get (model, &iter,
+ COLUMN_ACCOUNT, &account,
+ COLUMN_NAME, &name,
+ -1);
+
+ if (account) {
+ sort_order = account_tree_view_get_slist_index (account_uids, account->uid) + 1;
+ g_object_unref (account);
+ } else if (g_strcmp0 (name, _("On This Computer")) == 0) {
+ sort_order = account_tree_view_get_slist_index (account_uids, "local") + 1;
+ } else if (g_strcmp0 (name, _("Search Folders")) == 0) {
+ sort_order = account_tree_view_get_slist_index (account_uids, "vfolder") + 1;
+ } else {
+ g_warn_if_reached ();
+ }
+
+ gtk_list_store_set (GTK_LIST_STORE (model), &iter, COLUMN_SORTORDER, sort_order, -1);
+ g_free (name);
+ } while (gtk_tree_model_iter_next (model, &iter));
+
+ account_tree_view_normalize_sortorder_column (tree_view);
+ e_account_tree_view_sort_changed (tree_view);
+}
+
+static gint
+eval_order_by_sort_hash_cb (gconstpointer a, gconstpointer b, gpointer user_data)
+{
+ guint asortorder = GPOINTER_TO_UINT (g_hash_table_lookup (user_data, a));
+ guint bsortorder = GPOINTER_TO_UINT (g_hash_table_lookup (user_data, b));
+
+ if (asortorder < bsortorder)
+ return -1;
+ if (asortorder > bsortorder)
+ return 1;
+
+ return 0;
+}
+
+/**
+ * e_account_tree_view_get_sort_order:
+ * @tree_view: an #EAccountTreeView
+ *
+ * Returns: Newly allocated #GSList of newly allocated strings
+ * containing account UIDs in order as user wish to see them.
+ * Each item of the returned list should be freed with g_free()
+ * and the list itself should be freed with g_slist_free(), when
+ * no longer needed.
+ *
+ * Since: 3.4
+ **/
+GSList *
+e_account_tree_view_get_sort_order (EAccountTreeView *tree_view)
+{
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ GHashTable *hash;
+ GSList *res = NULL;
+
+ g_return_val_if_fail (tree_view != NULL, NULL);
+ g_return_val_if_fail (E_IS_ACCOUNT_TREE_VIEW (tree_view), NULL);
+
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_view));
+
+ if (!model || !gtk_tree_model_get_iter_first (model, &iter))
+ return NULL;
+
+ hash = g_hash_table_new (g_direct_hash, g_direct_equal);
+
+ do {
+ gchar *toadd = NULL;
+ gchar *name = NULL;
+ EAccount *account = NULL;
+ guint sort_order = 0;
+
+ gtk_tree_model_get (model, &iter,
+ COLUMN_ACCOUNT, &account,
+ COLUMN_NAME, &name,
+ COLUMN_SORTORDER, &sort_order,
+ -1);
+
+ if (account) {
+ toadd = g_strdup (account->uid);
+ g_object_unref (account);
+ } else if (g_strcmp0 (name, _("On This Computer")) == 0) {
+ toadd = g_strdup ("local");
+ } else if (g_strcmp0 (name, _("Search Folders")) == 0) {
+ toadd = g_strdup ("vfolder");
+ } else {
+ g_warn_if_reached ();
+ }
+
+ if (toadd) {
+ g_hash_table_insert (hash, toadd, GUINT_TO_POINTER (sort_order));
+ res = g_slist_prepend (res, toadd);
+ }
+
+ g_free (name);
+ } while (gtk_tree_model_iter_next (model, &iter));
+
+ res = g_slist_sort_with_data (res, eval_order_by_sort_hash_cb, hash);
+
+ g_hash_table_destroy (hash);
+
+ return res;
+}
+
+/**
+ * e_account_tree_view_sort_changed:
+ * @tree_view: an #EAccountTreeView
+ *
+ * Notifies @tree_view about sort order change, thus it resorts
+ * items in a view.
+ *
+ * Since: 3.4
+ **/
+void
+e_account_tree_view_sort_changed (EAccountTreeView *tree_view)
+{
+ GtkTreeModel *model;
+
+ g_return_if_fail (tree_view != NULL);
+ g_return_if_fail (E_IS_ACCOUNT_TREE_VIEW (tree_view));
+
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_view));
+ if (!model)
+ return;
+
+ /* this invokes also sort on a GtkListStore */
+ gtk_tree_sortable_set_default_sort_func (
+ GTK_TREE_SORTABLE (model),
+ account_tree_view_sort, tree_view, NULL);
+}
+
+static void
+account_tree_view_swap_sort_order (EAccountTreeView *tree_view, gint direction)
+{
+ GtkTreeSelection *selection;
+ GtkTreeModel *model;
+ GtkTreeIter iter1, iter2;
+ guint sortorder1, sortorder2;
+
+ g_return_if_fail (tree_view != NULL);
+ g_return_if_fail (E_IS_ACCOUNT_TREE_VIEW (tree_view));
+ g_return_if_fail (direction != 0);
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
+ if (!gtk_tree_selection_get_selected (selection, &model, &iter1))
+ return;
+
+ iter2 = iter1;
+ if ((direction < 0 && !gtk_tree_model_iter_previous (model, &iter2)) ||
+ (direction > 0 && !gtk_tree_model_iter_next (model, &iter2)))
+ return;
+
+ gtk_tree_model_get (model, &iter1, COLUMN_SORTORDER, &sortorder1, -1);
+ gtk_tree_model_get (model, &iter2, COLUMN_SORTORDER, &sortorder2, -1);
+
+ gtk_list_store_set (GTK_LIST_STORE (model), &iter1, COLUMN_SORTORDER, sortorder2, -1);
+ gtk_list_store_set (GTK_LIST_STORE (model), &iter2, COLUMN_SORTORDER, sortorder1, -1);
+
+ e_account_tree_view_sort_changed (tree_view);
+
+ g_signal_emit (tree_view, signals[SORT_ORDER_CHANGED], 0);
+}
+
+/**
+ * e_account_tree_view_move_up:
+ * @tree_view: an #EAccountTreeView
+ *
+ * Moves currently selected node up within user's sort order.
+ *
+ * Since: 3.4
+ **/
+void
+e_account_tree_view_move_up (EAccountTreeView *tree_view)
+{
+ g_return_if_fail (tree_view != NULL);
+ g_return_if_fail (E_IS_ACCOUNT_TREE_VIEW (tree_view));
+
+ account_tree_view_swap_sort_order (tree_view, -1);
+}
+
+/**
+ * e_account_tree_view_move_down:
+ * @tree_view: an #EAccountTreeView
+ *
+ * Moves currently selected node down within user's sort order.
+ *
+ * Since: 3.4
+ **/
+void
+e_account_tree_view_move_down (EAccountTreeView *tree_view)
+{
+ g_return_if_fail (tree_view != NULL);
+ g_return_if_fail (E_IS_ACCOUNT_TREE_VIEW (tree_view));
+
+ account_tree_view_swap_sort_order (tree_view, +1);
+}
+
+void
+e_account_tree_view_set_sort_alpha (EAccountTreeView *tree_view, gboolean sort_alpha)
+{
+ g_return_if_fail (tree_view != NULL);
+ g_return_if_fail (E_IS_ACCOUNT_TREE_VIEW (tree_view));
+ g_return_if_fail (tree_view->priv != NULL);
+
+ if ((tree_view->priv->sort_alpha ? 1 : 0) == (sort_alpha ? 1 : 0))
+ return;
+
+ tree_view->priv->sort_alpha = sort_alpha;
+
+ g_object_notify (G_OBJECT (tree_view), "sort-alpha");
+ e_account_tree_view_sort_changed (tree_view);
+}
+
+gboolean
+e_account_tree_view_get_sort_alpha (EAccountTreeView *tree_view)
+{
+ g_return_val_if_fail (tree_view != NULL, FALSE);
+ g_return_val_if_fail (E_IS_ACCOUNT_TREE_VIEW (tree_view), FALSE);
+ g_return_val_if_fail (tree_view->priv != NULL, FALSE);
+
+ return tree_view->priv->sort_alpha;
+}
+
+void
+e_account_tree_view_set_express_mode (EAccountTreeView *tree_view, gboolean express_mode)
+{
+ g_return_if_fail (tree_view != NULL);
+ g_return_if_fail (E_IS_ACCOUNT_TREE_VIEW (tree_view));
+ g_return_if_fail (tree_view->priv != NULL);
+
+ if ((tree_view->priv->express_mode ? 1 : 0) == (express_mode ? 1 : 0))
+ return;
+
+ tree_view->priv->express_mode = express_mode;
+
+ g_object_notify (G_OBJECT (tree_view), "express-mode");
+ e_account_tree_view_sort_changed (tree_view);
+}
+
+gboolean
+e_account_tree_view_get_express_mode (EAccountTreeView *tree_view)
+{
+ g_return_val_if_fail (tree_view != NULL, FALSE);
+ g_return_val_if_fail (E_IS_ACCOUNT_TREE_VIEW (tree_view), FALSE);
+ g_return_val_if_fail (tree_view->priv != NULL, FALSE);
+
+ return tree_view->priv->express_mode;
+}
+
+static void
+update_special_enable_state (EAccountTreeView *tree_view, const gchar *display_name, gboolean enabled)
+{
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ GtkListStore *list_store;
+
+ g_return_if_fail (tree_view != NULL);
+ g_return_if_fail (display_name != NULL);
+
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_view));
+ if (!model)
+ return;
+
+ list_store = GTK_LIST_STORE (model);
+ g_return_if_fail (list_store != NULL);
+
+ if (!gtk_tree_model_get_iter_first (model, &iter))
+ return;
+
+ do {
+ gchar *name = NULL;
+ EAccount *account = NULL;
+
+ gtk_tree_model_get (model, &iter,
+ COLUMN_ACCOUNT, &account,
+ COLUMN_NAME, &name,
+ -1);
+
+ if (account) {
+ g_object_unref (account);
+ } else if (g_strcmp0 (name, display_name) == 0) {
+ gtk_list_store_set (list_store, &iter, COLUMN_ENABLED, enabled, -1);
+ g_free (name);
+ break;
+ }
+
+ g_free (name);
+ } while (gtk_tree_model_iter_next (model, &iter));
+}
+
+void
+e_account_tree_view_set_enable_local_folders (EAccountTreeView *tree_view, gboolean enabled)
+{
+ g_return_if_fail (tree_view != NULL);
+ g_return_if_fail (E_IS_ACCOUNT_TREE_VIEW (tree_view));
+ g_return_if_fail (tree_view->priv != NULL);
+
+ if ((tree_view->priv->enable_local_folders ? 1 : 0) == (enabled ? 1 : 0))
+ return;
+
+ tree_view->priv->enable_local_folders = enabled;
+
+ g_object_notify (G_OBJECT (tree_view), "enable-local-folders");
+
+ update_special_enable_state (tree_view, _("On This Computer"), enabled);
+}
+
+gboolean
+e_account_tree_view_get_enable_local_folders (EAccountTreeView *tree_view)
+{
+ g_return_val_if_fail (tree_view != NULL, FALSE);
+ g_return_val_if_fail (E_IS_ACCOUNT_TREE_VIEW (tree_view), FALSE);
+ g_return_val_if_fail (tree_view->priv != NULL, FALSE);
+
+ return tree_view->priv->enable_local_folders;
+}
+
+void
+e_account_tree_view_set_enable_search_folders (EAccountTreeView *tree_view, gboolean enabled)
+{
+ g_return_if_fail (tree_view != NULL);
+ g_return_if_fail (E_IS_ACCOUNT_TREE_VIEW (tree_view));
+ g_return_if_fail (tree_view->priv != NULL);
+
+ if ((tree_view->priv->enable_search_folders ? 1 : 0) == (enabled ? 1 : 0))
+ return;
+
+ tree_view->priv->enable_search_folders = enabled;
+
+ g_object_notify (G_OBJECT (tree_view), "enable-search-folders");
+
+ update_special_enable_state (tree_view, _("Search Folders"), enabled);
+}
+
+gboolean
+e_account_tree_view_get_enable_search_folders (EAccountTreeView *tree_view)
+{
+ g_return_val_if_fail (tree_view != NULL, FALSE);
+ g_return_val_if_fail (E_IS_ACCOUNT_TREE_VIEW (tree_view), FALSE);
+ g_return_val_if_fail (tree_view->priv != NULL, FALSE);
+
+ return tree_view->priv->enable_search_folders;
+}
diff --git a/widgets/misc/e-account-tree-view.h b/widgets/misc/e-account-tree-view.h
index e9b2f7f8d3..d62d040bbd 100644
--- a/widgets/misc/e-account-tree-view.h
+++ b/widgets/misc/e-account-tree-view.h
@@ -47,6 +47,14 @@
G_BEGIN_DECLS
+typedef enum
+{
+ E_ACCOUNT_TREE_VIEW_SELECTED_NONE,
+ E_ACCOUNT_TREE_VIEW_SELECTED_ACCOUNT,
+ E_ACCOUNT_TREE_VIEW_SELECTED_LOCAL,
+ E_ACCOUNT_TREE_VIEW_SELECTED_VFOLDER
+} EAccountTreeViewSelectedType;
+
typedef struct _EAccountTreeView EAccountTreeView;
typedef struct _EAccountTreeViewClass EAccountTreeViewClass;
typedef struct _EAccountTreeViewPrivate EAccountTreeViewPrivate;
@@ -62,6 +70,7 @@ struct _EAccountTreeViewClass {
void (*enable_account) (EAccountTreeView *tree_view);
void (*disable_account) (EAccountTreeView *tree_view);
void (*refreshed) (EAccountTreeView *tree_view);
+ void (*sort_order_changed) (EAccountTreeView *tree_view);
};
GType e_account_tree_view_get_type (void);
@@ -80,6 +89,43 @@ EAccount * e_account_tree_view_get_selected
gboolean e_account_tree_view_set_selected
(EAccountTreeView *tree_view,
EAccount *account);
+EAccountTreeViewSelectedType
+ e_account_tree_view_get_selected_type
+ (EAccountTreeView *tree_view);
+void e_account_tree_view_set_selected_type
+ (EAccountTreeView *tree_view,
+ EAccountTreeViewSelectedType select);
+
+void e_account_tree_view_set_sort_order
+ (EAccountTreeView *tree_view,
+ const GSList *account_uids);
+
+GSList * e_account_tree_view_get_sort_order
+ (EAccountTreeView *tree_view);
+
+void e_account_tree_view_sort_changed
+ (EAccountTreeView *tree_view);
+void e_account_tree_view_move_up (EAccountTreeView *tree_view);
+void e_account_tree_view_move_down (EAccountTreeView *tree_view);
+
+void e_account_tree_view_set_sort_alpha
+ (EAccountTreeView *tree_view,
+ gboolean sort_alpha);
+gboolean e_account_tree_view_get_sort_alpha
+ (EAccountTreeView *tree_view);
+void e_account_tree_view_set_express_mode
+ (EAccountTreeView *tree_view,
+ gboolean express_mode);
+gboolean e_account_tree_view_get_express_mode
+ (EAccountTreeView *tree_view);
+void e_account_tree_view_set_enable_local_folders
+ (EAccountTreeView *tree_view, gboolean enabled);
+gboolean e_account_tree_view_get_enable_local_folders
+ (EAccountTreeView *tree_view);
+void e_account_tree_view_set_enable_search_folders
+ (EAccountTreeView *tree_view, gboolean enabled);
+gboolean e_account_tree_view_get_enable_search_folders
+ (EAccountTreeView *tree_view);
G_END_DECLS