aboutsummaryrefslogblamecommitdiffstats
path: root/mail/e-mail-config-provider-page.c
blob: 81264babc6f89d16748ed30f20c7970b7cfe0b44 (plain) (tree)























                                                                             
                                    
 









                                                                                  







                          





                                                                              
                                         


                                        























































































































































































































                                                                            
                                                           


























































                                                                           
                                                           

























































                                                                        
                                                           






























































                                                                             
                             
                          





                                      

                








                                                                        

                                                                 
                                                                    


                                                                        






















































                                                                          










                                                                         




                                                                   



























                                                                         





























































































                                                                          

























                                                                                  





































                                                                                
/*
 * e-mail-config-provider-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 <http://www.gnu.org/licenses/>
 *
 */

#include "e-mail-config-provider-page.h"

#include <config.h>
#include <string.h>
#include <glib/gi18n-lib.h>

#include <libebackend/libebackend.h>

#define E_MAIL_CONFIG_PROVIDER_PAGE_GET_PRIVATE(obj) \
    (G_TYPE_INSTANCE_GET_PRIVATE \
    ((obj), E_TYPE_MAIL_CONFIG_PROVIDER_PAGE, EMailConfigProviderPagePrivate))

#define STANDARD_MARGIN   12
#define DEPENDENCY_MARGIN 24

struct _EMailConfigProviderPagePrivate {
    EMailConfigServiceBackend *backend;
    gboolean is_empty;
};

enum {
    PROP_0,
    PROP_BACKEND
};

/* Forward Declarations */
static void e_mail_config_provider_page_interface_init
                    (EMailConfigPageInterface *interface);

G_DEFINE_TYPE_WITH_CODE (
    EMailConfigProviderPage,
    e_mail_config_provider_page,
    E_TYPE_MAIL_CONFIG_ACTIVITY_PAGE,
    G_IMPLEMENT_INTERFACE (
        E_TYPE_EXTENSIBLE, NULL)
    G_IMPLEMENT_INTERFACE (
        E_TYPE_MAIL_CONFIG_PAGE,
        e_mail_config_provider_page_interface_init))

static void
mail_config_provider_page_handle_dependency (EMailConfigProviderPage *page,
                                             CamelProviderConfEntry *entry,
                                             GtkWidget *widget)
{
    EMailConfigServiceBackend *backend;
    CamelSettings *settings;
    GBindingFlags binding_flags = G_BINDING_SYNC_CREATE;
    const gchar *depname = entry->depname;
    gint margin;

    if (depname == NULL)
        return;

    if (*depname == '!') {
        binding_flags |= G_BINDING_INVERT_BOOLEAN;
        depname++;
    }

    backend = e_mail_config_provider_page_get_backend (page);
    settings = e_mail_config_service_backend_get_settings (backend);

    g_object_bind_property (
        settings, depname,
        widget, "sensitive",
        binding_flags);

    /* Further indent the widget to show its dependency. */
    margin = gtk_widget_get_margin_left (widget);
    gtk_widget_set_margin_left (widget, margin + DEPENDENCY_MARGIN);
}

static void
mail_config_provider_page_add_section (EMailConfigProviderPage *page,
                                       CamelProviderConfEntry *entry)
{
    EMailConfigServiceBackend *backend;
    CamelProvider *provider;
    GtkWidget *widget;
    gchar *markup;

    g_return_if_fail (entry->text != NULL);

    backend = e_mail_config_provider_page_get_backend (page);
    provider = e_mail_config_service_backend_get_provider (backend);

    markup = g_markup_printf_escaped ("<b>%s</b>", entry->text);

    widget = gtk_label_new (markup);
    gtk_label_set_use_markup (GTK_LABEL (widget), TRUE);
    gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
    gtk_box_pack_start (GTK_BOX (page), widget, FALSE, FALSE, 0);
    gtk_widget_show (widget);

    /* Skip the top margin if this is the first entry. */
    if (entry != provider->extra_conf)
        gtk_widget_set_margin_top (widget, 6);

    g_free (markup);
}

