From 3449e5fcc7f9c797fcde7f2a444b1eb7a934cd81 Mon Sep 17 00:00:00 2001 From: Matthew Barnes Date: Wed, 13 Apr 2011 10:30:40 -0400 Subject: Adapt mail to the new ESource API. --- mail/e-mail-config-service-page.c | 1039 +++++++++++++++++++++++++++++++++++++ 1 file changed, 1039 insertions(+) create mode 100644 mail/e-mail-config-service-page.c (limited to 'mail/e-mail-config-service-page.c') diff --git a/mail/e-mail-config-service-page.c b/mail/e-mail-config-service-page.c new file mode 100644 index 0000000000..1f53ed5ddb --- /dev/null +++ b/mail/e-mail-config-service-page.c @@ -0,0 +1,1039 @@ +/* + * e-mail-config-service-page.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 + * + */ + +#include "e-mail-config-service-page.h" + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#define E_MAIL_CONFIG_SERVICE_PAGE_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_MAIL_CONFIG_SERVICE_PAGE, EMailConfigServicePagePrivate)) + +/* Used for autoconfiguration. */ +#define POP3_BACKEND_NAME "pop" +#define IMAP_BACKEND_NAME "imapx" +#define SMTP_BACKEND_NAME "smtp" + +typedef struct _Candidate Candidate; + +struct _EMailConfigServicePagePrivate { + ESourceRegistry *registry; + EMailConfigServiceBackend *active_backend; + gchar *email_address; + + GHashTable *backends; + GPtrArray *candidates; + + /* Hidden candidates are not listed in the + * combo box but can still be accessed through + * e_mail_config_service_page_lookup_backend(). */ + GPtrArray *hidden_candidates; + + GtkWidget *type_combo; + GtkWidget *type_label; + GtkWidget *desc_label; + GtkWidget *notebook; + GtkWidget *activity_bar; + GtkWidget *alert_bar; + + /* Combo box list store */ + GtkListStore *list_store; +}; + +struct _Candidate { + gchar *name; + EMailConfigServiceBackend *backend; + + CamelProvider *provider; + CamelSettings *settings; + gulong settings_notify_handler_id; + + GtkWidget *widget; +}; + +enum { + PROP_0, + PROP_ACTIVE_BACKEND, + PROP_EMAIL_ADDRESS, + PROP_REGISTRY +}; + +enum { + COLUMN_BACKEND_NAME, + COLUMN_DISPLAY_NAME, + COLUMN_SELECTABLE, + NUM_COLUMNS +}; + +/* Forward Declarations */ +static void e_mail_config_service_page_alert_sink_init + (EAlertSinkInterface *interface); +static void e_mail_config_service_page_interface_init + (EMailConfigPageInterface *interface); + +G_DEFINE_ABSTRACT_TYPE_WITH_CODE ( + EMailConfigServicePage, + e_mail_config_service_page, + GTK_TYPE_BOX, + G_IMPLEMENT_INTERFACE ( + E_TYPE_EXTENSIBLE, NULL) + G_IMPLEMENT_INTERFACE ( + E_TYPE_ALERT_SINK, + e_mail_config_service_page_alert_sink_init) + G_IMPLEMENT_INTERFACE ( + E_TYPE_MAIL_CONFIG_PAGE, + e_mail_config_service_page_interface_init)) + +static void +mail_config_service_page_settings_notify_cb (CamelSettings *settings, + GParamSpec *pspec, + EMailConfigPage *page) +{ + e_mail_config_page_changed (page); +} + +static Candidate * +mail_config_service_page_new_candidate (EMailConfigServicePage *page, + ESource *scratch_source, + ESource *opt_collection) +{ + Candidate *candidate; + CamelProvider *provider; + CamelSettings *settings; + ESourceBackend *extension; + EMailConfigServiceBackend *backend; + EMailConfigServicePageClass *class; + const gchar *extension_name; + const gchar *backend_name; + gulong handler_id; + + /* Get the backend name for this scratch source. */ + class = E_MAIL_CONFIG_SERVICE_PAGE_GET_CLASS (page); + extension_name = class->extension_name; + extension = e_source_get_extension (scratch_source, extension_name); + backend_name = e_source_backend_get_backend_name (extension); + g_return_val_if_fail (backend_name != NULL, NULL); + + /* Make sure we have a corresponding EMailConfigServicePageBackend. */ + backend = g_hash_table_lookup (page->priv->backends, backend_name); + g_return_val_if_fail (E_IS_MAIL_CONFIG_SERVICE_BACKEND (backend), NULL); + + /* Make sure we have a corresponding CamelProvider. */ + provider = e_mail_config_service_backend_get_provider (backend); + g_return_val_if_fail (provider != NULL, NULL); + + /* Need to give the backend a scratch source and (if provided) a + * scratch collection source before we can extract a CamelSettings + * instance, since the CamelSettings instance comes from either the + * scratch collection source or else the scratch source. */ + e_mail_config_service_backend_set_source (backend, scratch_source); + if (opt_collection != NULL) + e_mail_config_service_backend_set_collection ( + backend, opt_collection); + + /* Make sure we have a corresponding CamelSettings. */ + settings = e_mail_config_service_backend_get_settings (backend); + g_return_val_if_fail (CAMEL_IS_SETTINGS (settings), NULL); + + candidate = g_slice_new0 (Candidate); + candidate->name = g_strdup (backend_name); + candidate->backend = g_object_ref (backend); + candidate->provider = provider; + candidate->settings = g_object_ref (settings); + + /* Remove the backend so it can't be reused. If another scratch + * source with the same backend name gets added, the hash table + * lookup will fail and emit a runtime warning, which we want. */ + g_hash_table_remove (page->priv->backends, backend_name); + + /* Emit "changed" signals for subsequent CamelSettings changes. */ + handler_id = g_signal_connect ( + candidate->settings, "notify", + G_CALLBACK (mail_config_service_page_settings_notify_cb), page); + candidate->settings_notify_handler_id = handler_id; + + return candidate; +} + +static void +mail_config_service_page_free_candidate (Candidate *candidate) +{ + g_free (candidate->name); + + if (candidate->backend != NULL) + g_object_unref (candidate->backend); + + if (candidate->settings != NULL) { + g_signal_handler_disconnect ( + candidate->settings, + candidate->settings_notify_handler_id); + g_object_unref (candidate->settings); + } + + if (candidate->widget != NULL) + g_object_unref (candidate->widget); + + g_slice_free (Candidate, candidate); +} + +static void +mail_config_service_page_init_backends (EMailConfigServicePage *page) +{ + GList *list, *iter; + + page->priv->backends = g_hash_table_new_full ( + (GHashFunc) g_str_hash, + (GEqualFunc) g_str_equal, + (GDestroyNotify) g_free, + (GDestroyNotify) g_object_unref); + + e_extensible_load_extensions (E_EXTENSIBLE (page)); + + list = e_extensible_list_extensions ( + E_EXTENSIBLE (page), E_TYPE_MAIL_CONFIG_SERVICE_BACKEND); + + for (iter = list; iter != NULL; iter = g_list_next (iter)) { + EMailConfigServiceBackend *backend; + EMailConfigServiceBackendClass *class; + + backend = E_MAIL_CONFIG_SERVICE_BACKEND (iter->data); + class = E_MAIL_CONFIG_SERVICE_BACKEND_GET_CLASS (backend); + + if (class->backend_name != NULL) + g_hash_table_insert ( + page->priv->backends, + g_strdup (class->backend_name), + g_object_ref (backend)); + } + + g_list_free (list); +} + +static gboolean +mail_config_service_page_backend_to_id (GBinding *binding, + const GValue *source_value, + GValue *target_value, + gpointer user_data) +{ + EMailConfigServiceBackend *backend; + EMailConfigServiceBackendClass *backend_class; + + backend = g_value_get_object (source_value); + g_return_val_if_fail (backend != NULL, FALSE); + + backend_class = E_MAIL_CONFIG_SERVICE_BACKEND_GET_CLASS (backend); + g_value_set_string (target_value, backend_class->backend_name); + + return TRUE; +} + +static gboolean +mail_config_service_page_id_to_backend (GBinding *binding, + const GValue *source_value, + GValue *target_value, + gpointer user_data) +{ + EMailConfigServiceBackend *backend = NULL; + GObject *source_object; + const gchar *backend_name; + + source_object = g_binding_get_source (binding); + backend_name = g_value_get_string (source_value); + + if (backend_name != NULL) + backend = e_mail_config_service_page_lookup_backend ( + E_MAIL_CONFIG_SERVICE_PAGE (source_object), + backend_name); + + g_value_set_object (target_value, backend); + + return TRUE; +} + +static gboolean +mail_config_service_page_backend_name_to_description (GBinding *binding, + const GValue *source_value, + GValue *target_value, + gpointer user_data) +{ + CamelProvider *provider; + const gchar *description; + const gchar *backend_name; + + backend_name = g_value_get_string (source_value); + + /* XXX Silly special case. */ + if (backend_name == NULL) + backend_name = "none"; + + provider = camel_provider_get (backend_name, NULL); + + if (provider != NULL && provider->description != NULL) + description = g_dgettext ( + provider->translation_domain, + provider->description); + else + description = ""; + + g_value_set_string (target_value, description); + + return TRUE; +} + +static Candidate * +mail_config_service_page_get_active_candidate (EMailConfigServicePage *page) +{ + GtkComboBox *combo_box; + gint active; + + combo_box = GTK_COMBO_BOX (page->priv->type_combo); + active = gtk_combo_box_get_active (combo_box); + g_return_val_if_fail (active >= 0, NULL); + + return g_ptr_array_index (page->priv->candidates, active); +} + +static void +mail_config_service_page_set_registry (EMailConfigServicePage *page, + ESourceRegistry *registry) +{ + g_return_if_fail (E_IS_SOURCE_REGISTRY (registry)); + g_return_if_fail (page->priv->registry == NULL); + + page->priv->registry = g_object_ref (registry); +} + +static void +mail_config_service_page_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_ACTIVE_BACKEND: + e_mail_config_service_page_set_active_backend ( + E_MAIL_CONFIG_SERVICE_PAGE (object), + g_value_get_object (value)); + return; + + case PROP_EMAIL_ADDRESS: + e_mail_config_service_page_set_email_address ( + E_MAIL_CONFIG_SERVICE_PAGE (object), + g_value_get_string (value)); + return; + + case PROP_REGISTRY: + mail_config_service_page_set_registry ( + E_MAIL_CONFIG_SERVICE_PAGE (object), + g_value_get_object (value)); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +mail_config_service_page_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_ACTIVE_BACKEND: + g_value_set_object ( + value, + e_mail_config_service_page_get_active_backend ( + E_MAIL_CONFIG_SERVICE_PAGE (object))); + return; + + case PROP_EMAIL_ADDRESS: + g_value_set_string ( + value, + e_mail_config_service_page_get_email_address ( + E_MAIL_CONFIG_SERVICE_PAGE (object))); + return; + + case PROP_REGISTRY: + g_value_set_object ( + value, + e_mail_config_service_page_get_registry ( + E_MAIL_CONFIG_SERVICE_PAGE (object))); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +mail_config_service_page_dispose (GObject *object) +{ + EMailConfigServicePagePrivate *priv; + + priv = E_MAIL_CONFIG_SERVICE_PAGE_GET_PRIVATE (object); + + if (priv->registry != NULL) { + g_object_unref (priv->registry); + priv->registry = NULL; + } + + if (priv->active_backend != NULL) { + g_object_unref (priv->active_backend); + priv->active_backend = NULL; + } + + g_hash_table_remove_all (priv->backends); + g_ptr_array_set_size (priv->candidates, 0); + g_ptr_array_set_size (priv->hidden_candidates, 0); + + if (priv->list_store != NULL) { + g_object_unref (priv->list_store); + priv->list_store = NULL; + } + + /* Chain up to parent's dispose() method. */ + G_OBJECT_CLASS (e_mail_config_service_page_parent_class)->dispose (object); +} + +static void +mail_config_service_page_finalize (GObject *object) +{ + EMailConfigServicePagePrivate *priv; + + priv = E_MAIL_CONFIG_SERVICE_PAGE_GET_PRIVATE (object); + + g_free (priv->email_address); + g_hash_table_destroy (priv->backends); + g_ptr_array_free (priv->candidates, TRUE); + g_ptr_array_free (priv->hidden_candidates, TRUE); + + /* Chain up to parent's finalize() method. */ + G_OBJECT_CLASS (e_mail_config_service_page_parent_class)->finalize (object); +} + +static void +mail_config_service_page_constructed (GObject *object) +{ + EMailConfigServicePage *page; + + page = E_MAIL_CONFIG_SERVICE_PAGE (object); + + mail_config_service_page_init_backends (page); +} + +static void +mail_config_service_page_submit_alert (EAlertSink *alert_sink, + EAlert *alert) +{ + EMailConfigServicePagePrivate *priv; + EAlertBar *alert_bar; + GtkWidget *dialog; + gpointer parent; + + priv = E_MAIL_CONFIG_SERVICE_PAGE_GET_PRIVATE (alert_sink); + + parent = gtk_widget_get_toplevel (GTK_WIDGET (alert_sink)); + parent = gtk_widget_is_toplevel (parent) ? parent : NULL; + + switch (e_alert_get_message_type (alert)) { + case GTK_MESSAGE_INFO: + case GTK_MESSAGE_WARNING: + case GTK_MESSAGE_ERROR: + alert_bar = E_ALERT_BAR (priv->alert_bar); + e_alert_bar_add_alert (alert_bar, alert); + break; + + default: + dialog = e_alert_dialog_new (parent, alert); + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + break; + } +} + +static void +mail_config_service_page_setup_defaults (EMailConfigPage *page) +{ + EMailConfigServicePageClass *class; + EMailConfigServicePagePrivate *priv; + guint ii; + + class = E_MAIL_CONFIG_SERVICE_PAGE_GET_CLASS (page); + priv = E_MAIL_CONFIG_SERVICE_PAGE_GET_PRIVATE (page); + + for (ii = 0; ii < priv->candidates->len; ii++) { + Candidate *candidate; + + candidate = priv->candidates->pdata[ii]; + g_return_if_fail (candidate != NULL); + + e_mail_config_service_backend_setup_defaults ( + candidate->backend); + } + + /* XXX Not sure if we need to call setup_defaults() for + * hidden candidates. Hold off until a need arises. */ + + if (class->default_backend_name != NULL) + gtk_combo_box_set_active_id ( + GTK_COMBO_BOX (priv->type_combo), + class->default_backend_name); +} + +static gboolean +mail_config_service_page_check_complete (EMailConfigPage *page) +{ + EMailConfigServicePagePrivate *priv; + Candidate *candidate; + GtkComboBox *type_combo; + + priv = E_MAIL_CONFIG_SERVICE_PAGE_GET_PRIVATE (page); + + /* Make sure the combo box has an active item. */ + type_combo = GTK_COMBO_BOX (priv->type_combo); + if (gtk_combo_box_get_active_id (type_combo) == NULL) + return FALSE; + + candidate = mail_config_service_page_get_active_candidate ( + E_MAIL_CONFIG_SERVICE_PAGE (page)); + g_return_val_if_fail (candidate != NULL, FALSE); + + return e_mail_config_service_backend_check_complete ( + candidate->backend); +} + +static void +mail_config_service_page_commit_changes (EMailConfigPage *page, + GQueue *source_queue) +{ + Candidate *candidate; + + candidate = mail_config_service_page_get_active_candidate ( + E_MAIL_CONFIG_SERVICE_PAGE (page)); + g_return_if_fail (candidate != NULL); + + e_mail_config_service_backend_commit_changes (candidate->backend); +} + +static void +e_mail_config_service_page_class_init (EMailConfigServicePageClass *class) +{ + GObjectClass *object_class; + + g_type_class_add_private (class, sizeof (EMailConfigServicePagePrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->set_property = mail_config_service_page_set_property; + object_class->get_property = mail_config_service_page_get_property; + object_class->dispose = mail_config_service_page_dispose; + object_class->finalize = mail_config_service_page_finalize; + object_class->constructed = mail_config_service_page_constructed; + + g_object_class_install_property ( + object_class, + PROP_ACTIVE_BACKEND, + g_param_spec_object ( + "active-backend", + "Active Backend", + "The active service backend", + E_TYPE_MAIL_CONFIG_SERVICE_BACKEND, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property ( + object_class, + PROP_EMAIL_ADDRESS, + g_param_spec_string ( + "email-address", + "Email Address", + "The user's email address", + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property ( + object_class, + PROP_REGISTRY, + g_param_spec_object ( + "registry", + "Registry", + "Data source registry", + E_TYPE_SOURCE_REGISTRY, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); +} + +static void +e_mail_config_service_page_alert_sink_init (EAlertSinkInterface *interface) +{ + interface->submit_alert = mail_config_service_page_submit_alert; +} + +static void +e_mail_config_service_page_interface_init (EMailConfigPageInterface *interface) +{ + interface->setup_defaults = mail_config_service_page_setup_defaults; + interface->check_complete = mail_config_service_page_check_complete; + interface->commit_changes = mail_config_service_page_commit_changes; +} + +static void +e_mail_config_service_page_init (EMailConfigServicePage *page) +{ + GPtrArray *candidates; + GPtrArray *hidden_candidates; + PangoAttribute *attr; + PangoAttrList *attr_list; + GtkLabel *label; + GtkWidget *frame; + GtkWidget *widget; + GtkWidget *container; + GtkTreeModel *tree_model; + GtkCellRenderer *renderer; + + /* The candidates array holds scratch ESources, one for each + * item in the "type" combo box. Scratch ESources are never + * added to the registry, so backend extensions can make any + * changes they want to them. Whichever scratch ESource is + * "active" (selected in the "type" combo box) when the user + * clicks OK wins and is written to disk. The others are + * discarded. */ + candidates = g_ptr_array_new_with_free_func ( + (GDestroyNotify) mail_config_service_page_free_candidate); + + /* Hidden candidates are not listed in the "type" combo box + * but their scratch ESource can still be "active". This is + * a hack to accommodate groupware backends. Usually when a + * hidden candidate is active the service page will not be + * visible anyway. */ + hidden_candidates = g_ptr_array_new_with_free_func ( + (GDestroyNotify) mail_config_service_page_free_candidate); + + gtk_box_set_spacing (GTK_BOX (page), 12); + + gtk_orientable_set_orientation ( + GTK_ORIENTABLE (page), GTK_ORIENTATION_VERTICAL); + + page->priv = E_MAIL_CONFIG_SERVICE_PAGE_GET_PRIVATE (page); + page->priv->candidates = candidates; + page->priv->hidden_candidates = hidden_candidates; + + /* Build a filtered model for the combo box, where row + * visibility is determined by the "selectable" column. */ + + page->priv->list_store = gtk_list_store_new ( + NUM_COLUMNS, + G_TYPE_STRING, /* COLUMN_BACKEND_NAME */ + G_TYPE_STRING, /* COLUMN_DISPLAY_NAME */ + G_TYPE_BOOLEAN); /* COLUMN_SELECTABLE */ + + tree_model = gtk_tree_model_filter_new ( + GTK_TREE_MODEL (page->priv->list_store), NULL); + + gtk_tree_model_filter_set_visible_column ( + GTK_TREE_MODEL_FILTER (tree_model), COLUMN_SELECTABLE); + + /* Either the combo box or the label is shown, never both. + * But we create both widgets and keep them both up-to-date + * regardless just because it makes the logic simpler. */ + + container = GTK_WIDGET (page); + + widget = gtk_grid_new (); + gtk_grid_set_row_spacing (GTK_GRID (widget), 12); + gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); + gtk_widget_show (widget); + + container = widget; + + attr_list = pango_attr_list_new (); + + attr = pango_attr_weight_new (PANGO_WEIGHT_BOLD); + pango_attr_list_insert (attr_list, attr); + + widget = gtk_label_new_with_mnemonic (_("Server _Type:")); + gtk_widget_set_margin_right (widget, 12); + gtk_misc_set_alignment (GTK_MISC (widget), 1.0, 0.5); + gtk_grid_attach (GTK_GRID (container), widget, 0, 0, 1, 1); + gtk_widget_show (widget); + + label = GTK_LABEL (widget); + + widget = gtk_combo_box_new_with_model (tree_model); + gtk_widget_set_hexpand (widget, TRUE); + gtk_label_set_mnemonic_widget (label, widget); + gtk_combo_box_set_id_column ( + GTK_COMBO_BOX (widget), COLUMN_BACKEND_NAME); + gtk_grid_attach (GTK_GRID (container), widget, 1, 0, 1, 1); + page->priv->type_combo = widget; /* not referenced */ + gtk_widget_show (widget); + + renderer = gtk_cell_renderer_text_new (); + gtk_cell_layout_pack_start ( + GTK_CELL_LAYOUT (widget), renderer, TRUE); + gtk_cell_layout_add_attribute ( + GTK_CELL_LAYOUT (widget), renderer, + "text", COLUMN_DISPLAY_NAME); + + widget = gtk_label_new (NULL); + gtk_widget_set_hexpand (widget, TRUE); + gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5); + gtk_label_set_attributes (GTK_LABEL (widget), attr_list); + gtk_grid_attach (GTK_GRID (container), widget, 2, 0, 1, 1); + page->priv->type_label = widget; /* not referenced */ + gtk_widget_show (widget); + + widget = gtk_label_new (_("Description:")); + gtk_widget_set_margin_right (widget, 12); + gtk_misc_set_alignment (GTK_MISC (widget), 1.0, 0.0); + gtk_grid_attach (GTK_GRID (container), widget, 0, 1, 1, 1); + gtk_widget_show (widget); + + widget = gtk_label_new (NULL); + gtk_label_set_line_wrap (GTK_LABEL (widget), TRUE); + gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5); + gtk_grid_attach (GTK_GRID (container), widget, 1, 1, 2, 1); + page->priv->desc_label = widget; /* not referenced */ + gtk_widget_show (widget); + + pango_attr_list_unref (attr_list); + + container = GTK_WIDGET (page); + + widget = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL); + gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); + gtk_widget_show (widget); + + widget = e_mail_config_service_notebook_new (); + gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0); + page->priv->notebook = widget; /* not referenced */ + gtk_widget_show (widget); + + widget = gtk_frame_new (NULL); + gtk_frame_set_shadow_type (GTK_FRAME (widget), GTK_SHADOW_IN); + gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); + /* Visibility is bound to the EActivityBar. */ + + frame = widget; + + widget = e_activity_bar_new (); + gtk_container_add (GTK_CONTAINER (frame), widget); + page->priv->activity_bar = widget; /* not referenced */ + /* EActivityBar controls its own visibility. */ + + g_object_bind_property ( + widget, "visible", + frame, "visible", + G_BINDING_SYNC_CREATE); + + widget = gtk_frame_new (NULL); + gtk_frame_set_shadow_type (GTK_FRAME (widget), GTK_SHADOW_IN); + gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); + /* Visibility is bound to the EAlertBar. */ + + frame = widget; + + widget = e_alert_bar_new (); + gtk_container_add (GTK_CONTAINER (frame), widget); + page->priv->alert_bar = widget; /* not referenced */ + /* EAlertBar controls its own visibility. */ + + g_object_bind_property ( + widget, "visible", + frame, "visible", + G_BINDING_SYNC_CREATE); + + /* Keep the notebook's active page number synchronized with our + * own "active-backend" property. Avoid G_BINDING_SYNC_CREATE + * since we haven't added any notebook pages. */ + g_object_bind_property ( + page, "active-backend", + page->priv->notebook, "active-backend", + G_BINDING_BIDIRECTIONAL); + + /* Keep the combo box's active row number synchronized with our + * own "active-backend" property. Avoid G_BINDING_SYNC_CREATE + * since we haven't added any combo box rows. */ + g_object_bind_property_full ( + page, "active-backend", + page->priv->type_combo, "active-id", + G_BINDING_BIDIRECTIONAL, + mail_config_service_page_backend_to_id, + mail_config_service_page_id_to_backend, + NULL, (GDestroyNotify) NULL); + + /* This keeps the description field up-to-date. */ + g_object_bind_property_full ( + page->priv->type_combo, "active-id", + page->priv->desc_label, "label", + G_BINDING_DEFAULT, + mail_config_service_page_backend_name_to_description, + NULL, + NULL, (GDestroyNotify) NULL); + + /* For the "Server Type", either the combo + * box or the label is visible, never both. */ + g_object_bind_property ( + page->priv->type_combo, "visible", + page->priv->type_label, "visible", + G_BINDING_SYNC_CREATE | + G_BINDING_BIDIRECTIONAL | + G_BINDING_INVERT_BOOLEAN); + + g_signal_connect_swapped ( + page->priv->type_combo, "changed", + G_CALLBACK (e_mail_config_page_changed), page); + + g_object_unref (tree_model); +} + +EMailConfigServiceBackend * +e_mail_config_service_page_get_active_backend (EMailConfigServicePage *page) +{ + g_return_val_if_fail (E_IS_MAIL_CONFIG_SERVICE_PAGE (page), NULL); + + return page->priv->active_backend; +} + +void +e_mail_config_service_page_set_active_backend (EMailConfigServicePage *page, + EMailConfigServiceBackend *backend) +{ + g_return_if_fail (E_IS_MAIL_CONFIG_SERVICE_PAGE (page)); + + if (backend != NULL) { + g_return_if_fail (E_IS_MAIL_CONFIG_SERVICE_BACKEND (backend)); + g_object_ref (backend); + } + + if (page->priv->active_backend != NULL) + g_object_unref (page->priv->active_backend); + + page->priv->active_backend = backend; + + g_object_notify (G_OBJECT (page), "active-backend"); +} + +const gchar * +e_mail_config_service_page_get_email_address (EMailConfigServicePage *page) +{ + g_return_val_if_fail (E_IS_MAIL_CONFIG_SERVICE_PAGE (page), NULL); + + return page->priv->email_address; +} + +void +e_mail_config_service_page_set_email_address (EMailConfigServicePage *page, + const gchar *email_address) +{ + g_return_if_fail (E_IS_MAIL_CONFIG_SERVICE_PAGE (page)); + + g_free (page->priv->email_address); + page->priv->email_address = g_strdup (email_address); + + g_object_notify (G_OBJECT (page), "email-address"); +} + +ESourceRegistry * +e_mail_config_service_page_get_registry (EMailConfigServicePage *page) +{ + g_return_val_if_fail (E_IS_MAIL_CONFIG_SERVICE_PAGE (page), NULL); + + return page->priv->registry; +} + +EMailConfigServiceBackend * +e_mail_config_service_page_add_scratch_source (EMailConfigServicePage *page, + ESource *scratch_source, + ESource *opt_collection) +{ + GtkWidget *widget; + GtkLabel *type_label; + GtkComboBox *type_combo; + GtkTreeIter iter; + Candidate *candidate; + const gchar *display_name; + gboolean selectable; + gint page_num; + + g_return_val_if_fail (E_IS_MAIL_CONFIG_SERVICE_PAGE (page), NULL); + g_return_val_if_fail (E_IS_SOURCE (scratch_source), NULL); + + if (opt_collection != NULL) + g_return_val_if_fail (E_IS_SOURCE (opt_collection), NULL); + + type_label = GTK_LABEL (page->priv->type_label); + type_combo = GTK_COMBO_BOX (page->priv->type_combo); + + candidate = mail_config_service_page_new_candidate ( + page, scratch_source, opt_collection); + g_return_val_if_fail (candidate != NULL, NULL); + + widget = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6); + e_mail_config_service_backend_insert_widgets ( + candidate->backend, GTK_BOX (widget)); + candidate->widget = g_object_ref_sink (widget); + gtk_widget_show (widget); + + g_ptr_array_add (page->priv->candidates, candidate); + + display_name = g_dgettext ( + candidate->provider->translation_domain, + candidate->provider->name); + + page_num = e_mail_config_service_notebook_add_page ( + E_MAIL_CONFIG_SERVICE_NOTEBOOK (page->priv->notebook), + candidate->backend, widget); + + selectable = e_mail_config_service_backend_get_selectable ( + candidate->backend); + + gtk_list_store_append (page->priv->list_store, &iter); + + gtk_list_store_set ( + page->priv->list_store, &iter, + COLUMN_BACKEND_NAME, candidate->name, + COLUMN_DISPLAY_NAME, display_name, + COLUMN_SELECTABLE, selectable, + -1); + + /* The type label is only visible if we have one scratch source, + * so just always set the label text to the most recently added + * scratch source. */ + gtk_label_set_text (type_label, display_name); + + /* If no combo box row is active yet, choose the new row. */ + if (gtk_combo_box_get_active_id (type_combo) == NULL) + gtk_combo_box_set_active_id (type_combo, candidate->name); + + /* If the page number of the newly-added notebook page is zero, + * show the "type" label. Otherwise show the "type" combo box. + * There's an inverted "visible" binding between the combo box + * and label, so we only need to change one of the widgets. */ + gtk_widget_set_visible (GTK_WIDGET (type_combo), page_num > 0); + + return candidate->backend; +} + +EMailConfigServiceBackend * +e_mail_config_service_page_lookup_backend (EMailConfigServicePage *page, + const gchar *backend_name) +{ + guint index; + + g_return_val_if_fail (E_IS_MAIL_CONFIG_SERVICE_PAGE (page), NULL); + g_return_val_if_fail (backend_name != NULL, NULL); + + for (index = 0; index < page->priv->candidates->len; index++) { + Candidate *candidate; + + candidate = page->priv->candidates->pdata[index]; + + if (g_strcmp0 (backend_name, candidate->name) == 0) + return candidate->backend; + } + + return NULL; +} + +EActivity * +e_mail_config_service_page_new_activity (EMailConfigServicePage *page) +{ + EActivity *activity; + EActivityBar *activity_bar; + GCancellable *cancellable; + + g_return_val_if_fail (E_IS_MAIL_CONFIG_SERVICE_PAGE (page), NULL); + + /* Clear any previous alerts. */ + e_alert_bar_clear (E_ALERT_BAR (page->priv->alert_bar)); + + activity = e_activity_new (); + + e_activity_set_alert_sink (activity, E_ALERT_SINK (page)); + + cancellable = camel_operation_new (); + e_activity_set_cancellable (activity, cancellable); + g_object_unref (cancellable); + + activity_bar = E_ACTIVITY_BAR (page->priv->activity_bar); + e_activity_bar_set_activity (activity_bar, activity); + + return activity; +} + +void +e_mail_config_service_page_auto_configure (EMailConfigServicePage *page, + EMailAutoconfig *autoconfig) +{ + EMailConfigServiceBackend *pop3 = NULL; + EMailConfigServiceBackend *imap = NULL; + EMailConfigServiceBackend *smtp = NULL; + guint ii; + + g_return_if_fail (E_IS_MAIL_CONFIG_SERVICE_PAGE (page)); + g_return_if_fail (E_IS_MAIL_AUTOCONFIG (autoconfig)); + + for (ii = 0; ii < page->priv->candidates->len; ii++) { + EMailConfigServiceBackendClass *class; + EMailConfigServiceBackend *backend; + Candidate *candidate; + gboolean configured; + + candidate = page->priv->candidates->pdata[ii]; + + backend = candidate->backend; + class = E_MAIL_CONFIG_SERVICE_BACKEND_GET_CLASS (backend); + + configured = e_mail_config_service_backend_auto_configure ( + backend, autoconfig); + + /* XXX There's a few specific backends to check for. + * It requires that we know about these backends, + * which violates the abstraction, but we need to + * break our own rule to be practical here. */ + if (g_strcmp0 (class->backend_name, POP3_BACKEND_NAME) == 0) + pop3 = configured ? backend : NULL; + if (g_strcmp0 (class->backend_name, IMAP_BACKEND_NAME) == 0) + imap = configured ? backend : NULL; + if (g_strcmp0 (class->backend_name, SMTP_BACKEND_NAME) == 0) + smtp = configured ? backend : NULL; + } + + /* Select POP3 before IMAP. If both are present we want IMAP. */ + if (pop3 != NULL) + e_mail_config_service_page_set_active_backend (page, pop3); + if (imap != NULL) + e_mail_config_service_page_set_active_backend (page, imap); + if (smtp != NULL) + e_mail_config_service_page_set_active_backend (page, smtp); +} + -- cgit