diff options
Diffstat (limited to 'mail/em-folder-properties.c')
-rw-r--r-- | mail/em-folder-properties.c | 546 |
1 files changed, 546 insertions, 0 deletions
diff --git a/mail/em-folder-properties.c b/mail/em-folder-properties.c new file mode 100644 index 0000000000..d50888fea9 --- /dev/null +++ b/mail/em-folder-properties.c @@ -0,0 +1,546 @@ +/* + * 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/> + * + * + * Authors: + * Michael Zucchi <notzed@ximian.com> + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "em-folder-properties.h" + +#include <string.h> + +#include <gtk/gtk.h> +#include <glib/gi18n.h> + +#include <libemail-engine/e-mail-folder-utils.h> +#include <libemail-engine/mail-mt.h> +#include <libemail-engine/mail-ops.h> + +#include "e-mail-backend.h" +#include "e-mail-ui-session.h" +#include "em-config.h" +#include "mail-vfolder-ui.h" + +typedef struct _AsyncContext AsyncContext; + +struct _AsyncContext { + EActivity *activity; + CamelFolder *folder; + GtkWindow *parent_window; + CamelFolderQuotaInfo *quota_info; + gint total; + gint unread; +}; + +static void +async_context_free (AsyncContext *context) +{ + if (context->activity != NULL) + g_object_unref (context->activity); + + if (context->folder != NULL) + g_object_unref (context->folder); + + if (context->parent_window != NULL) + g_object_unref (context->parent_window); + + if (context->quota_info != NULL) + camel_folder_quota_info_free (context->quota_info); + + g_slice_free (AsyncContext, context); +} + +static void +emfp_free (EConfig *ec, + GSList *items, + gpointer data) +{ + g_slist_free (items); +} + +static gint +add_numbered_row (GtkTable *table, + gint row, + const gchar *description, + const gchar *format, + gint num) +{ + gchar *str; + GtkWidget *label; + + g_return_val_if_fail (table != NULL, row); + g_return_val_if_fail (description != NULL, row); + g_return_val_if_fail (format != NULL, row); + + label = gtk_label_new (description); + gtk_widget_show (label); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_table_attach ( + table, label, 0, 1, row, row + 1, + GTK_FILL, 0, 0, 0); + + str = g_strdup_printf (format, num); + + label = gtk_label_new (str); + gtk_widget_show (label); + gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5); + gtk_table_attach ( + table, label, 1, 2, row, row + 1, + GTK_FILL | GTK_EXPAND, 0, 0, 0); + + g_free (str); + + return row + 1; +} + +static GtkWidget * +emfp_get_folder_item (EConfig *ec, + EConfigItem *item, + GtkWidget *parent, + GtkWidget *old, + gint position, + gpointer data) +{ + GObjectClass *class; + GParamSpec **properties; + GtkWidget *widget, *table; + AsyncContext *context = data; + guint ii, n_properties; + gint row = 0; + gboolean can_apply_filters = FALSE; + + if (old) + return old; + + table = gtk_table_new (2, 2, FALSE); + gtk_table_set_row_spacings ((GtkTable *) table, 6); + gtk_table_set_col_spacings ((GtkTable *) table, 12); + gtk_widget_show (table); + gtk_box_pack_start ((GtkBox *) parent, table, TRUE, TRUE, 0); + + /* To be on the safe side, ngettext is used here, + * see e.g. comment #3 at bug 272567 */ + row = add_numbered_row ( + GTK_TABLE (table), row, + ngettext ( + "Unread messages:", + "Unread messages:", + context->unread), + "%d", context->unread); + + /* TODO: can this be done in a loop? */ + /* To be on the safe side, ngettext is used here, + * see e.g. comment #3 at bug 272567 */ + row = add_numbered_row ( + GTK_TABLE (table), row, + ngettext ( + "Total messages:", + "Total messages:", + context->total), + "%d", context->total); + + if (context->quota_info) { + CamelFolderQuotaInfo *info; + CamelFolderQuotaInfo *quota = context->quota_info; + + for (info = quota; info; info = info->next) { + gchar *descr; + gint procs; + + /* should not happen, but anyway... */ + if (!info->total) + continue; + + /* Show quota name only when available and we + * have more than one quota info. */ + if (info->name && quota->next) + descr = g_strdup_printf ( + _("Quota usage (%s):"), _(info->name)); + else + descr = g_strdup_printf (_("Quota usage")); + + procs = (gint) ((((gdouble) info->used) / + ((gdouble) info->total)) * 100.0 + 0.5); + + row = add_numbered_row ( + GTK_TABLE (table), row, + descr, "%d%%", procs); + + g_free (descr); + } + } + + if (context->folder != NULL) { + CamelStore *store; + CamelSession *session; + CamelFolderInfoFlags fi_flags = 0; + const gchar *folder_name; + MailFolderCache *folder_cache; + gboolean have_flags; + + store = camel_folder_get_parent_store (context->folder); + folder_name = camel_folder_get_full_name (context->folder); + + session = camel_service_ref_session (CAMEL_SERVICE (store)); + + folder_cache = e_mail_session_get_folder_cache ( + E_MAIL_SESSION (session)); + + have_flags = mail_folder_cache_get_folder_info_flags ( + folder_cache, store, folder_name, &fi_flags); + + can_apply_filters = + !CAMEL_IS_VEE_FOLDER (context->folder) && + have_flags && + (fi_flags & CAMEL_FOLDER_TYPE_MASK) != CAMEL_FOLDER_TYPE_INBOX; + + g_object_unref (session); + } + + class = G_OBJECT_GET_CLASS (context->folder); + properties = g_object_class_list_properties (class, &n_properties); + + for (ii = 0; ii < n_properties; ii++) { + const gchar *blurb; + + if ((properties[ii]->flags & CAMEL_PARAM_PERSISTENT) == 0) + continue; + + if (!can_apply_filters && + g_strcmp0 (properties[ii]->name, "apply-filters") == 0) + continue; + + blurb = g_param_spec_get_blurb (properties[ii]); + + switch (properties[ii]->value_type) { + case G_TYPE_BOOLEAN: + widget = gtk_check_button_new_with_mnemonic (blurb); + g_object_bind_property ( + context->folder, + properties[ii]->name, + widget, "active", + G_BINDING_BIDIRECTIONAL | + G_BINDING_SYNC_CREATE); + gtk_widget_show (widget); + gtk_table_attach ( + GTK_TABLE (table), widget, + 0, 2, row, row + 1, + GTK_FILL | GTK_EXPAND, 0, 0, 0); + row++; + break; + default: + g_warn_if_reached (); + break; + } + } + + g_free (properties); + + return table; +} + +#define EMFP_FOLDER_SECTION (2) + +static EMConfigItem emfp_items[] = { + { E_CONFIG_BOOK, (gchar *) "", NULL }, + { E_CONFIG_PAGE, (gchar *) "00.general", + (gchar *) N_("General") }, + { E_CONFIG_SECTION, (gchar *) "00.general/00.folder", + NULL /* set by code */ }, + { E_CONFIG_ITEM, (gchar *) "00.general/00.folder/00.info", + NULL, emfp_get_folder_item }, +}; +static gboolean emfp_items_translated = FALSE; + +static void +emfp_dialog_run (AsyncContext *context) +{ + GtkWidget *dialog, *w; + GtkWidget *content_area; + GSList *l; + gint32 i,deleted; + EMConfig *ec; + EMConfigTargetFolder *target; + CamelStore *parent_store; + CamelFolderSummary *summary; + gboolean store_is_local; + gboolean hide_deleted; + GSettings *settings; + const gchar *name; + const gchar *uid; + + parent_store = camel_folder_get_parent_store (context->folder); + + /* Get number of VISIBLE and DELETED messages, instead of TOTAL + * messages. VISIBLE+DELETED gives the correct count that matches + * the label below the Send & Receive button. */ + summary = context->folder->summary; + context->total = camel_folder_summary_get_visible_count (summary); + context->unread = camel_folder_summary_get_unread_count (summary); + deleted = camel_folder_summary_get_deleted_count (summary); + + settings = g_settings_new ("org.gnome.evolution.mail"); + hide_deleted = !g_settings_get_boolean (settings, "show-deleted"); + g_object_unref (settings); + + /* + * Do the calculation only for those accounts that support VTRASHes + */ + if (parent_store->flags & CAMEL_STORE_VTRASH) { + if (CAMEL_IS_VTRASH_FOLDER (context->folder)) + context->total += deleted; + else if (!hide_deleted && deleted > 0) + context->total += deleted; + } + + /* + * If the folder is junk folder, get total number of mails. + */ + if (parent_store->flags & CAMEL_STORE_VJUNK) + context->total = camel_folder_summary_count ( + context->folder->summary); + + name = camel_folder_get_display_name (context->folder); + + uid = camel_service_get_uid (CAMEL_SERVICE (parent_store)); + store_is_local = (g_strcmp0 (uid, E_MAIL_SESSION_LOCAL_UID) == 0); + + if (store_is_local + && (!strcmp (name, "Drafts") + || !strcmp (name, "Templates") + || !strcmp (name, "Inbox") + || !strcmp (name, "Outbox") + || !strcmp (name, "Sent"))) { + emfp_items[EMFP_FOLDER_SECTION].label = gettext (name); + if (!emfp_items_translated) { + for (i = 0; i < G_N_ELEMENTS (emfp_items); i++) { + if (emfp_items[i].label) + emfp_items[i].label = _(emfp_items[i].label); + } + emfp_items_translated = TRUE; + } + } else if (!strcmp (name, "INBOX")) + emfp_items[EMFP_FOLDER_SECTION].label = _("Inbox"); + else + emfp_items[EMFP_FOLDER_SECTION].label = (gchar *) name; + + dialog = gtk_dialog_new_with_buttons ( + _("Folder Properties"), + context->parent_window, + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_STOCK_CLOSE, GTK_RESPONSE_OK, NULL); + gtk_window_set_default_size ((GtkWindow *) dialog, 192, 160); + + gtk_widget_ensure_style (dialog); + + content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog)); + gtk_container_set_border_width (GTK_CONTAINER (content_area), 12); + + /** @HookPoint-EMConfig: Folder Properties Window + * @Id: org.gnome.evolution.mail.folderConfig + * @Type: E_CONFIG_BOOK + * @Class: org.gnome.evolution.mail.config:1.0 + * @Target: EMConfigTargetFolder + * + * The folder properties window. + */ + ec = em_config_new ("org.gnome.evolution.mail.folderConfig"); + l = NULL; + for (i = 0; i < G_N_ELEMENTS (emfp_items); i++) + l = g_slist_prepend (l, &emfp_items[i]); + e_config_add_items ((EConfig *) ec, l, emfp_free, context); + + target = em_config_target_new_folder (ec, context->folder); + + e_config_set_target ((EConfig *) ec, (EConfigTarget *) target); + w = e_config_create_widget ((EConfig *) ec); + + gtk_box_pack_start (GTK_BOX (content_area), w, TRUE, TRUE, 0); + + /* We do 'apply on ok', since instant apply may start some + * very long running tasks. */ + + if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) { + e_config_commit ((EConfig *) ec); + camel_object_state_write (CAMEL_OBJECT (context->folder)); + } else + e_config_abort ((EConfig *) ec); + + gtk_widget_destroy (dialog); +} + +static void +emfp_dialog_got_quota_info (CamelFolder *folder, + GAsyncResult *result, + AsyncContext *context) +{ + EAlertSink *alert_sink; + GError *error = NULL; + + alert_sink = e_activity_get_alert_sink (context->activity); + + context->quota_info = + camel_folder_get_quota_info_finish (folder, result, &error); + + /* If the folder does not implement quota info, just continue. */ + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED)) { + g_warn_if_fail (context->quota_info == NULL); + g_error_free (error); + + } else if (e_activity_handle_cancellation (context->activity, error)) { + g_warn_if_fail (context->quota_info == NULL); + async_context_free (context); + g_error_free (error); + return; + + /* FIXME Add an EAlert for failing to get quota info. */ + } else if (error != NULL) { + g_warn_if_fail (context->folder == NULL); + e_alert_submit ( + alert_sink, "mail:folder-open", + error->message, NULL); + async_context_free (context); + g_error_free (error); + return; + } + + /* Quota info may still be NULL here if not supported. */ + + /* Finalize the activity here so we don't leave a message + * in the task bar while the properties window is shown. */ + e_activity_set_state (context->activity, E_ACTIVITY_COMPLETED); + g_object_unref (context->activity); + context->activity = NULL; + + emfp_dialog_run (context); + + async_context_free (context); +} + +static void +emfp_dialog_got_folder (CamelStore *store, + GAsyncResult *result, + AsyncContext *context) +{ + EAlertSink *alert_sink; + GCancellable *cancellable; + GError *error = NULL; + + alert_sink = e_activity_get_alert_sink (context->activity); + cancellable = e_activity_get_cancellable (context->activity); + + context->folder = camel_store_get_folder_finish ( + store, result, &error); + + if (e_activity_handle_cancellation (context->activity, error)) { + g_warn_if_fail (context->folder == NULL); + async_context_free (context); + g_error_free (error); + return; + + } else if (error != NULL) { + g_warn_if_fail (context->folder == NULL); + e_alert_submit ( + alert_sink, "mail:folder-open", + error->message, NULL); + async_context_free (context); + g_error_free (error); + return; + } + + g_return_if_fail (CAMEL_IS_FOLDER (context->folder)); + + camel_folder_get_quota_info ( + context->folder, G_PRIORITY_DEFAULT, cancellable, + (GAsyncReadyCallback) emfp_dialog_got_quota_info, context); +} + +/** + * em_folder_properties_show: + * @store: a #CamelStore + * @folder_name: a folder name + * @alert_sink: an #EAlertSink + * @parent_window: a parent #GtkWindow + * + * Show folder properties for @folder_name. + **/ +void +em_folder_properties_show (CamelStore *store, + const gchar *folder_name, + EAlertSink *alert_sink, + GtkWindow *parent_window) +{ + CamelService *service; + CamelSession *session; + GCancellable *cancellable; + AsyncContext *context; + const gchar *uid; + + g_return_if_fail (CAMEL_IS_STORE (store)); + g_return_if_fail (folder_name != NULL); + g_return_if_fail (E_IS_ALERT_SINK (alert_sink)); + g_return_if_fail (GTK_IS_WINDOW (parent_window)); + + service = CAMEL_SERVICE (store); + uid = camel_service_get_uid (service); + session = camel_service_ref_session (service); + + /* Show the Edit Rule dialog for Search Folders, but not "Unmatched". + * "Unmatched" is a special Search Folder which can't be modified. */ + if (g_strcmp0 (uid, E_MAIL_SESSION_VFOLDER_UID) == 0) { + if (g_strcmp0 (folder_name, CAMEL_UNMATCHED_NAME) != 0) { + gchar *folder_uri; + + folder_uri = e_mail_folder_uri_build ( + store, folder_name); + vfolder_edit_rule ( + E_MAIL_SESSION (session), + folder_uri, alert_sink); + g_free (folder_uri); + + goto exit; + } + } + + /* Open the folder asynchronously. */ + + context = g_slice_new0 (AsyncContext); + context->activity = e_activity_new (); + context->parent_window = g_object_ref (parent_window); + + e_activity_set_alert_sink (context->activity, alert_sink); + + cancellable = camel_operation_new (); + e_activity_set_cancellable (context->activity, cancellable); + + e_mail_ui_session_add_activity ( + E_MAIL_UI_SESSION (session), context->activity); + + camel_store_get_folder ( + store, folder_name, 0, G_PRIORITY_DEFAULT, cancellable, + (GAsyncReadyCallback) emfp_dialog_got_folder, context); + + g_object_unref (cancellable); + +exit: + g_object_unref (session); +} |