static void
mail_config_provider_page_add_checkbox (EMailConfigProviderPage *page,
                                        CamelProviderConfEntry *entry)
{
    EMailConfigServiceBackend *backend;
    CamelSettings *settings;
    GtkWidget *widget;

    g_return_if_fail (entry->text != NULL);

    backend = e_mail_config_provider_page_get_backend (page);
    settings = e_mail_config_service_backend_get_settings (backend);

    widget = gtk_check_button_new_with_mnemonic (entry->text);
    gtk_widget_set_margin_left (widget, STANDARD_MARGIN);
    gtk_box_pack_start (GTK_BOX (page), widget, FALSE, FALSE, 0);
    gtk_widget_show (widget);

    g_object_bind_property (
        settings, entry->name,
        widget, "active",
        G_BINDING_BIDIRECTIONAL |
        G_BINDING_SYNC_CREATE);

    mail_config_provider_page_handle_dependency (page, entry, widget);
}

static void
mail_config_provider_page_add_checkspin (EMailConfigProviderPage *page,
                                         CamelProviderConfEntry *entry)
{
    EMailConfigServiceBackend *backend;
    CamelSettings *settings;
    GObjectClass *class;
    GParamSpec *pspec;
    GParamSpec *use_pspec;
    GtkAdjustment *adjustment;
    GtkWidget *hbox, *spin;
    GtkWidget *prefix;
    gchar *use_property_name;
    gchar *pre, *post;

    g_return_if_fail (entry->text != NULL);

    backend = e_mail_config_provider_page_get_backend (page);
    settings = e_mail_config_service_backend_get_settings (backend);

    /* The entry->name property (e.g. "foo") should be numeric for the
     * spin button.  If a "use" boolean property exists (e.g. "use-foo")
     * then a checkbox is also shown. */

    class = G_OBJECT_GET_CLASS (settings);
    pspec = g_object_class_find_property (class, entry->name);
    g_return_if_fail (pspec != NULL);

    use_property_name = g_strconcat ("use-", entry->name, NULL);
    use_pspec = g_object_class_find_property (class, use_property_name);
    if (use_pspec != NULL && use_pspec->value_type != G_TYPE_BOOLEAN)
        use_pspec = NULL;
    g_free (use_property_name);

    /* Make sure we can convert to and from doubles. */
    g_return_if_fail (
        g_value_type_transformable (
        pspec->value_type, G_TYPE_DOUBLE));
    g_return_if_fail (
        g_value_type_transformable (
        G_TYPE_DOUBLE, pspec->value_type));

    if (G_IS_PARAM_SPEC_CHAR (pspec)) {
        GParamSpecChar *pspec_char;
        pspec_char = G_PARAM_SPEC_CHAR (pspec);
        adjustment = gtk_adjustment_new (
            (gdouble) pspec_char->default_value,
            (gdouble) pspec_char->minimum,
            (gdouble) pspec_char->maximum,
            1.0, 1.0, 0.0);

    } else if (G_IS_PARAM_SPEC_UCHAR (pspec)) {
        GParamSpecUChar *pspec_uchar;
        pspec_uchar = G_PARAM_SPEC_UCHAR (pspec);
        adjustment = gtk_adjustment_new (
            (gdouble) pspec_uchar->default_value,
            (gdouble) pspec_uchar->minimum,
            (gdouble) pspec_uchar->maximum,
            1.0, 1.0, 0.0);

    } else if (G_IS_PARAM_SPEC_INT (pspec)) {
        GParamSpecInt *pspec_int;
        pspec_int = G_PARAM_SPEC_INT (pspec);
        adjustment = gtk_adjustment_new (
            (gdouble) pspec_int->default_value,
            (gdouble) pspec_int->minimum,
            (gdouble) pspec_int->maximum,
            1.0, 1.0, 0.0);

    } else if (G_IS_PARAM_SPEC_UINT (pspec)) {
        GParamSpecUInt *pspec_uint;
        pspec_uint = G_PARAM_SPEC_UINT (pspec);
        adjustment = gtk_adjustment_new (
            (gdouble) pspec_uint->default_value,
            (gdouble) pspec_uint->minimum,
            (gdouble) pspec_uint->maximum,
            1.0, 1.0, 0.0);

    } else if (G_IS_PARAM_SPEC_LONG (pspec)) {
        GParamSpecLong *pspec_long;
        pspec_long = G_PARAM_SPEC_LONG (pspec);
        adjustment = gtk_adjustment_new (
            (gdouble) pspec_long->default_value,
            (gdouble) pspec_long->minimum,
            (gdouble) pspec_long->maximum,
            1.0, 1.0, 0.0);

    } else if (G_IS_PARAM_SPEC_ULONG (pspec)) {
        GParamSpecULong *pspec_ulong;
        pspec_ulong = G_PARAM_SPEC_ULONG (pspec);
        adjustment = gtk_adjustment_new (
            (gdouble) pspec_ulong->default_value,
            (gdouble) pspec_ulong->minimum,
            (gdouble) pspec_ulong->maximum,
            1.0, 1.0, 0.0);

    } else if (G_IS_PARAM_SPEC_FLOAT (pspec)) {
        GParamSpecFloat *pspec_float;
        pspec_float = G_PARAM_SPEC_FLOAT (pspec);
        adjustment = gtk_adjustment_new (
            (gdouble) pspec_float->default_value,
            (gdouble) pspec_float->minimum,
            (gdouble) pspec_float->maximum,
            1.0, 1.0, 0.0);

    } else if (G_IS_PARAM_SPEC_DOUBLE (pspec)) {
        GParamSpecDouble *pspec_double;
        pspec_double = G_PARAM_SPEC_DOUBLE (pspec);
        adjustment = gtk_adjustment_new (
            (gdouble) pspec_double->default_value,
            (gdouble) pspec_double->minimum,
            (gdouble) pspec_double->maximum,
            1.0, 1.0, 0.0);

    } else
        g_return_if_reached ();

    pre = g_alloca (strlen (entry->text) + 1);
    strcpy (pre, entry->text);
    post = strstr (pre, "%s");
    if (post != NULL) {
        *post = '\0';
        post += 2;
    }

    hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 3);
    gtk_widget_set_margin_left (hbox, STANDARD_MARGIN);
    gtk_box_pack_start (GTK_BOX (page), hbox, FALSE, FALSE, 0);
    gtk_widget_show (hbox);

    if (use_pspec != NULL) {
        prefix = gtk_check_button_new_with_mnemonic (pre);

        g_object_bind_property (
            settings, use_pspec->name,
            prefix, "active",
            G_BINDING_BIDIRECTIONAL |
            G_BINDING_SYNC_CREATE);
    } else {
        prefix = gtk_label_new_with_mnemonic (pre);
    }
    gtk_box_pack_start (GTK_BOX (hbox), prefix, FALSE, TRUE, 0);
    gtk_widget_show (prefix);

    spin = gtk_spin_button_new (adjustment, 1.0, 0);
    gtk_box_pack_start (GTK_BOX (hbox), spin, FALSE, TRUE, 0);
    gtk_widget_show (spin);

    g_object_bind_property (
        settings, entry->name,
        spin, "value",
        G_BINDING_BIDIRECTIONAL |
        G_BINDING_SYNC_CREATE);

    if (use_pspec != NULL)
        g_object_bind_property (
            prefix, "active",
            spin, "sensitive",
            G_BINDING_SYNC_CREATE);

    if (post != NULL) {
        GtkWidget *label = gtk_label_new_with_mnemonic (post);
        gtk_label_set_mnemonic_widget (GTK_LABEL (label), prefix);
        gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0);
        gtk_widget_show (label);
    }

    mail_config_provider_page_handle_dependency (page, entry, hbox);
}

