aboutsummaryrefslogblamecommitdiffstats
path: root/mail/e-mail-folder-create-dialog.c
blob: 019261475cee7c41aafee1f9b29008e7de6cf793 (plain) (tree)



































































































































































































































































































































                                                                                  
                                                                                        














































































                                                                            




                                                                                     

























































































                                                                                    
/*
 * e-mail-folder-create-dialog.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.
 *
 * 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 General Public License
 * for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
 *
 */

#include "e-mail-folder-create-dialog.h"

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

#include "em-vfolder-editor-rule.h"
#include "mail-vfolder-ui.h"

#define E_MAIL_FOLDER_CREATE_DIALOG_GET_PRIVATE(obj) \
    (G_TYPE_INSTANCE_GET_PRIVATE \
    ((obj), E_TYPE_MAIL_FOLDER_CREATE_DIALOG, EMailFolderCreateDialogPrivate))

typedef struct _AsyncContext AsyncContext;

struct _EMailFolderCreateDialogPrivate {
    EMailUISession *session;
    GtkWidget *name_entry;
};

struct _AsyncContext {
    EMailFolderCreateDialog *dialog;
    EActivity *activity;
};

enum {
    PROP_0,
    PROP_SESSION
};

enum {
    FOLDER_CREATED,
    LAST_SIGNAL
};

static guint signals[LAST_SIGNAL];

G_DEFINE_TYPE (
    EMailFolderCreateDialog,
    e_mail_folder_create_dialog,
    EM_TYPE_FOLDER_SELECTOR)

static void
async_context_free (AsyncContext *async_context)
{
    g_clear_object (&async_context->dialog);
    g_clear_object (&async_context->activity);

    g_slice_free (AsyncContext, async_context);
}

static void
mail_folder_create_dialog_create_folder_cb (GObject *source_object,
                                            GAsyncResult *result,
                                            gpointer user_data)
{
    EMailFolderCreateDialog *dialog;
    EActivity *activity;
    EAlertSink *alert_sink;
    GdkWindow *gdk_window;
    AsyncContext *async_context;
    GError *local_error = NULL;

    async_context = (AsyncContext *) user_data;

    dialog = async_context->dialog;
    activity = async_context->activity;
    alert_sink = e_activity_get_alert_sink (activity);

    /* Set the cursor back to normal. */
    gdk_window = gtk_widget_get_window (GTK_WIDGET (dialog));
    gdk_window_set_cursor (gdk_window, NULL);

    e_mail_store_create_folder_finish (
        CAMEL_STORE (source_object), result, &local_error);

    /* Ignore cancellations. */
    if (e_activity_handle_cancellation (activity, local_error)) {
        g_error_free (local_error);

    } else if (local_error != NULL) {
        e_alert_submit (
            alert_sink,
            "system:simple-error",
            local_error->message, NULL);
        g_error_free (local_error);

    } else {
        gtk_widget_destroy (GTK_WIDGET (dialog));
    }

    async_context_free (async_context);
}

static void
mail_folder_create_dialog_create_folder (EMailFolderCreateDialog *dialog)
{
    CamelStore *store = NULL;
    gchar *create_folder_name;
    gchar *parent_folder_name = NULL;
    const gchar *text;

    em_folder_selector_get_selected (
        EM_FOLDER_SELECTOR (dialog), &store, &parent_folder_name);

    g_return_if_fail (store != NULL);

    text = gtk_entry_get_text (GTK_ENTRY (dialog->priv->name_entry));

    if (parent_folder_name != NULL) {
        create_folder_name = g_strconcat (
            parent_folder_name, "/", text, NULL);
    } else {
        create_folder_name = g_strdup (text);
    }

    /* For the vfolder store, we just open the editor window. */
    if (CAMEL_IS_VEE_STORE (store)) {
        EMailUISession *session;
        EFilterRule *rule;

        session = e_mail_folder_create_dialog_get_session (dialog);
        rule = em_vfolder_editor_rule_new (E_MAIL_SESSION (session));
        e_filter_rule_set_name (rule, create_folder_name);
        vfolder_gui_add_rule (EM_VFOLDER_RULE (rule));

        gtk_widget_destroy (GTK_WIDGET (dialog));

    } else {
        AsyncContext *async_context;
        EActivity *activity;
        GCancellable *cancellable;
        GdkCursor *gdk_cursor;
        GdkWindow *gdk_window;

        /* Make the cursor appear busy. */
        gdk_cursor = gdk_cursor_new (GDK_WATCH);
        gdk_window = gtk_widget_get_window (GTK_WIDGET (dialog));
        gdk_window_set_cursor (gdk_window, gdk_cursor);
        g_object_unref (gdk_cursor);

        activity = em_folder_selector_new_activity (
            EM_FOLDER_SELECTOR (dialog));

        async_context = g_slice_new0 (AsyncContext);
        async_context->dialog = g_object_ref (dialog);
        async_context->activity = g_object_ref (activity);

        cancellable = e_activity_get_cancellable (activity);

        e_mail_store_create_folder (
            store, create_folder_name,
            G_PRIORITY_DEFAULT, cancellable,
            mail_folder_create_dialog_create_folder_cb,
            async_context);

        g_object_unref (activity);
    }

    g_free (create_folder_name);
    g_free (parent_folder_name);

    g_object_unref (store);
}

