aboutsummaryrefslogtreecommitdiffstats
path: root/widgets/misc
diff options
context:
space:
mode:
Diffstat (limited to 'widgets/misc')
-rw-r--r--widgets/misc/Makefile.am8
-rw-r--r--widgets/misc/e-account-combo-box.c514
-rw-r--r--widgets/misc/e-account-combo-box.h85
-rw-r--r--widgets/misc/e-mail-account-manager.c384
-rw-r--r--widgets/misc/e-mail-account-manager.h77
-rw-r--r--widgets/misc/e-mail-account-tree-view.c575
-rw-r--r--widgets/misc/e-mail-account-tree-view.h83
-rw-r--r--widgets/misc/e-mail-identity-combo-box.c374
-rw-r--r--widgets/misc/e-mail-identity-combo-box.h76
-rw-r--r--widgets/misc/test-mail-accounts.c61
10 files changed, 1636 insertions, 601 deletions
diff --git a/widgets/misc/Makefile.am b/widgets/misc/Makefile.am
index c09a78f70c..bb3c662d5c 100644
--- a/widgets/misc/Makefile.am
+++ b/widgets/misc/Makefile.am
@@ -5,7 +5,6 @@ widgetsincludedir = $(privincludedir)/misc
ui_DATA = e-send-options.ui
widgetsinclude_HEADERS = \
- e-account-combo-box.h \
e-action-combo-box.h \
e-activity-bar.h \
e-activity-proxy.h \
@@ -38,6 +37,9 @@ widgetsinclude_HEADERS = \
e-image-chooser.h \
e-import-assistant.h \
e-interval-chooser.h \
+ e-mail-account-manager.h \
+ e-mail-account-tree-view.h \
+ e-mail-identity-combo-box.h \
e-map.h \
e-menu-tool-action.h \
e-menu-tool-button.h \
@@ -93,7 +95,6 @@ libemiscwidgets_la_CPPFLAGS = \
libemiscwidgets_la_SOURCES = \
$(widgetsinclude_HEADERS) \
- e-account-combo-box.c \
e-action-combo-box.c \
e-activity-bar.c \
e-activity-proxy.c \
@@ -126,6 +127,9 @@ libemiscwidgets_la_SOURCES = \
e-image-chooser.c \
e-import-assistant.c \
e-interval-chooser.c \
+ e-mail-account-manager.c \
+ e-mail-account-tree-view.c \
+ e-mail-identity-combo-box.c \
e-map.c \
e-menu-tool-action.c \
e-menu-tool-button.c \
diff --git a/widgets/misc/e-account-combo-box.c b/widgets/misc/e-account-combo-box.c
deleted file mode 100644
index 9c750f9ec4..0000000000
--- a/widgets/misc/e-account-combo-box.c
+++ /dev/null
@@ -1,514 +0,0 @@
-/*
- * e-account-combo-box.c
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) version 3.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
- *
- *
- * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include "e-account-combo-box.h"
-
-#include <string.h>
-
-#define E_ACCOUNT_COMBO_BOX_GET_PRIVATE(obj) \
- (G_TYPE_INSTANCE_GET_PRIVATE \
- ((obj), E_TYPE_ACCOUNT_COMBO_BOX, EAccountComboBoxPrivate))
-
-enum {
- COLUMN_STRING,
- COLUMN_ACCOUNT
-};
-
-enum {
- REFRESHED,
- LAST_SIGNAL
-};
-
-struct _EAccountComboBoxPrivate {
- EAccountList *account_list;
- GHashTable *index;
- gint num_displayed_accounts;
-};
-
-static CamelSession *camel_session;
-static guint signal_ids[LAST_SIGNAL];
-
-G_DEFINE_TYPE (
- EAccountComboBox,
- e_account_combo_box,
- GTK_TYPE_COMBO_BOX)
-
-static gboolean
-account_combo_box_has_dupes (GList *list,
- const gchar *address)
-{
- GList *iter;
- guint count = 0;
-
- /* Look for duplicates of the given email address. */
- for (iter = list; iter != NULL; iter = iter->next) {
- EAccount *account = iter->data;
-
- if (g_ascii_strcasecmp (account->id->address, address) == 0)
- count++;
- }
-
- return (count > 1);
-}
-
-static EAccount *
-account_combo_box_choose_account (EAccountComboBox *combo_box)
-{
- EAccountList *account_list;
- EAccount *account;
- GtkTreeModel *model;
- GtkTreeIter iter;
-
- account_list = e_account_combo_box_get_account_list (combo_box);
- g_return_val_if_fail (account_list != NULL, NULL);
-
- /* First try the default account. */
-
- /* XXX EAccountList misuses const. */
- account = (EAccount *)
- e_account_list_get_default (account_list);
-
- /* If there is no default account, give up. */
- if (account == NULL)
- return NULL;
-
- /* Make sure the default account appears in the combo box. */
- if (g_hash_table_lookup (combo_box->priv->index, account) != NULL)
- return account;
-
- /* Default account is disabled or otherwise unusable,
- * so fall back to the first account in the combo box. */
-
- model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo_box));
-
- if (!gtk_tree_model_get_iter_first (model, &iter))
- return NULL;
-
- gtk_tree_model_get (model, &iter, COLUMN_ACCOUNT, &account, -1);
-
- return account;
-}
-
-static gboolean
-account_combo_box_test_account (EAccount *account)
-{
- CamelService *service;
- gboolean writable = FALSE;
-
- /* Account must be enabled. */
- if (!account->enabled)
- return FALSE;
-
- /* Account must have a non-empty email address. */
- if (account->id->address == NULL || *account->id->address == '\0')
- return FALSE;
-
- /* XXX Not sure I understand this part. */
- if (account->parent_uid == NULL)
- return TRUE;
-
- /* Account must be writable. */
- service = camel_session_get_service (camel_session, account->uid);
- if (CAMEL_IS_STORE (service)) {
- CamelStore *store = CAMEL_STORE (service);
- writable = (store->mode & CAMEL_STORE_WRITE);
- }
-
- return writable;
-}
-
-static void
-account_combo_box_refresh_cb (EAccountList *account_list,
- EAccount *unused,
- EAccountComboBox *combo_box)
-{
- GtkListStore *store;
- GtkTreeModel *model;
- EIterator *account_iter;
- EAccount *account;
- GHashTable *index;
- GList *list = NULL;
- GList *iter;
-
- combo_box->priv->num_displayed_accounts = 0;
-
- store = gtk_list_store_new (2, G_TYPE_STRING, E_TYPE_ACCOUNT);
- model = GTK_TREE_MODEL (store);
- index = combo_box->priv->index;
-
- g_hash_table_remove_all (index);
-
- if (account_list == NULL)
- goto skip;
-
- /* Build a list of EAccounts to display. */
- account_iter = e_list_get_iterator (E_LIST (account_list));
- while (e_iterator_is_valid (account_iter)) {
- EAccount *account;
-
- /* XXX EIterator misuses const. */
- account = (EAccount *) e_iterator_get (account_iter);
- if (account_combo_box_test_account (account))
- list = g_list_prepend (list, account);
- e_iterator_next (account_iter);
- }
- g_object_unref (account_iter);
-
- list = g_list_reverse (list);
-
- /* Populate the list store and index. */
- for (iter = list; iter != NULL; iter = iter->next) {
- GtkTreeRowReference *reference;
- GtkTreeIter tree_iter;
- GtkTreePath *path;
- gchar *string;
-
- account = iter->data;
- combo_box->priv->num_displayed_accounts++;
-
- /* Show the account name for duplicate email addresses. */
- if (account_combo_box_has_dupes (list, account->id->address))
- string = g_strdup_printf (
- "%s <%s> (%s)",
- account->id->name,
- account->id->address,
- account->name);
- else
- string = g_strdup_printf (
- "%s <%s>",
- account->id->name,
- account->id->address);
-
- gtk_list_store_append (store, &tree_iter);
- gtk_list_store_set (
- store, &tree_iter,
- COLUMN_STRING, string,
- COLUMN_ACCOUNT, account, -1);
-
- path = gtk_tree_model_get_path (model, &tree_iter);
- reference = gtk_tree_row_reference_new (model, path);
- g_hash_table_insert (index, account, reference);
- gtk_tree_path_free (path);
-
- g_free (string);
- }
-
- g_list_free (list);
-
-skip:
- /* Restore the previously selected account. */
- account = e_account_combo_box_get_active (combo_box);
- if (account != NULL)
- g_object_ref (account);
- gtk_combo_box_set_model (GTK_COMBO_BOX (combo_box), model);
- e_account_combo_box_set_active (combo_box, account);
- if (account != NULL)
- g_object_unref (account);
-
- g_signal_emit (combo_box, signal_ids[REFRESHED], 0);
-}
-
-static GObject *
-account_combo_box_constructor (GType type,
- guint n_construct_properties,
- GObjectConstructParam *construct_properties)
-{
- GObject *object;
- GObjectClass *parent_class;
- GtkCellRenderer *renderer;
-
- /* Chain up to parent's constructor() method. */
- parent_class = G_OBJECT_CLASS (e_account_combo_box_parent_class);
- object = parent_class->constructor (
- type, n_construct_properties, construct_properties);
-
- renderer = gtk_cell_renderer_text_new ();
-
- gtk_cell_layout_pack_start (
- GTK_CELL_LAYOUT (object), renderer, TRUE);
- gtk_cell_layout_add_attribute (
- GTK_CELL_LAYOUT (object), renderer, "text", COLUMN_STRING);
-
- return object;
-}
-
-static void
-account_combo_box_dispose (GObject *object)
-{
- EAccountComboBoxPrivate *priv;
-
- priv = E_ACCOUNT_COMBO_BOX_GET_PRIVATE (object);
-
- if (priv->account_list != NULL) {
- g_signal_handlers_disconnect_by_func (
- priv->account_list,
- account_combo_box_refresh_cb, object);
- g_object_unref (priv->account_list);
- priv->account_list = NULL;
- }
-
- g_hash_table_remove_all (priv->index);
-
- /* Chain up to parent's dispose() method. */
- G_OBJECT_CLASS (e_account_combo_box_parent_class)->dispose (object);
-}
-
-static void
-account_combo_box_finalize (GObject *object)
-{
- EAccountComboBoxPrivate *priv;
-
- priv = E_ACCOUNT_COMBO_BOX_GET_PRIVATE (object);
-
- g_hash_table_destroy (priv->index);
-
- /* Chain up to parent's finalize() method. */
- G_OBJECT_CLASS (e_account_combo_box_parent_class)->finalize (object);
-}
-
-static void
-e_account_combo_box_class_init (EAccountComboBoxClass *class)
-{
- GObjectClass *object_class;
-
- g_type_class_add_private (class, sizeof (EAccountComboBoxPrivate));
-
- object_class = G_OBJECT_CLASS (class);
- object_class->constructor = account_combo_box_constructor;
- object_class->dispose = account_combo_box_dispose;
- object_class->finalize = account_combo_box_finalize;
-
- signal_ids[REFRESHED] = g_signal_new (
- "refreshed",
- G_TYPE_FROM_CLASS (class),
- G_SIGNAL_RUN_LAST,
- 0, NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
-}
-
-static void
-e_account_combo_box_init (EAccountComboBox *combo_box)
-{
- GHashTable *index;
-
- /* Reverse-lookup index */
- index = g_hash_table_new_full (
- g_direct_hash, g_direct_equal,
- (GDestroyNotify) g_object_unref,
- (GDestroyNotify) gtk_tree_row_reference_free);
-
- combo_box->priv = E_ACCOUNT_COMBO_BOX_GET_PRIVATE (combo_box);
- combo_box->priv->index = index;
-}
-
-GtkWidget *
-e_account_combo_box_new (void)
-{
- return g_object_new (E_TYPE_ACCOUNT_COMBO_BOX, NULL);
-}
-
-void
-e_account_combo_box_set_session (CamelSession *session)
-{
- /* XXX Really gross hack.
- *
- * We need a CamelSession to test whether a given EAccount is
- * writable. The global CamelSession object is defined in the
- * mailer, but we're too far down the stack to access it. So
- * we have to rely on someone passing us a reference to it.
- *
- * A much cleaner solution would be to store the writeability
- * of an account directly into the EAccount, but this would likely
- * require breaking ABI and all the fun that goes along with that.
- */
-
- camel_session = session;
-}
-
-EAccountList *
-e_account_combo_box_get_account_list (EAccountComboBox *combo_box)
-{
- g_return_val_if_fail (E_IS_ACCOUNT_COMBO_BOX (combo_box), NULL);
-
- return combo_box->priv->account_list;
-}
-
-void
-e_account_combo_box_set_account_list (EAccountComboBox *combo_box,
- EAccountList *account_list)
-{
- EAccountComboBoxPrivate *priv;
-
- g_return_if_fail (E_IS_ACCOUNT_COMBO_BOX (combo_box));
-
- if (account_list != NULL)
- g_return_if_fail (E_IS_ACCOUNT_LIST (account_list));
-
- priv = E_ACCOUNT_COMBO_BOX_GET_PRIVATE (combo_box);
-
- if (priv->account_list != NULL) {
- g_signal_handlers_disconnect_by_func (
- priv->account_list,
- account_combo_box_refresh_cb, combo_box);
- g_object_unref (priv->account_list);
- priv->account_list = NULL;
- }
-
- if (account_list != NULL) {
- priv->account_list = g_object_ref (account_list);
-
- /* Listen for changes to the account list. */
- g_signal_connect (
- priv->account_list, "account-added",
- G_CALLBACK (account_combo_box_refresh_cb), combo_box);
- g_signal_connect (
- priv->account_list, "account-changed",
- G_CALLBACK (account_combo_box_refresh_cb), combo_box);
- g_signal_connect (
- priv->account_list, "account-removed",
- G_CALLBACK (account_combo_box_refresh_cb), combo_box);
- }
-
- account_combo_box_refresh_cb (account_list, NULL, combo_box);
-}
-
-EAccount *
-e_account_combo_box_get_active (EAccountComboBox *combo_box)
-{
- EAccount *account;
- GtkTreeModel *model;
- GtkTreeIter iter;
- gboolean iter_set;
-
- g_return_val_if_fail (E_IS_ACCOUNT_COMBO_BOX (combo_box), NULL);
-
- iter_set = gtk_combo_box_get_active_iter (
- GTK_COMBO_BOX (combo_box), &iter);
- if (!iter_set)
- return NULL;
-
- model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo_box));
- gtk_tree_model_get (model, &iter, COLUMN_ACCOUNT, &account, -1);
-
- return account;
-}
-
-gboolean
-e_account_combo_box_set_active (EAccountComboBox *combo_box,
- EAccount *account)
-{
- EAccountList *account_list;
- GtkTreeRowReference *reference;
- GtkTreeModel *model;
- GtkTreePath *path;
- GtkTreeIter iter;
- gboolean iter_set;
-
- g_return_val_if_fail (E_IS_ACCOUNT_COMBO_BOX (combo_box), FALSE);
-
- if (account != NULL)
- g_return_val_if_fail (E_IS_ACCOUNT (account), FALSE);
-
- account_list = combo_box->priv->account_list;
- g_return_val_if_fail (account_list != NULL, FALSE);
-
- /* NULL means choose an account ourselves. */
- if (account == NULL)
- account = account_combo_box_choose_account (combo_box);
-
- if (account == NULL)
- return FALSE;
-
- /* Lookup the tree row reference for the account. */
- reference = g_hash_table_lookup (combo_box->priv->index, account);
- if (reference == NULL)
- return FALSE;
-
- /* Convert the reference to a tree iterator. */
- path = gtk_tree_row_reference_get_path (reference);
- model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo_box));
- iter_set = gtk_tree_model_get_iter (model, &iter, path);
- gtk_tree_path_free (path);
-
- if (!iter_set)
- return FALSE;
-
- /* Activate the corresponding combo box item. */
- gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo_box), &iter);
-
- return TRUE;
-}
-
-const gchar *
-e_account_combo_box_get_active_name (EAccountComboBox *combo_box)
-{
- EAccount *account;
-
- g_return_val_if_fail (E_IS_ACCOUNT_COMBO_BOX (combo_box), NULL);
-
- account = e_account_combo_box_get_active (combo_box);
- return (account != NULL) ? account->name : NULL;
-}
-
-gboolean
-e_account_combo_box_set_active_name (EAccountComboBox *combo_box,
- const gchar *account_name)
-{
- EAccountList *account_list;
- EAccount *account;
-
- g_return_val_if_fail (E_IS_ACCOUNT_COMBO_BOX (combo_box), FALSE);
-
- account_list = combo_box->priv->account_list;
- g_return_val_if_fail (account_list != NULL, FALSE);
-
- /* XXX EAccountList misuses const. */
- account = (EAccount *) e_account_list_find (
- account_list, E_ACCOUNT_FIND_NAME, account_name);
-
- if (account == NULL)
- return FALSE;
-
- return e_account_combo_box_set_active (combo_box, account);
-}
-
-/**
- * e_account_combo_box_count_displayed_accounts:
- * @combo_box: an #EAccountComboBox
- *
- * Counts the number of accounts that are displayed in the @combo_box. This may not
- * be the actual number of accounts that are configured, as some of those accounts
- * may be disabled by the user.
- *
- * Return value: number of active and valid accounts as shown in the @combo_box.
- */
-gint
-e_account_combo_box_count_displayed_accounts (EAccountComboBox *combo_box)
-{
- g_return_val_if_fail (E_IS_ACCOUNT_COMBO_BOX (combo_box), -1);
-
- return combo_box->priv->num_displayed_accounts;
-}
diff --git a/widgets/misc/e-account-combo-box.h b/widgets/misc/e-account-combo-box.h
deleted file mode 100644
index aa29c97306..0000000000
--- a/widgets/misc/e-account-combo-box.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * e-account-combo-box.h
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) version 3.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
- *
- *
- * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
- *
- */
-
-#ifndef E_ACCOUNT_COMBO_BOX_H
-#define E_ACCOUNT_COMBO_BOX_H
-
-#include <gtk/gtk.h>
-#include <camel/camel.h>
-#include <libedataserver/e-account.h>
-#include <libedataserver/e-account-list.h>
-
-/* Standard GObject macros */
-#define E_TYPE_ACCOUNT_COMBO_BOX \
- (e_account_combo_box_get_type ())
-#define E_ACCOUNT_COMBO_BOX(obj) \
- (G_TYPE_CHECK_INSTANCE_CAST \
- ((obj), E_TYPE_ACCOUNT_COMBO_BOX, EAccountComboBox))
-#define E_ACCOUNT_COMBO_BOX_CLASS(cls) \
- (G_TYPE_CHECK_CLASS_CAST \
- ((cls), E_TYPE_ACCOUNT_COMBO_BOX, EAccountComboBoxClass))
-#define E_IS_ACCOUNT_COMBO_BOX(obj) \
- (G_TYPE_CHECK_INSTANCE_TYPE \
- ((obj), E_TYPE_ACCOUNT_COMBO_BOX))
-#define E_IS_ACCOUNT_COMBO_BOX_CLASS(cls) \
- (G_TYPE_CHECK_CLASS_TYPE \
- ((cls), E_TYPE_ACCOUNT_COMBO_BOX))
-#define E_ACCOUNT_COMBO_BOX_GET_CLASS(obj) \
- (G_TYPE_INSTANCE_GET_CLASS \
- ((obj), E_TYPE_ACCOUNT_COMBO_BOX, EAccountComboBoxClass))
-
-G_BEGIN_DECLS
-
-typedef struct _EAccountComboBox EAccountComboBox;
-typedef struct _EAccountComboBoxClass EAccountComboBoxClass;
-typedef struct _EAccountComboBoxPrivate EAccountComboBoxPrivate;
-
-struct _EAccountComboBox {
- GtkComboBox parent;
- EAccountComboBoxPrivate *priv;
-};
-
-struct _EAccountComboBoxClass {
- GtkComboBoxClass parent_class;
-};
-
-GType e_account_combo_box_get_type (void);
-GtkWidget * e_account_combo_box_new (void);
-void e_account_combo_box_set_session (CamelSession *session);
-EAccountList * e_account_combo_box_get_account_list
- (EAccountComboBox *combo_box);
-void e_account_combo_box_set_account_list
- (EAccountComboBox *combo_box,
- EAccountList *account_list);
-EAccount * e_account_combo_box_get_active (EAccountComboBox *combo_box);
-gboolean e_account_combo_box_set_active (EAccountComboBox *combo_box,
- EAccount *account);
-const gchar * e_account_combo_box_get_active_name
- (EAccountComboBox *combo_box);
-gboolean e_account_combo_box_set_active_name
- (EAccountComboBox *combo_box,
- const gchar *account_name);
-gint e_account_combo_box_count_displayed_accounts
- (EAccountComboBox *combo_box);
-
-G_END_DECLS
-
-#endif /* E_ACCOUNT_COMBO_BOX_H */
diff --git a/widgets/misc/e-mail-account-manager.c b/widgets/misc/e-mail-account-manager.c
new file mode 100644
index 0000000000..fd5e999a90
--- /dev/null
+++ b/widgets/misc/e-mail-account-manager.c
@@ -0,0 +1,384 @@
+/*
+ * e-mail-account-manager.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-mail-account-manager.h"
+
+#include <config.h>
+#include <glib/gi18n-lib.h>
+#include <gdk/gdkkeysyms.h>
+
+#include "e-mail-account-tree-view.h"
+
+#define E_MAIL_ACCOUNT_MANAGER_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_MAIL_ACCOUNT_MANAGER, EMailAccountManagerPrivate))
+
+struct _EMailAccountManagerPrivate {
+ ESourceRegistry *registry;
+
+ GtkWidget *tree_view; /* not referenced */
+ GtkWidget *add_button; /* not referenced */
+ GtkWidget *edit_button; /* not referenced */
+ GtkWidget *delete_button; /* not referenced */
+ GtkWidget *default_button; /* not referenced */
+};
+
+enum {
+ PROP_0,
+ PROP_REGISTRY
+};
+
+enum {
+ ADD_ACCOUNT,
+ EDIT_ACCOUNT,
+ DELETE_ACCOUNT,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+
+G_DEFINE_TYPE (
+ EMailAccountManager,
+ e_mail_account_manager,
+ GTK_TYPE_TABLE)
+
+static gboolean
+mail_account_manager_key_press_event_cb (EMailAccountManager *manager,
+ GdkEventKey *event)
+{
+ if (event->keyval == GDK_KEY_Delete) {
+ e_mail_account_manager_delete_account (manager);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+mail_account_manager_selection_changed_cb (EMailAccountManager *manager,
+ GtkTreeSelection *selection)
+{
+ EMailAccountTreeView *tree_view;
+ ESourceRegistry *registry;
+ ESource *default_source;
+ ESource *source;
+ GtkWidget *add_button;
+ GtkWidget *edit_button;
+ GtkWidget *delete_button;
+ GtkWidget *default_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;
+
+ registry = e_mail_account_manager_get_registry (manager);
+ tree_view = E_MAIL_ACCOUNT_TREE_VIEW (manager->priv->tree_view);
+
+ source = e_mail_account_tree_view_get_selected_source (tree_view);
+ default_source = e_source_registry_get_default_mail_account (registry);
+
+ if (source == NULL)
+ gtk_widget_grab_focus (add_button);
+
+ sensitive = (source != NULL);
+ gtk_widget_set_sensitive (edit_button, sensitive);
+
+ sensitive = (source != NULL);
+ gtk_widget_set_sensitive (delete_button, sensitive);
+
+ sensitive = (source != NULL && source != default_source);
+ gtk_widget_set_sensitive (default_button, sensitive);
+}
+
+static void
+mail_account_manager_set_registry (EMailAccountManager *manager,
+ ESourceRegistry *registry)
+{
+ g_return_if_fail (E_IS_SOURCE_REGISTRY (registry));
+ g_return_if_fail (manager->priv->registry == NULL);
+
+ manager->priv->registry = g_object_ref (registry);
+}
+
+static void
+mail_account_manager_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_REGISTRY:
+ mail_account_manager_set_registry (
+ E_MAIL_ACCOUNT_MANAGER (object),
+ g_value_get_object (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+mail_account_manager_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_REGISTRY:
+ g_value_set_object (
+ value,
+ e_mail_account_manager_get_registry (
+ E_MAIL_ACCOUNT_MANAGER (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+mail_account_manager_dispose (GObject *object)
+{
+ EMailAccountManagerPrivate *priv;
+
+ priv = E_MAIL_ACCOUNT_MANAGER_GET_PRIVATE (object);
+
+ if (priv->registry != NULL) {
+ g_object_unref (priv->registry);
+ priv->registry = NULL;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (e_mail_account_manager_parent_class)->dispose (object);
+}
+
+static void
+mail_account_manager_constructed (GObject *object)
+{
+ EMailAccountManager *manager;
+ ESourceRegistry *registry;
+ GtkTreeSelection *selection;
+ GtkWidget *container;
+ GtkWidget *widget;
+
+ manager = E_MAIL_ACCOUNT_MANAGER (object);
+ registry = e_mail_account_manager_get_registry (manager);
+
+ /* Chain up to parent's constructed() method. */
+ G_OBJECT_CLASS (e_mail_account_manager_parent_class)->
+ constructed (object);
+
+ gtk_table_resize (GTK_TABLE (manager), 1, 2);
+ gtk_table_set_col_spacings (GTK_TABLE (manager), 6);
+ gtk_table_set_row_spacings (GTK_TABLE (manager), 12);
+
+ container = GTK_WIDGET (manager);
+
+ widget = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (
+ GTK_SCROLLED_WINDOW (widget),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_shadow_type (
+ GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
+ gtk_table_attach (
+ GTK_TABLE (container), widget, 0, 1, 0, 1,
+ GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
+ gtk_widget_show (widget);
+
+ container = widget;
+
+ widget = e_mail_account_tree_view_new (registry);
+ gtk_container_add (GTK_CONTAINER (container), widget);
+ manager->priv->tree_view = widget; /* not referenced */
+ gtk_widget_show (widget);
+
+ g_signal_connect_swapped (
+ widget, "key-press-event",
+ G_CALLBACK (mail_account_manager_key_press_event_cb),
+ manager);
+
+ g_signal_connect_swapped (
+ widget, "row-activated",
+ G_CALLBACK (e_mail_account_manager_edit_account),
+ manager);
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget));
+
+ g_signal_connect_swapped (
+ selection, "changed",
+ G_CALLBACK (mail_account_manager_selection_changed_cb),
+ manager);
+
+ container = GTK_WIDGET (manager);
+
+ widget = gtk_vbutton_box_new ();
+ gtk_button_box_set_layout (
+ GTK_BUTTON_BOX (widget), GTK_BUTTONBOX_START);
+ gtk_box_set_spacing (GTK_BOX (widget), 6);
+ gtk_table_attach (
+ GTK_TABLE (container), widget,
+ 1, 2, 0, 2, 0, GTK_FILL, 0, 0);
+ gtk_widget_show (widget);
+
+ container = widget;
+
+ widget = gtk_button_new_from_stock (GTK_STOCK_ADD);
+ gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
+ manager->priv->add_button = widget; /* not referenced */
+ gtk_widget_show (widget);
+
+ g_signal_connect_swapped (
+ widget, "clicked",
+ G_CALLBACK (e_mail_account_manager_add_account), manager);
+
+ widget = gtk_button_new_from_stock (GTK_STOCK_EDIT);
+ gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
+ manager->priv->edit_button = widget; /* not referenced */
+ gtk_widget_show (widget);
+
+ g_signal_connect_swapped (
+ widget, "clicked",
+ G_CALLBACK (e_mail_account_manager_edit_account), manager);
+
+ widget = gtk_button_new_from_stock (GTK_STOCK_DELETE);
+ gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
+ manager->priv->delete_button = widget; /* not referenced */
+ gtk_widget_show (widget);
+
+ g_signal_connect_swapped (
+ widget, "clicked",
+ G_CALLBACK (e_mail_account_manager_delete_account), manager);
+
+ widget = gtk_button_new_with_mnemonic (_("De_fault"));
+ gtk_button_set_image (
+ GTK_BUTTON (widget),
+ gtk_image_new_from_icon_name (
+ "emblem-default", GTK_ICON_SIZE_BUTTON));
+ gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
+ manager->priv->default_button = widget; /* not referenced */
+ gtk_widget_show (widget);
+
+ g_signal_connect_swapped (
+ widget, "clicked",
+ G_CALLBACK (e_mail_account_tree_view_enable_selected),
+ manager->priv->tree_view);
+}
+
+static void
+e_mail_account_manager_class_init (EMailAccountManagerClass *class)
+{
+ GObjectClass *object_class;
+
+ g_type_class_add_private (class, sizeof (EMailAccountManagerPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = mail_account_manager_set_property;
+ object_class->get_property = mail_account_manager_get_property;
+ object_class->dispose = mail_account_manager_dispose;
+ object_class->constructed = mail_account_manager_constructed;
+
+ /* XXX If we moved the account editor to /widgets/misc we
+ * could handle adding and editing accounts directly. */
+
+ g_object_class_install_property (
+ object_class,
+ PROP_REGISTRY,
+ g_param_spec_object (
+ "registry",
+ "Registry",
+ NULL,
+ E_TYPE_SOURCE_REGISTRY,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY));
+
+ signals[ADD_ACCOUNT] = g_signal_new (
+ "add-account",
+ G_OBJECT_CLASS_TYPE (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EMailAccountManagerClass, add_account),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ signals[EDIT_ACCOUNT] = g_signal_new (
+ "edit-account",
+ G_OBJECT_CLASS_TYPE (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EMailAccountManagerClass, edit_account),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ signals[DELETE_ACCOUNT] = g_signal_new (
+ "delete-account",
+ G_OBJECT_CLASS_TYPE (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EMailAccountManagerClass, delete_account),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+}
+
+static void
+e_mail_account_manager_init (EMailAccountManager *manager)
+{
+ manager->priv = E_MAIL_ACCOUNT_MANAGER_GET_PRIVATE (manager);
+}
+
+GtkWidget *
+e_mail_account_manager_new (ESourceRegistry *registry)
+{
+ g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
+
+ return g_object_new (
+ E_TYPE_MAIL_ACCOUNT_MANAGER,
+ "registry", registry, NULL);
+}
+
+void
+e_mail_account_manager_add_account (EMailAccountManager *manager)
+{
+ g_return_if_fail (E_IS_MAIL_ACCOUNT_MANAGER (manager));
+
+ g_signal_emit (manager, signals[ADD_ACCOUNT], 0);
+}
+
+void
+e_mail_account_manager_edit_account (EMailAccountManager *manager)
+{
+ g_return_if_fail (E_IS_MAIL_ACCOUNT_MANAGER (manager));
+
+ g_signal_emit (manager, signals[EDIT_ACCOUNT], 0);
+}
+
+void
+e_mail_account_manager_delete_account (EMailAccountManager *manager)
+{
+ g_return_if_fail (E_IS_MAIL_ACCOUNT_MANAGER (manager));
+
+ g_signal_emit (manager, signals[DELETE_ACCOUNT], 0);
+}
+
+ESourceRegistry *
+e_mail_account_manager_get_registry (EMailAccountManager *manager)
+{
+ g_return_val_if_fail (E_IS_MAIL_ACCOUNT_MANAGER (manager), NULL);
+
+ return manager->priv->registry;
+}
diff --git a/widgets/misc/e-mail-account-manager.h b/widgets/misc/e-mail-account-manager.h
new file mode 100644
index 0000000000..4afbe7052d
--- /dev/null
+++ b/widgets/misc/e-mail-account-manager.h
@@ -0,0 +1,77 @@
+/*
+ * e-mail-account-manager.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_MAIL_ACCOUNT_MANAGER_H
+#define E_MAIL_ACCOUNT_MANAGER_H
+
+#include <gtk/gtk.h>
+#include <libedataserver/e-source-registry.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MAIL_ACCOUNT_MANAGER \
+ (e_mail_account_manager_get_type ())
+#define E_MAIL_ACCOUNT_MANAGER(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_MAIL_ACCOUNT_MANAGER, EMailAccountManager))
+#define E_MAIL_ACCOUNT_MANAGER_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_MAIL_ACCOUNT_MANAGER, EMailAccountManagerClass))
+#define E_IS_MAIL_ACCOUNT_MANAGER(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_MAIL_ACCOUNT_MANAGER))
+#define E_IS_MAIL_ACCOUNT_MANAGER_CLASS(cls) \
+ (G_TYPE_CHECK_INSTANCE_CLASS \
+ ((cls), E_TYPE_MAIL_ACCOUNT_MANAGER))
+#define E_MAIL_ACCOUNT_MANAGER_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_MAIL_ACCOUNT_MANAGER, EMailAccountManagerClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EMailAccountManager EMailAccountManager;
+typedef struct _EMailAccountManagerClass EMailAccountManagerClass;
+typedef struct _EMailAccountManagerPrivate EMailAccountManagerPrivate;
+
+struct _EMailAccountManager {
+ GtkTable parent;
+ EMailAccountManagerPrivate *priv;
+};
+
+struct _EMailAccountManagerClass {
+ GtkTableClass parent_class;
+
+ void (*add_account) (EMailAccountManager *manager);
+ void (*edit_account) (EMailAccountManager *manager);
+ void (*delete_account) (EMailAccountManager *manager);
+};
+
+GType e_mail_account_manager_get_type (void) G_GNUC_CONST;
+GtkWidget * e_mail_account_manager_new (ESourceRegistry *registry);
+void e_mail_account_manager_add_account
+ (EMailAccountManager *manager);
+void e_mail_account_manager_edit_account
+ (EMailAccountManager *manager);
+void e_mail_account_manager_delete_account
+ (EMailAccountManager *manager);
+ESourceRegistry *
+ e_mail_account_manager_get_registry
+ (EMailAccountManager *manager);
+
+G_END_DECLS
+
+#endif /* E_MAIL_ACCOUNT_MANAGER_H */
diff --git a/widgets/misc/e-mail-account-tree-view.c b/widgets/misc/e-mail-account-tree-view.c
new file mode 100644
index 0000000000..45d6a0d72e
--- /dev/null
+++ b/widgets/misc/e-mail-account-tree-view.c
@@ -0,0 +1,575 @@
+/*
+ * e-mail-account-tree-view.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-mail-account-tree-view.h"
+
+#include <config.h>
+#include <glib/gi18n-lib.h>
+
+#include <libedataserver/e-source-mail-account.h>
+
+#define E_MAIL_ACCOUNT_TREE_VIEW_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_MAIL_ACCOUNT_TREE_VIEW, EMailAccountTreeViewPrivate))
+
+#define SOURCE_IS_MAIL_ACCOUNT(source) \
+ (e_source_has_extension ((source), E_SOURCE_EXTENSION_MAIL_ACCOUNT))
+
+struct _EMailAccountTreeViewPrivate {
+ ESourceRegistry *registry;
+ guint refresh_idle_id;
+};
+
+enum {
+ PROP_0,
+ PROP_REGISTRY
+};
+
+enum {
+ ENABLE_SELECTED,
+ DISABLE_SELECTED,
+ LAST_SIGNAL
+};
+
+enum {
+ COLUMN_DISPLAY_NAME,
+ COLUMN_BACKEND_NAME,
+ COLUMN_DEFAULT,
+ COLUMN_ENABLED,
+ COLUMN_UID
+};
+
+static guint signals[LAST_SIGNAL];
+
+G_DEFINE_TYPE (
+ EMailAccountTreeView,
+ e_mail_account_tree_view,
+ GTK_TYPE_TREE_VIEW)
+
+static gboolean
+mail_account_tree_view_refresh_idle_cb (EMailAccountTreeView *tree_view)
+{
+ /* The refresh function will clear the idle ID. */
+ e_mail_account_tree_view_refresh (tree_view);
+
+ return FALSE;
+}
+
+static void
+mail_account_tree_view_registry_changed (ESourceRegistry *registry,
+ ESource *source,
+ EMailAccountTreeView *tree_view)
+{
+ /* If the ESource in question has a "Mail Account" extension,
+ * schedule a refresh of the tree model. Otherwise ignore it.
+ * We use an idle callback to limit how frequently we refresh
+ * the tree model, in case the registry is emitting lots of
+ * signals at once. */
+
+ if (!SOURCE_IS_MAIL_ACCOUNT (source))
+ return;
+
+ if (tree_view->priv->refresh_idle_id > 0)
+ return;
+
+ tree_view->priv->refresh_idle_id = gdk_threads_add_idle (
+ (GSourceFunc) mail_account_tree_view_refresh_idle_cb,
+ tree_view);
+}
+
+static void
+mail_account_tree_view_enabled_toggled_cb (GtkCellRendererToggle *cell_renderer,
+ const gchar *path_string,
+ EMailAccountTreeView *tree_view)
+{
+ GtkTreeSelection *selection;
+ GtkTreePath *path;
+
+ /* Chain the selection first so we enable or disable the
+ * correct account. */
+ path = gtk_tree_path_new_from_string (path_string);
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
+ gtk_tree_selection_select_path (selection, path);
+ gtk_tree_path_free (path);
+
+ if (gtk_cell_renderer_toggle_get_active (cell_renderer))
+ e_mail_account_tree_view_disable_selected (tree_view);
+ else
+ e_mail_account_tree_view_enable_selected (tree_view);
+}
+
+static void
+mail_account_tree_view_set_registry (EMailAccountTreeView *tree_view,
+ ESourceRegistry *registry)
+{
+ g_return_if_fail (E_IS_SOURCE_REGISTRY (registry));
+ g_return_if_fail (tree_view->priv->registry == NULL);
+
+ tree_view->priv->registry = g_object_ref (registry);
+
+ g_signal_connect (
+ registry, "source-added",
+ G_CALLBACK (mail_account_tree_view_registry_changed),
+ tree_view);
+
+ g_signal_connect (
+ registry, "source-changed",
+ G_CALLBACK (mail_account_tree_view_registry_changed),
+ tree_view);
+
+ g_signal_connect (
+ registry, "source-removed",
+ G_CALLBACK (mail_account_tree_view_registry_changed),
+ tree_view);
+}
+
+static void
+mail_account_tree_view_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_REGISTRY:
+ mail_account_tree_view_set_registry (
+ E_MAIL_ACCOUNT_TREE_VIEW (object),
+ g_value_get_object (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+mail_account_tree_view_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_REGISTRY:
+ g_value_set_object (
+ value,
+ e_mail_account_tree_view_get_registry (
+ E_MAIL_ACCOUNT_TREE_VIEW (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+mail_account_tree_view_dispose (GObject *object)
+{
+ EMailAccountTreeViewPrivate *priv;
+
+ priv = E_MAIL_ACCOUNT_TREE_VIEW_GET_PRIVATE (object);
+
+ if (priv->registry != NULL) {
+ g_signal_handlers_disconnect_matched (
+ priv->registry, G_SIGNAL_MATCH_DATA,
+ 0, 0, NULL, NULL, object);
+ g_object_unref (priv->registry);
+ priv->registry = NULL;
+ }
+
+ if (priv->refresh_idle_id > 0) {
+ g_source_remove (priv->refresh_idle_id);
+ priv->refresh_idle_id = 0;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (e_mail_account_tree_view_parent_class)->
+ dispose (object);
+}
+
+static void
+mail_account_tree_view_constructed (GObject *object)
+{
+ GtkTreeView *tree_view;
+ GtkTreeViewColumn *column;
+ GtkCellRenderer *cell_renderer;
+
+ /* Chain up to parent's constructed() method. */
+ G_OBJECT_CLASS (e_mail_account_tree_view_parent_class)->
+ constructed (object);
+
+ tree_view = GTK_TREE_VIEW (object);
+ gtk_tree_view_set_headers_visible (tree_view, TRUE);
+
+ /* Column: Enabled */
+
+ column = gtk_tree_view_column_new ();
+ gtk_tree_view_column_set_expand (column, FALSE);
+ gtk_tree_view_column_set_title (column, _("Enabled"));
+
+ cell_renderer = gtk_cell_renderer_toggle_new ();
+ gtk_tree_view_column_pack_start (column, cell_renderer, TRUE);
+
+ g_signal_connect (
+ cell_renderer, "toggled",
+ G_CALLBACK (mail_account_tree_view_enabled_toggled_cb),
+ tree_view);
+
+ gtk_tree_view_column_add_attribute (
+ column, cell_renderer, "active", COLUMN_ENABLED);
+
+ gtk_tree_view_append_column (tree_view, column);
+
+ /* Column: Account Name */
+
+ column = gtk_tree_view_column_new ();
+ gtk_tree_view_column_set_expand (column, TRUE);
+ gtk_tree_view_column_set_title (column, _("Account Name"));
+
+ cell_renderer = gtk_cell_renderer_text_new ();
+ g_object_set (cell_renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
+ gtk_tree_view_column_pack_start (column, cell_renderer, TRUE);
+
+ gtk_tree_view_column_add_attribute (
+ column, cell_renderer, "text", COLUMN_DISPLAY_NAME);
+
+ cell_renderer = gtk_cell_renderer_text_new ();
+ g_object_set (cell_renderer, "text", _("Default"), NULL);
+ gtk_tree_view_column_pack_end (column, cell_renderer, FALSE);
+
+ gtk_tree_view_column_add_attribute (
+ column, cell_renderer, "visible", COLUMN_DISPLAY_NAME);
+
+ cell_renderer = gtk_cell_renderer_pixbuf_new ();
+ g_object_set (
+ cell_renderer, "icon-name", "emblem-default",
+ "stock-size", GTK_ICON_SIZE_MENU, NULL);
+ gtk_tree_view_column_pack_end (column, cell_renderer, FALSE);
+
+ gtk_tree_view_column_add_attribute (
+ column, cell_renderer, "visible", COLUMN_DISPLAY_NAME);
+
+ gtk_tree_view_append_column (tree_view, column);
+
+ /* Column: Type */
+
+ column = gtk_tree_view_column_new ();
+ gtk_tree_view_column_set_expand (column, FALSE);
+ gtk_tree_view_column_set_title (column, _("Type"));
+
+ cell_renderer = gtk_cell_renderer_text_new ();
+ gtk_tree_view_column_pack_start (column, cell_renderer, TRUE);
+
+ gtk_tree_view_column_add_attribute (
+ column, cell_renderer, "text", COLUMN_BACKEND_NAME);
+
+ gtk_tree_view_append_column (tree_view, column);
+
+ e_mail_account_tree_view_refresh (E_MAIL_ACCOUNT_TREE_VIEW (object));
+}
+
+static void
+mail_account_tree_view_enable_selected (EMailAccountTreeView *tree_view)
+{
+ ESource *source;
+ ESourceMailAccount *mail_account;
+ const gchar *extension_name;
+ GError *error = NULL;
+
+ source = e_mail_account_tree_view_get_selected_source (tree_view);
+
+ if (source == NULL)
+ return;
+
+ /* The source should already be a mail account. */
+ g_return_if_fail (SOURCE_IS_MAIL_ACCOUNT (source));
+
+ extension_name = E_SOURCE_EXTENSION_MAIL_ACCOUNT;
+ mail_account = e_source_get_extension (source, extension_name);
+
+ /* Avoid unnecessary signal emissions and disk writes. */
+ if (e_source_mail_account_get_enabled (mail_account))
+ return;
+
+ e_source_mail_account_set_enabled (mail_account, TRUE);
+
+ if (!e_source_sync (source, &error)) {
+ g_warning ("%s", error->message);
+ g_error_free (error);
+ }
+}
+
+static void
+mail_account_tree_view_disable_selected (EMailAccountTreeView *tree_view)
+{
+ ESource *source;
+ ESourceMailAccount *mail_account;
+ const gchar *extension_name;
+ GError *error = NULL;
+
+ source = e_mail_account_tree_view_get_selected_source (tree_view);
+
+ if (source == NULL)
+ return;
+
+ /* The source should already be a mail account. */
+ g_return_if_fail (SOURCE_IS_MAIL_ACCOUNT (source));
+
+ extension_name = E_SOURCE_EXTENSION_MAIL_ACCOUNT;
+ mail_account = e_source_get_extension (source, extension_name);
+
+ /* Avoid unnecessary signal emissions and disk writes. */
+ if (!e_source_mail_account_get_enabled (mail_account))
+ return;
+
+ e_source_mail_account_set_enabled (mail_account, FALSE);
+
+ if (!e_source_sync (source, &error)) {
+ g_warning ("%s", error->message);
+ g_error_free (error);
+ }
+}
+
+static void
+e_mail_account_tree_view_class_init (EMailAccountTreeViewClass *class)
+{
+ GObjectClass *object_class;
+
+ g_type_class_add_private (class, sizeof (EMailAccountTreeViewPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = mail_account_tree_view_set_property;
+ object_class->get_property = mail_account_tree_view_get_property;
+ object_class->dispose = mail_account_tree_view_dispose;
+ object_class->constructed = mail_account_tree_view_constructed;
+
+ class->enable_selected = mail_account_tree_view_enable_selected;
+ class->disable_selected = mail_account_tree_view_disable_selected;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_REGISTRY,
+ g_param_spec_object (
+ "registry",
+ "Registry",
+ NULL,
+ E_TYPE_SOURCE_REGISTRY,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+
+ signals[ENABLE_SELECTED] = g_signal_new (
+ "enable-selected",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EMailAccountTreeViewClass, enable_selected),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ signals[DISABLE_SELECTED] = g_signal_new (
+ "disable-selected",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EMailAccountTreeViewClass, disable_selected),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+}
+
+static void
+e_mail_account_tree_view_init (EMailAccountTreeView *tree_view)
+{
+ tree_view->priv = E_MAIL_ACCOUNT_TREE_VIEW_GET_PRIVATE (tree_view);
+}
+
+GtkWidget *
+e_mail_account_tree_view_new (ESourceRegistry *registry)
+{
+ g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
+
+ return g_object_new (
+ E_TYPE_MAIL_ACCOUNT_TREE_VIEW,
+ "registry", registry, NULL);
+}
+
+void
+e_mail_account_tree_view_refresh (EMailAccountTreeView *tree_view)
+{
+ ESourceRegistry *registry;
+ GtkTreeModel *tree_model;
+ ESource *default_source;
+ ESource *source;
+ GList *list, *link;
+ const gchar *extension_name;
+ gchar *saved_uid = NULL;
+
+ g_return_if_fail (E_IS_MAIL_ACCOUNT_TREE_VIEW (tree_view));
+
+ if (tree_view->priv->refresh_idle_id > 0) {
+ g_source_remove (tree_view->priv->refresh_idle_id);
+ tree_view->priv->refresh_idle_id = 0;
+ }
+
+ registry = e_mail_account_tree_view_get_registry (tree_view);
+ tree_model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_view));
+
+ source = e_mail_account_tree_view_get_selected_source (tree_view);
+ if (source != NULL)
+ saved_uid = g_strdup (e_source_get_uid (source));
+
+ default_source = e_source_registry_get_default_mail_account (registry);
+
+ gtk_list_store_clear (GTK_LIST_STORE (tree_model));
+
+ extension_name = E_SOURCE_EXTENSION_MAIL_ACCOUNT;
+ list = e_source_registry_list_sources (registry, extension_name);
+
+ for (link = list; link != NULL; link = g_list_next (link)) {
+ ESourceMailAccount *mail_account;
+ GtkTreeIter iter;
+ const gchar *backend_name;
+ const gchar *display_name;
+ const gchar *uid;
+ gboolean is_default;
+ gboolean is_enabled;
+
+ source = E_SOURCE (link->data);
+ mail_account = e_source_get_extension (source, extension_name);
+
+ display_name = e_source_get_display_name (source);
+ backend_name = e_source_get_backend_name (source);
+ is_default = e_source_equal (source, default_source);
+ is_enabled = e_source_mail_account_get_enabled (mail_account);
+ uid = e_source_get_uid (source);
+
+ gtk_list_store_append (GTK_LIST_STORE (tree_model), &iter);
+
+ gtk_list_store_set (
+ GTK_LIST_STORE (tree_model), &iter,
+ COLUMN_DISPLAY_NAME, display_name,
+ COLUMN_BACKEND_NAME, backend_name,
+ COLUMN_DEFAULT, is_default,
+ COLUMN_ENABLED, is_enabled,
+ COLUMN_UID, uid, -1);
+ }
+
+ g_list_free (list);
+
+ /* Try and restore the previous selected source,
+ * or else just pick the default mail account. */
+
+ source = NULL;
+
+ if (saved_uid != NULL) {
+ source = e_source_registry_lookup_by_uid (registry, saved_uid);
+ g_free (saved_uid);
+ }
+
+ if (source == NULL)
+ source = default_source;
+
+ if (source != NULL)
+ e_mail_account_tree_view_set_selected_source (
+ tree_view, source);
+}
+
+void
+e_mail_account_tree_view_enable_selected (EMailAccountTreeView *tree_view)
+{
+ g_return_if_fail (E_IS_MAIL_ACCOUNT_TREE_VIEW (tree_view));
+
+ g_signal_emit (tree_view, signals[ENABLE_SELECTED], 0);
+}
+
+void
+e_mail_account_tree_view_disable_selected (EMailAccountTreeView *tree_view)
+{
+ g_return_if_fail (E_IS_MAIL_ACCOUNT_TREE_VIEW (tree_view));
+
+ g_signal_emit (tree_view, signals[DISABLE_SELECTED], 0);
+}
+
+ESourceRegistry *
+e_mail_account_tree_view_get_registry (EMailAccountTreeView *tree_view)
+{
+ g_return_val_if_fail (E_IS_MAIL_ACCOUNT_TREE_VIEW (tree_view), NULL);
+
+ return tree_view->priv->registry;
+}
+
+ESource *
+e_mail_account_tree_view_get_selected_source (EMailAccountTreeView *tree_view)
+{
+ ESourceRegistry *registry;
+ GtkTreeSelection *selection;
+ GtkTreeModel *tree_model;
+ GtkTreeIter iter;
+ ESource *source;
+ gchar *uid;
+
+ g_return_val_if_fail (E_IS_MAIL_ACCOUNT_TREE_VIEW (tree_view), NULL);
+
+ registry = e_mail_account_tree_view_get_registry (tree_view);
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
+
+ if (!gtk_tree_selection_get_selected (selection, &tree_model, &iter))
+ return NULL;
+
+ gtk_tree_model_get (tree_model, &iter, COLUMN_UID, &uid, -1);
+ source = e_source_registry_lookup_by_uid (registry, uid);
+ g_free (uid);
+
+ return source;
+}
+
+void
+e_mail_account_tree_view_set_selected_source (EMailAccountTreeView *tree_view,
+ ESource *source)
+{
+ ESourceRegistry *registry;
+ GtkTreeSelection *selection;
+ GtkTreeModel *tree_model;
+ GtkTreeIter iter;
+ gboolean valid;
+
+ g_return_if_fail (E_IS_MAIL_ACCOUNT_TREE_VIEW (tree_view));
+ g_return_if_fail (E_IS_SOURCE (source));
+
+ /* It is a programming error to pass an ESource that has no
+ * "Mail Account" extension. */
+ g_return_if_fail (SOURCE_IS_MAIL_ACCOUNT (source));
+
+ registry = e_mail_account_tree_view_get_registry (tree_view);
+ tree_model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_view));
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
+
+ valid = gtk_tree_model_get_iter_first (tree_model, &iter);
+
+ while (valid) {
+ ESource *candidate;
+ gchar *uid;
+
+ gtk_tree_model_get (tree_model, &iter, COLUMN_UID, &uid, -1);
+ candidate = e_source_registry_lookup_by_uid (registry, uid);
+ g_free (uid);
+
+ if (candidate != NULL && e_source_equal (source, candidate)) {
+ gtk_tree_selection_select_iter (selection, &iter);
+ break;
+ }
+
+ valid = gtk_tree_model_iter_next (tree_model, &iter);
+ }
+}
diff --git a/widgets/misc/e-mail-account-tree-view.h b/widgets/misc/e-mail-account-tree-view.h
new file mode 100644
index 0000000000..4bf9099191
--- /dev/null
+++ b/widgets/misc/e-mail-account-tree-view.h
@@ -0,0 +1,83 @@
+/*
+ * e-mail-account-tree-view.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_MAIL_ACCOUNT_TREE_VIEW_H
+#define E_MAIL_ACCOUNT_TREE_VIEW_H
+
+#include <gtk/gtk.h>
+#include <libedataserver/e-source-registry.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MAIL_ACCOUNT_TREE_VIEW \
+ (e_mail_account_tree_view_get_type ())
+#define E_MAIL_ACCOUNT_TREE_VIEW(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_MAIL_ACCOUNT_TREE_VIEW, EMailAccountTreeView))
+#define E_MAIL_ACCOUNT_TREE_VIEW_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_MAIL_ACCOUNT_TREE_VIEW, EMailAccountTreeViewClass))
+#define E_IS_MAIL_ACCOUNT_TREE_VIEW(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_MAIL_ACCOUNT_TREE_VIEW))
+#define E_IS_MAIL_ACCOUNT_TREE_VIEW_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_MAIL_ACCOUNT_TREE_VIEW))
+#define E_MAIL_ACCOUNT_TREE_VIEW_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_MAIL_ACCOUNT_TREE_VIEW, EMailAccountTreeViewClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EMailAccountTreeView EMailAccountTreeView;
+typedef struct _EMailAccountTreeViewClass EMailAccountTreeViewClass;
+typedef struct _EMailAccountTreeViewPrivate EMailAccountTreeViewPrivate;
+
+struct _EMailAccountTreeView {
+ GtkTreeView parent;
+ EMailAccountTreeViewPrivate *priv;
+};
+
+struct _EMailAccountTreeViewClass {
+ GtkTreeViewClass parent_class;
+
+ void (*enable_selected) (EMailAccountTreeView *tree_view);
+ void (*disable_selected) (EMailAccountTreeView *tree_view);
+};
+
+GType e_mail_account_tree_view_get_type
+ (void) G_GNUC_CONST;
+GtkWidget * e_mail_account_tree_view_new
+ (ESourceRegistry *registry);
+void e_mail_account_tree_view_refresh
+ (EMailAccountTreeView *tree_view);
+void e_mail_account_tree_view_enable_selected
+ (EMailAccountTreeView *tree_view);
+void e_mail_account_tree_view_disable_selected
+ (EMailAccountTreeView *tree_view);
+ESourceRegistry *
+ e_mail_account_tree_view_get_registry
+ (EMailAccountTreeView *tree_view);
+ESource * e_mail_account_tree_view_get_selected_source
+ (EMailAccountTreeView *tree_view);
+void e_mail_account_tree_view_set_selected_source
+ (EMailAccountTreeView *tree_view,
+ ESource *source);
+
+G_END_DECLS
+
+#endif /* E_MAIL_ACCOUNT_TREE_VIEW_H */
diff --git a/widgets/misc/e-mail-identity-combo-box.c b/widgets/misc/e-mail-identity-combo-box.c
new file mode 100644
index 0000000000..4b830153a2
--- /dev/null
+++ b/widgets/misc/e-mail-identity-combo-box.c
@@ -0,0 +1,374 @@
+/*
+ * e-mail-identity-combo-box.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-mail-identity-combo-box.h"
+
+#include <libedataserver/e-source-mail-account.h>
+#include <libedataserver/e-source-mail-identity.h>
+
+#define E_MAIL_IDENTITY_COMBO_BOX_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_MAIL_IDENTITY_COMBO_BOX, EMailIdentityComboBoxPrivate))
+
+#define SOURCE_IS_MAIL_IDENTITY(source) \
+ (e_source_has_extension ((source), E_SOURCE_EXTENSION_MAIL_IDENTITY))
+
+struct _EMailIdentityComboBoxPrivate {
+ ESourceRegistry *registry;
+ guint refresh_idle_id;
+};
+
+enum {
+ PROP_0,
+ PROP_REGISTRY
+};
+
+enum {
+ COLUMN_DISPLAY_NAME,
+ COLUMN_UID
+};
+
+G_DEFINE_TYPE (
+ EMailIdentityComboBox,
+ e_mail_identity_combo_box,
+ GTK_TYPE_COMBO_BOX)
+
+static gboolean
+mail_identity_combo_box_refresh_idle_cb (EMailIdentityComboBox *combo_box)
+{
+ /* The refresh function will clear the idle ID. */
+ e_mail_identity_combo_box_refresh (combo_box);
+
+ return FALSE;
+}
+
+static void
+mail_identity_combo_box_registry_changed (ESourceRegistry *registry,
+ ESource *source,
+ EMailIdentityComboBox *combo_box)
+{
+ /* If the ESource in question has a "Mail Identity" extension,
+ * schedule a refresh of the tree model. Otherwise ignore it.
+ * We use an idle callback to limit how frequently we refresh
+ * the tree model, in case the registry is emitting lots of
+ * signals at once. */
+
+ if (!SOURCE_IS_MAIL_IDENTITY (source))
+ return;
+
+ if (combo_box->priv->refresh_idle_id > 0)
+ return;
+
+ combo_box->priv->refresh_idle_id = gdk_threads_add_idle (
+ (GSourceFunc) mail_identity_combo_box_refresh_idle_cb,
+ combo_box);
+}
+
+static ESource *
+mail_identity_combo_box_get_default (EMailIdentityComboBox *combo_box)
+{
+ ESource *source;
+ ESourceRegistry *registry;
+ ESourceMailAccount *mail_account;
+ const gchar *extension_name;
+ const gchar *uid;
+
+ extension_name = E_SOURCE_EXTENSION_MAIL_ACCOUNT;
+ registry = e_mail_identity_combo_box_get_registry (combo_box);
+ source = e_source_registry_get_default_mail_account (registry);
+
+ if (source == NULL)
+ return NULL;
+
+ if (!e_source_has_extension (source, extension_name))
+ return NULL;
+
+ mail_account = e_source_get_extension (source, extension_name);
+ uid = e_source_mail_account_get_identity (mail_account);
+
+ if (uid == NULL)
+ return NULL;
+
+ return e_source_registry_lookup_by_uid (registry, uid);
+}
+
+static void
+mail_identity_combo_box_set_registry (EMailIdentityComboBox *combo_box,
+ ESourceRegistry *registry)
+{
+ g_return_if_fail (E_IS_SOURCE_REGISTRY (registry));
+ g_return_if_fail (combo_box->priv->registry == NULL);
+
+ combo_box->priv->registry = g_object_ref (registry);
+
+ g_signal_connect (
+ registry, "source-added",
+ G_CALLBACK (mail_identity_combo_box_registry_changed),
+ combo_box);
+
+ g_signal_connect (
+ registry, "source-changed",
+ G_CALLBACK (mail_identity_combo_box_registry_changed),
+ combo_box);
+
+ g_signal_connect (
+ registry, "source-removed",
+ G_CALLBACK (mail_identity_combo_box_registry_changed),
+ combo_box);
+}
+
+static void
+mail_identity_combo_box_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_REGISTRY:
+ mail_identity_combo_box_set_registry (
+ E_MAIL_IDENTITY_COMBO_BOX (object),
+ g_value_get_object (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+mail_identity_combo_box_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_REGISTRY:
+ g_value_set_object (
+ value,
+ e_mail_identity_combo_box_get_registry (
+ E_MAIL_IDENTITY_COMBO_BOX (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+mail_identity_combo_box_dispose (GObject *object)
+{
+ EMailIdentityComboBoxPrivate *priv;
+
+ priv = E_MAIL_IDENTITY_COMBO_BOX_GET_PRIVATE (object);
+
+ if (priv->registry != NULL) {
+ g_signal_handlers_disconnect_matched (
+ priv->registry, G_SIGNAL_MATCH_DATA,
+ 0, 0, NULL, NULL, object);
+ g_object_unref (priv->registry);
+ priv->registry = NULL;
+ }
+
+ if (priv->refresh_idle_id > 0) {
+ g_source_remove (priv->refresh_idle_id);
+ priv->refresh_idle_id = 0;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (e_mail_identity_combo_box_parent_class)->
+ dispose (object);
+}
+
+static void
+mail_identity_combo_box_constructed (GObject *object)
+{
+ GtkListStore *list_store;
+ GtkComboBox *combo_box;
+ GtkCellLayout *cell_layout;
+ GtkCellRenderer *cell_renderer;
+
+ /* Chain up to parent's constructed() method. */
+ G_OBJECT_CLASS (e_mail_identity_combo_box_parent_class)->
+ constructed (object);
+
+ combo_box = GTK_COMBO_BOX (object);
+ cell_layout = GTK_CELL_LAYOUT (object);
+
+ list_store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);
+ gtk_combo_box_set_model (combo_box, GTK_TREE_MODEL (list_store));
+ gtk_combo_box_set_id_column (combo_box, COLUMN_UID);
+ g_object_unref (list_store);
+
+ cell_renderer = gtk_cell_renderer_text_new ();
+ gtk_cell_layout_pack_start (cell_layout, cell_renderer, TRUE);
+ gtk_cell_layout_add_attribute (
+ cell_layout, cell_renderer, "text", COLUMN_DISPLAY_NAME);
+
+ e_mail_identity_combo_box_refresh (E_MAIL_IDENTITY_COMBO_BOX (object));
+}
+
+static void
+e_mail_identity_combo_box_class_init (EMailIdentityComboBoxClass *class)
+{
+ GObjectClass *object_class;
+
+ g_type_class_add_private (class, sizeof (EMailIdentityComboBoxPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = mail_identity_combo_box_set_property;
+ object_class->get_property = mail_identity_combo_box_get_property;
+ object_class->dispose = mail_identity_combo_box_dispose;
+ object_class->constructed = mail_identity_combo_box_constructed;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_REGISTRY,
+ g_param_spec_object (
+ "registry",
+ "Registry",
+ NULL,
+ E_TYPE_SOURCE_REGISTRY,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+}
+
+static void
+e_mail_identity_combo_box_init (EMailIdentityComboBox *combo_box)
+{
+ combo_box->priv = E_MAIL_IDENTITY_COMBO_BOX_GET_PRIVATE (combo_box);
+}
+
+GtkWidget *
+e_mail_identity_combo_box_new (ESourceRegistry *registry)
+{
+ g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
+
+ return g_object_new (
+ E_TYPE_MAIL_IDENTITY_COMBO_BOX,
+ "registry", registry, NULL);
+}
+
+void
+e_mail_identity_combo_box_refresh (EMailIdentityComboBox *combo_box)
+{
+ ESourceRegistry *registry;
+ GtkTreeModel *tree_model;
+ ESource *source;
+ GList *list, *link;
+ const gchar *extension_name;
+ gchar *saved_uid = NULL;
+
+ g_return_if_fail (E_IS_MAIL_IDENTITY_COMBO_BOX (combo_box));
+
+ if (combo_box->priv->refresh_idle_id > 0) {
+ g_source_remove (combo_box->priv->refresh_idle_id);
+ combo_box->priv->refresh_idle_id = 0;
+ }
+
+ registry = e_mail_identity_combo_box_get_registry (combo_box);
+ tree_model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo_box));
+
+ source = e_mail_identity_combo_box_get_active_source (combo_box);
+ if (source != NULL)
+ saved_uid = g_strdup (e_source_get_uid (source));
+
+ gtk_list_store_clear (GTK_LIST_STORE (tree_model));
+
+ extension_name = E_SOURCE_EXTENSION_MAIL_IDENTITY;
+ list = e_source_registry_list_sources (registry, extension_name);
+
+ for (link = list; link != NULL; link = g_list_next (link)) {
+ GtkTreeIter iter;
+ const gchar *display_name;
+ const gchar *uid;
+
+ source = E_SOURCE (link->data);
+ display_name = e_source_get_display_name (source);
+ uid = e_source_get_uid (source);
+
+ gtk_list_store_append (GTK_LIST_STORE (tree_model), &iter);
+
+ gtk_list_store_set (
+ GTK_LIST_STORE (tree_model), &iter,
+ COLUMN_DISPLAY_NAME, display_name,
+ COLUMN_UID, uid, -1);
+ }
+
+ g_list_free (list);
+
+ /* Try and restore the previous selected source, or else pick
+ * the default identity of the default mail account. If even
+ * that fails, just pick the first item. */
+
+ source = NULL;
+
+ if (saved_uid != NULL) {
+ source = e_source_registry_lookup_by_uid (registry, saved_uid);
+ g_free (saved_uid);
+ }
+
+ if (source == NULL)
+ source = mail_identity_combo_box_get_default (combo_box);
+
+ if (source != NULL)
+ e_mail_identity_combo_box_set_active_source (combo_box, source);
+ else
+ gtk_combo_box_set_active (GTK_COMBO_BOX (combo_box), 0);
+}
+
+ESourceRegistry *
+e_mail_identity_combo_box_get_registry (EMailIdentityComboBox *combo_box)
+{
+ g_return_val_if_fail (E_IS_MAIL_IDENTITY_COMBO_BOX (combo_box), NULL);
+
+ return combo_box->priv->registry;
+}
+
+ESource *
+e_mail_identity_combo_box_get_active_source (EMailIdentityComboBox *combo_box)
+{
+ ESourceRegistry *registry;
+ ESource *source = NULL;
+ const gchar *uid;
+
+ g_return_val_if_fail (E_IS_MAIL_IDENTITY_COMBO_BOX (combo_box), NULL);
+
+ registry = e_mail_identity_combo_box_get_registry (combo_box);
+ uid = gtk_combo_box_get_active_id (GTK_COMBO_BOX (combo_box));
+
+ if (uid != NULL)
+ source = e_source_registry_lookup_by_uid (registry, uid);
+
+ return source;
+}
+
+void
+e_mail_identity_combo_box_set_active_source (EMailIdentityComboBox *combo_box,
+ ESource *active_source)
+{
+ const gchar *uid;
+
+ g_return_if_fail (E_IS_MAIL_IDENTITY_COMBO_BOX (combo_box));
+ g_return_if_fail (E_IS_SOURCE (active_source));
+
+ /* It is a programming error to pass an ESource that has no
+ * "Mail Identity" extension. */
+ g_return_if_fail (SOURCE_IS_MAIL_IDENTITY (active_source));
+
+ uid = e_source_get_uid (active_source);
+ gtk_combo_box_set_active_id (GTK_COMBO_BOX (combo_box), uid);
+}
diff --git a/widgets/misc/e-mail-identity-combo-box.h b/widgets/misc/e-mail-identity-combo-box.h
new file mode 100644
index 0000000000..b40957df7a
--- /dev/null
+++ b/widgets/misc/e-mail-identity-combo-box.h
@@ -0,0 +1,76 @@
+/*
+ * e-mail-identity-combo-box.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_MAIL_IDENTITY_COMBO_BOX_H
+#define E_MAIL_IDENTITY_COMBO_BOX_H
+
+#include <gtk/gtk.h>
+#include <libedataserver/e-source-registry.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MAIL_IDENTITY_COMBO_BOX \
+ (e_mail_identity_combo_box_get_type ())
+#define E_MAIL_IDENTITY_COMBO_BOX(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_MAIL_IDENTITY_COMBO_BOX, EMailIdentityComboBox))
+#define E_MAIL_IDENTITY_COMBO_BOX_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_MAIL_IDENTITY_COMBO_BOX, EMailIdentityComboBoxClass))
+#define E_IS_MAIL_IDENTITY_COMBO_BOX(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_MAIL_IDENTITY_COMBO_BOX))
+#define E_IS_MAIL_IDENTITY_COMBO_BOX_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_MAIL_IDENTITY_COMBO_BOX))
+#define E_MAIL_IDENTITY_COMBO_BOX_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_MAIL_IDENTITY_COMBO_BOX, EMailIdentityComboBoxClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EMailIdentityComboBox EMailIdentityComboBox;
+typedef struct _EMailIdentityComboBoxClass EMailIdentityComboBoxClass;
+typedef struct _EMailIdentityComboBoxPrivate EMailIdentityComboBoxPrivate;
+
+struct _EMailIdentityComboBox {
+ GtkComboBox parent;
+ EMailIdentityComboBoxPrivate *priv;
+};
+
+struct _EMailIdentityComboBoxClass {
+ GtkComboBoxClass parent_class;
+};
+
+GType e_mail_identity_combo_box_get_type
+ (void) G_GNUC_CONST;
+GtkWidget * e_mail_identity_combo_box_new
+ (ESourceRegistry *registry);
+void e_mail_identity_combo_box_refresh
+ (EMailIdentityComboBox *combo_box);
+ESourceRegistry *
+ e_mail_identity_combo_box_get_registry
+ (EMailIdentityComboBox *combo_box);
+ESource * e_mail_identity_combo_box_get_active_source
+ (EMailIdentityComboBox *combo_box);
+void e_mail_identity_combo_box_set_active_source
+ (EMailIdentityComboBox *combo_box,
+ ESource *active_source);
+
+G_END_DECLS
+
+#endif /* E_MAIL_IDENTITY_COMBO_BOX_H */
diff --git a/widgets/misc/test-mail-accounts.c b/widgets/misc/test-mail-accounts.c
new file mode 100644
index 0000000000..92069b4bb2
--- /dev/null
+++ b/widgets/misc/test-mail-accounts.c
@@ -0,0 +1,61 @@
+/*
+ * test-mail-accounts.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include <misc/e-mail-account-manager.h>
+#include <misc/e-mail-identity-combo-box.h>
+
+gint
+main (gint argc, gchar **argv)
+{
+ ESourceRegistry *registry;
+ GtkWidget *container;
+ GtkWidget *widget;
+ GtkWidget *window;
+
+ gtk_init (&argc, &argv);
+
+ registry = e_source_registry_get_default ();
+
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_title (GTK_WINDOW (window), "Mail Sources");
+ gtk_widget_set_default_size (GTK_WINDOW (window), 400, 400);
+ gtk_container_set_border_width (GTK_CONTAINER (window), 12);
+ gtk_widget_show (window);
+
+ g_signal_connect (
+ window, "delete-event",
+ G_CALLBACK (gtk_main_quit), NULL);
+
+ widget = gtk_vbox_new (FALSE, 12);
+ gtk_container_add (GTK_CONTAINER (window), widget);
+ gtk_widget_show (widget);
+
+ container = widget;
+
+ widget = e_mail_identity_combo_box_new (registry);
+ gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
+ gtk_widget_show (widget);
+
+ widget = e_mail_account_manager_new (registry);
+ gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
+ gtk_widget_show (widget);
+
+ gtk_main ();
+
+ return 0;
+}