static void
mail_config_provider_page_add_entry (EMailConfigProviderPage *page,
                                     CamelProviderConfEntry *entry)
{
    EMailConfigServiceBackend *backend;
    CamelSettings *settings;
    GtkWidget *hbox;
    GtkWidget *input;
    GtkWidget *label;

    g_return_if_fail (entry->text != NULL);

    backend = e_mail_config_provider_page_get_backend (page);
    settings = e_mail_config_service_backend_get_settings (backend);

    hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
    gtk_box_set_spacing (GTK_BOX (hbox), 6);
    gtk_widget_set_margin_left (hbox, STANDARD_MARGIN);
    gtk_box_pack_start (GTK_BOX (page), hbox, FALSE, FALSE, 0);
    gtk_widget_show (hbox);

    label = gtk_label_new_with_mnemonic (entry->text);
    gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
    gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
    gtk_widget_show (label);

    input = gtk_entry_new ();
    gtk_label_set_mnemonic_widget (GTK_LABEL (label), input);
    gtk_box_pack_start (GTK_BOX (hbox), input, TRUE, TRUE, 0);
    gtk_widget_show (input);

    g_object_bind_property (
        settings, entry->name,
        input, "text",
        G_BINDING_BIDIRECTIONAL |
        G_BINDING_SYNC_CREATE);

    g_object_bind_property (
        input, "sensitive",
        label, "sensitive",
        G_BINDING_SYNC_CREATE);

    mail_config_provider_page_handle_dependency (page, entry, hbox);
}