static gboolean
mail_folder_create_dialog_inputs_are_valid (EMailFolderCreateDialog *dialog)
{
    GtkEntry *entry;
    const gchar *original_text;
    gchar *stripped_text;
    gboolean folder_or_store_is_selected;
    gboolean inputs_are_valid;

    entry = GTK_ENTRY (dialog->priv->name_entry);

    original_text = gtk_entry_get_text (entry);
    stripped_text = e_util_strdup_strip (original_text);

    folder_or_store_is_selected =
        em_folder_selector_get_selected (
        EM_FOLDER_SELECTOR (dialog), NULL, NULL);

    inputs_are_valid =
        folder_or_store_is_selected &&
        (stripped_text != NULL) &&
        (strchr (stripped_text, '/') == NULL);

    g_free (stripped_text);

    return inputs_are_valid;
}

static void
mail_folder_create_dialog_entry_activate_cb (GtkEntry *entry,
                                             EMailFolderCreateDialog *dialog)
{
    if (mail_folder_create_dialog_inputs_are_valid (dialog))
        gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
}

static void
mail_folder_create_dialog_entry_changed_cb (GtkEntry *entry,
                                            EMailFolderCreateDialog *dialog)
{
    gtk_dialog_set_response_sensitive (
        GTK_DIALOG (dialog), GTK_RESPONSE_OK,
        mail_folder_create_dialog_inputs_are_valid (dialog));
}

static void
mail_folder_create_dialog_set_session (EMailFolderCreateDialog *dialog,
                                       EMailUISession *session)
{
    g_return_if_fail (E_IS_MAIL_UI_SESSION (session));
    g_return_if_fail (dialog->priv->session == NULL);

    dialog->priv->session = g_object_ref (session);
}

static void
mail_folder_create_dialog_set_property (GObject *object,
                                        guint property_id,
                                        const GValue *value,
                                        GParamSpec *pspec)
{
    switch (property_id) {
        case PROP_SESSION:
            mail_folder_create_dialog_set_session (
                E_MAIL_FOLDER_CREATE_DIALOG (object),
                g_value_get_object (value));
            return;
    }

    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}

static void
mail_folder_create_dialog_get_property (GObject *object,
                                        guint property_id,
                                        GValue *value,
                                        GParamSpec *pspec)
{
    switch (property_id) {
        case PROP_SESSION:
            g_value_set_object (
                value,
                e_mail_folder_create_dialog_get_session (
                E_MAIL_FOLDER_CREATE_DIALOG (object)));
            return;
    }

    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}

