Commit e0548d25 authored by Milan Crha's avatar Milan Crha
Browse files

Bug #351025 - Make the order of the mail accounts configurable

parent 4046d194
......@@ -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);
}
......@@ -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 */
......@@ -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,
......
......@@ -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,
......
......@@ -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);
......
......@@ -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),
......
......@@ -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,
......
......@@ -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;
......@@ -259,6 +277,106 @@ account_added_cb (EAccountList *accounts,
e_mail_store_add_by_account (session, account);
}
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)
{
......@@ -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 (