static void
mail_config_provider_page_add_options (EMailConfigProviderPage *page,
                                       CamelProviderConfEntry *entry)
{
    EMailConfigServiceBackend *backend;
    CamelProvider *provider;
    CamelSettings *settings;
    GtkCellRenderer *renderer;
    GtkListStore *store;
    GtkWidget *hbox;
    GtkWidget *combo;
    GtkWidget *label;
    gchar **tokens;
    guint length, ii;

    /* The 'value' string is of the format:
     *
     *   'nick0:caption0:nick1:caption1:...nickN:captionN'
     *
     * where 'nick' is the nickname a GEnumValue and 'caption'
     * is the localized combo box item displayed to the user. */

    g_return_if_fail (entry->text != NULL);
    g_return_if_fail (entry->value != NULL);

    backend = e_mail_config_provider_page_get_backend (page);
    provider = e_mail_config_service_backend_get_provider (backend);
    settings = e_mail_config_service_backend_get_settings (backend);

    hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
    gtk_box_set_spacing (GTK_BOX (hbox), 6);
    gtk_widget_set_margin_left (hbox, STANDARD_MARGIN);
    gtk_box_pack_start (GTK_BOX (page), hbox, FALSE, FALSE, 0);
    gtk_widget_show (hbox);

    label = gtk_label_new_with_mnemonic (entry->text);
    gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
    gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
    gtk_widget_show (label);

    /* 0: 'nick', 1: caption */
    store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);

    tokens = g_strsplit (entry->value, ":", -1);
    length = g_strv_length (tokens);

    /* Take the strings two at a time. */
    for (ii = 0; ii + 1 < length; ii += 2) {
        GtkTreeIter iter;
        const gchar *nick;
        const gchar *caption;

        nick = tokens[ii + 0];
        caption = tokens[ii + 1];

        /* Localize the caption. */
        caption = dgettext (provider->translation_domain, caption);

        gtk_list_store_append (store, &iter);
        gtk_list_store_set (store, &iter, 0, nick, 1, caption, -1);
    }

    g_strfreev (tokens);

    combo = gtk_combo_box_new_with_model (GTK_TREE_MODEL (store));
    gtk_combo_box_set_id_column (GTK_COMBO_BOX (combo), 0);
    gtk_label_set_mnemonic_widget (GTK_LABEL (label), combo);
    gtk_box_pack_start (GTK_BOX (hbox), combo, FALSE, FALSE, 0);
    gtk_widget_show (combo);

    g_object_bind_property_full (
        settings, entry->name,
        combo, "active-id",
        G_BINDING_BIDIRECTIONAL |
        G_BINDING_SYNC_CREATE,
        e_binding_transform_enum_value_to_nick,
        e_binding_transform_enum_nick_to_value,
        NULL, (GDestroyNotify) NULL);

    renderer = gtk_cell_renderer_text_new ();
    gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), renderer, TRUE);
    gtk_cell_layout_set_attributes (
        GTK_CELL_LAYOUT (combo), renderer, "text", 1, NULL);

    mail_config_provider_page_handle_dependency (page, entry, hbox);
}