static void
mail_folder_create_dialog_dispose (GObject *object)
{
    EMailFolderCreateDialogPrivate *priv;

    priv = E_MAIL_FOLDER_CREATE_DIALOG_GET_PRIVATE (object);

    g_clear_object (&priv->session);
    g_clear_object (&priv->name_entry);

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

static void
mail_folder_create_dialog_constructed (GObject *object)
{
    EMailFolderCreateDialog *dialog;
    EMailAccountStore *account_store;
    EMailUISession *session;
    EMFolderTree *folder_tree;
    EMFolderTreeModel *model;
    GQueue queue = G_QUEUE_INIT;
    GtkWidget *container;
    GtkWidget *widget;
    GtkLabel *label;

    dialog = E_MAIL_FOLDER_CREATE_DIALOG (object);
    session = e_mail_folder_create_dialog_get_session (dialog);
    model = em_folder_selector_get_model (EM_FOLDER_SELECTOR (dialog));

    /* Populate the tree model before chaining up, since the
     * subclass will immediately try to restore the tree state. */

    account_store = e_mail_ui_session_get_account_store (session);
    e_mail_account_store_queue_enabled_services (account_store, &queue);

    while (!g_queue_is_empty (&queue)) {
        CamelService *service;
        CamelStoreFlags flags;

        service = g_queue_pop_head (&queue);
        g_warn_if_fail (CAMEL_IS_STORE (service));

        flags = CAMEL_STORE (service)->flags;
        if ((flags & CAMEL_STORE_CAN_EDIT_FOLDERS) == 0)
            continue;

        em_folder_tree_model_add_store (model, CAMEL_STORE (service));
    }

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

    gtk_window_set_title (GTK_WINDOW (dialog), _("Create Folder"));

    em_folder_selector_set_caption (
        EM_FOLDER_SELECTOR (dialog),
        _("Specify where to create the folder:"));

    em_folder_selector_set_default_button_label (
        EM_FOLDER_SELECTOR (dialog), _("C_reate"));

    folder_tree = em_folder_selector_get_folder_tree (
        EM_FOLDER_SELECTOR (dialog));
    em_folder_tree_set_excluded (folder_tree, EMFT_EXCLUDE_NOINFERIORS);

    /* Add a folder name entry field to the dialog. */

    container = em_folder_selector_get_content_area (
        EM_FOLDER_SELECTOR (dialog));

    widget = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
    gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
    gtk_widget_show (widget);

    container = widget;

    widget = gtk_label_new_with_mnemonic (_("Folder _name:"));
    gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
    gtk_widget_show (widget);

    label = GTK_LABEL (widget);

    widget = gtk_entry_new ();
    gtk_label_set_mnemonic_widget (label, widget);
    gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
    dialog->priv->name_entry = g_object_ref (widget);
    gtk_widget_grab_focus (widget);
    gtk_widget_show (widget);

    g_signal_connect (
        widget, "activate",
        G_CALLBACK (mail_folder_create_dialog_entry_activate_cb),
        dialog);

    g_signal_connect (
        widget, "changed",
        G_CALLBACK (mail_folder_create_dialog_entry_changed_cb),
        dialog);
}

static void
mail_folder_create_dialog_response (GtkDialog *dialog,
                                    gint response_id)
{
    /* Do not chain up.  GtkDialog does not implement this method. */

    switch (response_id) {
        case GTK_RESPONSE_OK:
            mail_folder_create_dialog_create_folder (
                E_MAIL_FOLDER_CREATE_DIALOG (dialog));
            break;
        case GTK_RESPONSE_CANCEL:
            gtk_widget_destroy (GTK_WIDGET (dialog));
            break;
        default:
            break;
    }
}

static void
mail_folder_create_dialog_folder_selected (EMFolderSelector *selector,
                                           CamelStore *store,
                                           const gchar *folder_name)
{
    EMailFolderCreateDialog *dialog;

    /* Do not chain up.  This overrides the subclass behavior. */

    dialog = E_MAIL_FOLDER_CREATE_DIALOG (selector);

    /* Can be NULL during dispose, when the folder tree model is being cleared */
    if (dialog->priv->name_entry)
        gtk_dialog_set_response_sensitive (
            GTK_DIALOG (dialog), GTK_RESPONSE_OK,
            mail_folder_create_dialog_inputs_are_valid (dialog));
}

static void
e_mail_folder_create_dialog_class_init (EMailFolderCreateDialogClass *class)
{
    GObjectClass *object_class;
    GtkDialogClass *dialog_class;
    EMFolderSelectorClass *selector_class;

    g_type_class_add_private (
        class, sizeof (EMailFolderCreateDialogPrivate));

    object_class = G_OBJECT_CLASS (class);
    object_class->set_property = mail_folder_create_dialog_set_property;
    object_class->get_property = mail_folder_create_dialog_get_property;
    object_class->dispose = mail_folder_create_dialog_dispose;
    object_class->constructed = mail_folder_create_dialog_constructed;

    dialog_class = GTK_DIALOG_CLASS (class);
    dialog_class->response = mail_folder_create_dialog_response;

    selector_class = EM_FOLDER_SELECTOR_CLASS (class);
    selector_class->folder_selected = mail_folder_create_dialog_folder_selected;

    g_object_class_install_property (
        object_class,
        PROP_SESSION,
        g_param_spec_object (
            "session",
            "Session",
            "An EMailUISession from which "
            "to list enabled mail stores",
            E_TYPE_MAIL_UI_SESSION,
            G_PARAM_READWRITE |
            G_PARAM_CONSTRUCT_ONLY |
            G_PARAM_STATIC_STRINGS));

    signals[FOLDER_CREATED] = g_signal_new (
        "folder-created",
        G_OBJECT_CLASS_TYPE (object_class),
        G_SIGNAL_RUN_LAST,
        G_STRUCT_OFFSET (EMailFolderCreateDialogClass, folder_created),
        NULL, NULL, NULL,
        G_TYPE_NONE, 2,
        CAMEL_TYPE_STORE,
        G_TYPE_STRING);
}

static void
e_mail_folder_create_dialog_init (EMailFolderCreateDialog *dialog)
{
    dialog->priv = E_MAIL_FOLDER_CREATE_DIALOG_GET_PRIVATE (dialog);
}

GtkWidget *
e_mail_folder_create_dialog_new (GtkWindow *parent,
                                 EMailUISession *session)
{
    GtkWidget *dialog;
    EMFolderTreeModel *model;

    g_return_val_if_fail (E_IS_MAIL_UI_SESSION (session), NULL);

    /* XXX The folder tree model is a construct-only property in
     *     EMFolderSelector, so create an empty model here and then
     *     populate it during instance initialization.  Already too
     *     much logic here for a "new" function, but works for now. */

    model = em_folder_tree_model_new ();
    em_folder_tree_model_set_session (model, E_MAIL_SESSION (session));

    dialog = g_object_new (
        E_TYPE_MAIL_FOLDER_CREATE_DIALOG,
        "transient-for", parent,
        "model", model,
        "session", session, NULL);

    g_object_unref (model);

    return dialog;
}

EMailUISession *
e_mail_folder_create_dialog_get_session (EMailFolderCreateDialog *dialog)
{
    g_return_val_if_fail (E_IS_MAIL_FOLDER_CREATE_DIALOG (dialog), NULL);

    return dialog->priv->session;
}