static void
mail_config_provider_page_add_widgets (EMailConfigProviderPage *page)
{
    EMailConfigServiceBackend *backend;
    CamelProviderConfEntry *entries;
    CamelProvider *provider;
    GtkWidget *container;
    GtkWidget *widget;
    ESource *source;
    ESourceExtension *extension;
    gboolean first_section = TRUE;
    const gchar *extension_name;
    const gchar *text;
    gchar *markup;
    gint ii;

    /* XXX We begin the page with our own section header and refresh
     *     interval setting, and then skip the CamelProvider's first
     *     CAMEL_PROVIDER_CONF_SECTION_START entry.
     *
     *     This is all very brittle.  I'm convinced that generating
     *     a user interface from an array of records like this is a
     *     bad idea.  We already have EMailConfigServiceBackend for
     *     building provider-specific "Receving Email" and "Sending
     *     EMail" pages by hand.  We should do similarly here. */

    backend = e_mail_config_provider_page_get_backend (page);
    source = e_mail_config_service_backend_get_source (backend);
    provider = e_mail_config_service_backend_get_provider (backend);
    g_return_if_fail (provider != NULL);

    /* XXX I guess refresh options go in the mail account source,
     *     even if the source is part of a collection.  I did not
     *     think about it too hard, so hopefully this is right. */
    extension_name = E_SOURCE_EXTENSION_REFRESH;
    extension = e_source_get_extension (source, extension_name);

    text = _("Checking for New Mail");
    markup = g_markup_printf_escaped ("<b>%s</b>", text);
    widget = gtk_label_new (markup);
    gtk_label_set_use_markup (GTK_LABEL (widget), TRUE);
    gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
    gtk_box_pack_start (GTK_BOX (page), widget, FALSE, FALSE, 0);
    gtk_widget_show (widget);
    g_free (markup);

    widget = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
    gtk_widget_set_margin_left (widget, STANDARD_MARGIN);
    gtk_box_pack_start (GTK_BOX (page), widget, FALSE, FALSE, 0);
    gtk_widget_show (widget);

    container = widget;

    text = _("Check for _new messages every");
    widget = gtk_check_button_new_with_mnemonic (text);
    gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
    gtk_widget_show (widget);

    g_object_bind_property (
        extension, "enabled",
        widget, "active",
        G_BINDING_BIDIRECTIONAL |
        G_BINDING_SYNC_CREATE);

    widget = gtk_spin_button_new_with_range (1.0, 1440.0, 1.0);
    gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
    gtk_widget_show (widget);

    g_object_bind_property (
        extension, "enabled",
        widget, "sensitive",
        G_BINDING_SYNC_CREATE);

    g_object_bind_property (
        extension, "interval-minutes",
        widget, "value",
        G_BINDING_BIDIRECTIONAL |
        G_BINDING_SYNC_CREATE);

    widget = gtk_label_new (_("minutes"));
    gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
    gtk_widget_show (widget);

    /* Note the "text" member of each CamelProviderConfEntry is
     * already localized, so we can use it directly in widgets. */

    entries = provider->extra_conf;

    /* Loop until we see CAMEL_PROVIDER_CONF_END. */
    for (ii = 0; entries[ii].type != CAMEL_PROVIDER_CONF_END; ii++) {

        /* Skip entries with no name. */
        if (entries[ii].name == NULL)
            continue;

        switch (entries[ii].type) {
            case CAMEL_PROVIDER_CONF_SECTION_START:
                /* Skip the first section start. */
                if (first_section) {
                    first_section = FALSE;
                    continue;
                }
                mail_config_provider_page_add_section (
                    page, &entries[ii]);
                break;

            case CAMEL_PROVIDER_CONF_CHECKBOX:
                mail_config_provider_page_add_checkbox (
                    page, &entries[ii]);
                break;

            case CAMEL_PROVIDER_CONF_CHECKSPIN:
                mail_config_provider_page_add_checkspin (
                    page, &entries[ii]);
                break;

            case CAMEL_PROVIDER_CONF_ENTRY:
                mail_config_provider_page_add_entry (
                    page, &entries[ii]);
                break;

            case CAMEL_PROVIDER_CONF_OPTIONS:
                mail_config_provider_page_add_options (
                    page, &entries[ii]);
                break;

            default:
                break;  /* skip it */
        }
    }
}

static void
mail_config_provider_page_set_backend (EMailConfigProviderPage *page,
                                       EMailConfigServiceBackend *backend)
{
    g_return_if_fail (E_IS_MAIL_CONFIG_SERVICE_BACKEND (backend));
    g_return_if_fail (page->priv->backend == NULL);

    page->priv->backend = g_object_ref (backend);
}

static void
mail_config_provider_page_set_property (GObject *object,
                                        guint property_id,
                                        const GValue *value,
                                        GParamSpec *pspec)
{
    switch (property_id) {
        case PROP_BACKEND:
            mail_config_provider_page_set_backend (
                E_MAIL_CONFIG_PROVIDER_PAGE (object),
                g_value_get_object (value));
            return;
    }

    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}

static void
mail_config_provider_page_get_property (GObject *object,
                                        guint property_id,
                                        GValue *value,
                                        GParamSpec *pspec)
{
    switch (property_id) {
        case PROP_BACKEND:
            g_value_set_object (
                value,
                e_mail_config_provider_page_get_backend (
                E_MAIL_CONFIG_PROVIDER_PAGE (object)));
            return;
    }

    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}

static void
mail_config_provider_page_dispose (GObject *object)
{
    EMailConfigProviderPagePrivate *priv;

    priv = E_MAIL_CONFIG_PROVIDER_PAGE_GET_PRIVATE (object);

    if (priv->backend != NULL) {
        g_object_unref (priv->backend);
        priv->backend = NULL;
    }

    /* Chain up parent's dispose() method. */
    G_OBJECT_CLASS (e_mail_config_provider_page_parent_class)->
        dispose (object);
}

static void
mail_config_provider_page_constructed (GObject *object)
{
    EMailConfigProviderPage *page;
    EMailConfigServiceBackend *backend;
    CamelProvider *provider;

    page = E_MAIL_CONFIG_PROVIDER_PAGE (object);

    /* Chain up parent's constructed() method. */
    G_OBJECT_CLASS (e_mail_config_provider_page_parent_class)->
        constructed (object);

    gtk_box_set_spacing (GTK_BOX (object), 6);

    gtk_orientable_set_orientation (
        GTK_ORIENTABLE (object), GTK_ORIENTATION_VERTICAL);

    backend = e_mail_config_provider_page_get_backend (page);
    provider = e_mail_config_service_backend_get_provider (backend);

    if (provider != NULL && provider->extra_conf != NULL)
        mail_config_provider_page_add_widgets (page);
    else
        page->priv->is_empty = TRUE;

    e_extensible_load_extensions (E_EXTENSIBLE (page));
}

static void
e_mail_config_provider_page_class_init (EMailConfigProviderPageClass *class)
{
    GObjectClass *object_class;

    g_type_class_add_private (class, sizeof (EMailConfigProviderPagePrivate));

    object_class = G_OBJECT_CLASS (class);
    object_class->set_property = mail_config_provider_page_set_property;
    object_class->get_property = mail_config_provider_page_get_property;
    object_class->dispose = mail_config_provider_page_dispose;
    object_class->constructed = mail_config_provider_page_constructed;

    g_object_class_install_property (
        object_class,
        PROP_BACKEND,
        g_param_spec_object (
            "backend",
            "Backend",
            "Service backend to generate options from",
            E_TYPE_MAIL_CONFIG_SERVICE_BACKEND,
            G_PARAM_READWRITE |
            G_PARAM_CONSTRUCT_ONLY |
            G_PARAM_STATIC_STRINGS));
}

static void
e_mail_config_provider_page_interface_init (EMailConfigPageInterface *interface)
{
    interface->title = _("Receiving Options");
    interface->sort_order = E_MAIL_CONFIG_PROVIDER_PAGE_SORT_ORDER;
}

static void
e_mail_config_provider_page_init (EMailConfigProviderPage *page)
{
    page->priv = E_MAIL_CONFIG_PROVIDER_PAGE_GET_PRIVATE (page);
}

EMailConfigPage *
e_mail_config_provider_page_new (EMailConfigServiceBackend *backend)
{
    g_return_val_if_fail (E_IS_MAIL_CONFIG_SERVICE_BACKEND (backend), NULL);

    return g_object_new (
        E_TYPE_MAIL_CONFIG_PROVIDER_PAGE,
        "backend", backend, NULL);
}

gboolean
e_mail_config_provider_page_is_empty (EMailConfigProviderPage *page)
{
    g_return_val_if_fail (E_IS_MAIL_CONFIG_PROVIDER_PAGE (page), TRUE);

    return page->priv->is_empty;
}

EMailConfigServiceBackend *
e_mail_config_provider_page_get_backend (EMailConfigProviderPage *page)
{
    g_return_val_if_fail (E_IS_MAIL_CONFIG_PROVIDER_PAGE (page), NULL);

    return page->priv->backend;
}