aboutsummaryrefslogtreecommitdiffstats
path: root/widgets/misc
diff options
context:
space:
mode:
authorMatthew Barnes <mbarnes@redhat.com>2009-04-28 03:36:19 +0800
committerMatthew Barnes <mbarnes@redhat.com>2009-04-28 03:36:19 +0800
commit4449a34101406bffe508dd40b8b653f7c7d14c7d (patch)
treee9fb2ce7efd3901cf1090040666f0ce15ad70554 /widgets/misc
parente377ea5e61171e57f9e892652d0fd1f77953eda8 (diff)
downloadgsoc2013-evolution-4449a34101406bffe508dd40b8b653f7c7d14c7d.tar.gz
gsoc2013-evolution-4449a34101406bffe508dd40b8b653f7c7d14c7d.tar.zst
gsoc2013-evolution-4449a34101406bffe508dd40b8b653f7c7d14c7d.zip
Commit the rest of the attachment UI rewrite
Oops, last commit only included the -new- files. This also removes EExpander, which is no longer used.
Diffstat (limited to 'widgets/misc')
-rw-r--r--widgets/misc/Makefile.am22
-rw-r--r--widgets/misc/e-attachment-bar.c1504
-rw-r--r--widgets/misc/e-attachment-bar.h105
-rw-r--r--widgets/misc/e-attachment.c3021
-rw-r--r--widgets/misc/e-attachment.h186
-rw-r--r--widgets/misc/e-expander.c1341
-rw-r--r--widgets/misc/e-expander.h82
7 files changed, 2538 insertions, 3723 deletions
diff --git a/widgets/misc/Makefile.am b/widgets/misc/Makefile.am
index 95acd8b929..3befe12e9d 100644
--- a/widgets/misc/Makefile.am
+++ b/widgets/misc/Makefile.am
@@ -37,7 +37,15 @@ widgetsinclude_HEADERS = \
e-account-combo-box.h \
e-activity-handler.h \
e-attachment.h \
- e-attachment-bar.h \
+ e-attachment-button.h \
+ e-attachment-dialog.h \
+ e-attachment-handler.h \
+ e-attachment-handler-image.h \
+ e-attachment-icon-view.h \
+ e-attachment-paned.h \
+ e-attachment-store.h \
+ e-attachment-tree-view.h \
+ e-attachment-view.h \
e-spinner.c \
e-spinner.h \
e-calendar.h \
@@ -51,7 +59,6 @@ widgetsinclude_HEADERS = \
e-combo-button.h \
e-dateedit.h \
e-dropdown-button.h \
- e-expander.h \
e-icon-entry.h \
e-image-chooser.h \
e-info-label.h \
@@ -88,7 +95,15 @@ libemiscwidgets_la_SOURCES = \
e-activity-handler.c \
e-calendar.c \
e-attachment.c \
- e-attachment-bar.c \
+ e-attachment-button.c \
+ e-attachment-dialog.c \
+ e-attachment-handler.c \
+ e-attachment-handler-image.c \
+ e-attachment-icon-view.c \
+ e-attachment-paned.c \
+ e-attachment-store.c \
+ e-attachment-tree-view.c \
+ e-attachment-view.c \
e-calendar-item.c \
e-cell-date-edit.c \
e-cell-percent.c \
@@ -99,7 +114,6 @@ libemiscwidgets_la_SOURCES = \
e-combo-button.c \
e-dateedit.c \
e-dropdown-button.c \
- e-expander.c \
e-icon-entry.c \
e-image-chooser.c \
e-info-label.c \
diff --git a/widgets/misc/e-attachment-bar.c b/widgets/misc/e-attachment-bar.c
deleted file mode 100644
index 0210d21b46..0000000000
--- a/widgets/misc/e-attachment-bar.c
+++ /dev/null
@@ -1,1504 +0,0 @@
-/*
- * 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:
- * Ettore Perazzoli <ettore@ximian.com>
- * Jeffrey Stedfast <fejj@ximian.com>
- * Srinivasa Ragavan <sragavan@novell.com>
- *
- * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <string.h>
-#include <gtk/gtk.h>
-#include <gio/gio.h>
-#include <glade/glade.h>
-#include <gconf/gconf.h>
-#include <gconf/gconf-client.h>
-#include <gdk/gdkkeysyms.h>
-#include <glib/gi18n.h>
-#include <glib/gstdio.h>
-#include <libgnome/libgnome.h>
-
-#ifdef HAVE_LIBGNOMEUI_GNOME_THUMBNAIL_H
-#include <libgnomeui/gnome-thumbnail.h>
-#endif
-
-#include "e-attachment.h"
-#include "e-attachment-bar.h"
-
-#include <libedataserver/e-data-server-util.h>
-
-#include <camel/camel-data-wrapper.h>
-#include <camel/camel-iconv.h>
-#include <camel/camel-mime-message.h>
-#include <camel/camel-stream-fs.h>
-#include <camel/camel-stream-null.h>
-#include <camel/camel-stream-mem.h>
-#include <camel/camel-stream-filter.h>
-#include <camel/camel-mime-filter-bestenc.h>
-#include <camel/camel-mime-part.h>
-
-#include "e-util/e-util.h"
-#include "e-util/e-gui-utils.h"
-#include "e-util/e-icon-factory.h"
-#include "e-util/e-error.h"
-#include "e-util/e-mktemp.h"
-
-#define ICON_WIDTH 64
-#define ICON_SEPARATORS " /-_"
-#define ICON_SPACING 2
-#define ICON_ROW_SPACING ICON_SPACING
-#define ICON_COL_SPACING ICON_SPACING
-#define ICON_BORDER 2
-#define ICON_TEXT_SPACING 2
-
-
-static GnomeIconListClass *parent_class = NULL;
-
-struct _EAttachmentBarPrivate {
- GtkWidget *attach; /* attachment file dialogue, if active */
-
- /* Recent documents. Use this widget directly when bonoboui is obsoleted */
- GtkWidget *recent;
-
- gboolean batch_unref;
- GPtrArray *attachments;
- char *path;
-};
-
-
-enum {
- CHANGED,
- LAST_SIGNAL
-};
-
-static guint signals[LAST_SIGNAL] = { 0 };
-
-
-static void update (EAttachmentBar *bar);
-
-/* Attachment handling functions. */
-
-static void
-attachment_destroy (EAttachmentBar *bar, EAttachment *attachment)
-{
- if (bar->priv->batch_unref)
- return;
-
- if (g_ptr_array_remove (bar->priv->attachments, attachment)) {
- update (bar);
- g_signal_emit (bar, signals[CHANGED], 0);
- }
-}
-
-static void
-attachment_changed_cb (EAttachment *attachment,
- gpointer data)
-{
- update (E_ATTACHMENT_BAR (data));
-}
-
-static void
-add_common (EAttachmentBar *bar, EAttachment *attachment)
-{
- g_return_if_fail (attachment != NULL);
-
- g_ptr_array_add (bar->priv->attachments, attachment);
- g_object_weak_ref ((GObject *) attachment, (GWeakNotify) attachment_destroy, bar);
- g_signal_connect (attachment, "changed", G_CALLBACK (attachment_changed_cb), bar);
-
- update (bar);
-
- g_signal_emit (bar, signals[CHANGED], 0);
-}
-
-static void
-add_from_mime_part (EAttachmentBar *bar, CamelMimePart *part)
-{
- add_common (bar, e_attachment_new_from_mime_part (part));
-}
-
-static void
-add_from_file (EAttachmentBar *bar, const char *file_name, const char *disposition)
-{
- EAttachment *attachment;
- CamelException ex;
-
- camel_exception_init (&ex);
-
- if ((attachment = e_attachment_new (file_name, disposition, &ex))) {
- add_common (bar, attachment);
- } else {
- /* FIXME: Avoid using error from mailer */
- e_error_run ((GtkWindow *) gtk_widget_get_toplevel ((GtkWidget *) bar), "mail-composer:no-attach",
- file_name, camel_exception_get_description (&ex), NULL);
- camel_exception_clear (&ex);
- }
-}
-
-/* get_system_thumbnail:
- * If filled store_uri, then creating thumbnail for it, otherwise, if is_available_local,
- * and attachment is not an application, then save to temp and create a thumbnail for the body.
- * Otherwise returns NULL (or if something goes wrong/library not available).
- */
-static GdkPixbuf *
-get_system_thumbnail (EAttachment *attachment, CamelContentType *content_type)
-{
- GdkPixbuf *pixbuf = NULL;
-#ifdef HAVE_LIBGNOMEUI_GNOME_THUMBNAIL_H
- struct stat file_stat;
- char *file_uri = NULL;
- gboolean is_tmp = FALSE;
-
- if (!attachment || !attachment->is_available_local)
- return NULL;
-
- if (attachment->store_uri && g_str_has_prefix (attachment->store_uri, "file://"))
- file_uri = attachment->store_uri;
- else if (attachment->body) {
- /* save part to the temp directory */
- char *tmp_file;
-
- is_tmp = TRUE;
-
- tmp_file = e_mktemp ("tmp-XXXXXX");
- if (tmp_file) {
- CamelStream *stream;
- char *mfilename = NULL;
- const char * filename;
-
- filename = camel_mime_part_get_filename (attachment->body);
- if (filename == NULL)
- filename = "unknown";
- else {
- char *utf8_mfilename;
-
- utf8_mfilename = g_strdup (filename);
- e_filename_make_safe (utf8_mfilename);
- mfilename = g_filename_from_utf8 ((const char *) utf8_mfilename, -1, NULL, NULL, NULL);
- g_free (utf8_mfilename);
-
- filename = (const char *) mfilename;
- }
-
- file_uri = g_strjoin (NULL, "file://", tmp_file, "-", filename, NULL);
-
- stream = camel_stream_fs_new_with_name (file_uri + 7, O_WRONLY | O_CREAT | O_TRUNC, 0644);
- if (stream) {
- CamelDataWrapper *content;
-
- content = camel_medium_get_content_object (CAMEL_MEDIUM (attachment->body));
-
- if (camel_data_wrapper_decode_to_stream (content, stream) == -1
- || camel_stream_flush (stream) == -1) {
- g_free (file_uri);
- file_uri = NULL;
- }
-
- camel_object_unref (stream);
- } else {
- g_free (file_uri);
- file_uri = NULL;
- }
-
- g_free (mfilename);
- g_free (tmp_file);
- }
- }
-
- if (!file_uri || !g_str_has_prefix (file_uri, "file://")) {
- if (is_tmp)
- g_free (file_uri);
-
- return NULL;
- }
-
- if (stat (file_uri + 7, &file_stat) != -1 && S_ISREG (file_stat.st_mode)) {
- GnomeThumbnailFactory *th_factory;
- char *th_file;
-
- th_factory = gnome_thumbnail_factory_new (GNOME_THUMBNAIL_SIZE_NORMAL);
- th_file = gnome_thumbnail_factory_lookup (th_factory, file_uri, file_stat.st_mtime);
-
- if (th_file) {
- pixbuf = gdk_pixbuf_new_from_file (th_file, NULL);
- g_free (th_file);
- } else if (content_type) {
- char *mime = camel_content_type_simple (content_type);
-
- if (gnome_thumbnail_factory_can_thumbnail (th_factory, file_uri, mime, file_stat.st_mtime)) {
- pixbuf = gnome_thumbnail_factory_generate_thumbnail (th_factory, file_uri, mime);
-
- if (pixbuf && !is_tmp)
- gnome_thumbnail_factory_save_thumbnail (th_factory, pixbuf, file_uri, file_stat.st_mtime);
- }
-
- g_free (mime);
- }
-
- g_object_unref (th_factory);
- }
-
- if (is_tmp) {
- /* clear the temp */
- g_remove (file_uri + 7);
- g_free (file_uri);
- }
-#endif
-
- return pixbuf;
-}
-
-static GdkPixbuf *
-scale_pixbuf (GdkPixbuf *pixbuf)
-{
- int ratio, width, height;
-
- if (!pixbuf)
- return NULL;
-
- width = gdk_pixbuf_get_width (pixbuf);
- height = gdk_pixbuf_get_height (pixbuf);
- if (width >= height) {
- if (width > 48) {
- ratio = width / 48;
- width = 48;
- height = height / ratio;
- if (height == 0)
- height = 1;
- }
- } else {
- if (height > 48) {
- ratio = height / 48;
- height = 48;
- width = width / ratio;
- if (width == 0)
- width = 1;
- }
- }
-
- return e_icon_factory_pixbuf_scale (pixbuf, width, height);
-}
-
-/* Icon list contents handling. */
-
-static void
-calculate_height_width(EAttachmentBar *bar, int *new_width, int *new_height)
-{
- int width, height, icon_width;
- PangoFontMetrics *metrics;
- PangoContext *context;
-
- context = gtk_widget_get_pango_context ((GtkWidget *) bar);
- metrics = pango_context_get_metrics (context, ((GtkWidget *) bar)->style->font_desc, pango_context_get_language (context));
- width = PANGO_PIXELS (pango_font_metrics_get_approximate_char_width (metrics)) * 15;
- /* This should be *2, but the icon list creates too much space above ... */
- height = PANGO_PIXELS (pango_font_metrics_get_ascent (metrics) + pango_font_metrics_get_descent (metrics)) * 3;
- pango_font_metrics_unref (metrics);
- icon_width = ICON_WIDTH + ICON_SPACING + ICON_BORDER + ICON_TEXT_SPACING;
-
- if (new_width)
- *new_width = MAX (icon_width, width);
-
- if (new_height)
- *new_height = ICON_WIDTH + ICON_SPACING + ICON_BORDER + ICON_TEXT_SPACING + height;
-
- return;
-}
-
-void
-e_attachment_bar_create_attachment_cache (EAttachment *attachment)
-{
-
- CamelContentType *content_type;
-
- if (!attachment->body)
- return;
-
- content_type = camel_mime_part_get_content_type (attachment->body);
-
- if (camel_content_type_is(content_type, "image", "*")) {
- CamelDataWrapper *wrapper;
- CamelStreamMem *mstream;
- GdkPixbufLoader *loader;
- gboolean error = TRUE;
- GdkPixbuf *pixbuf;
-
- wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (attachment->body));
- mstream = (CamelStreamMem *) camel_stream_mem_new ();
-
- camel_data_wrapper_decode_to_stream (wrapper, (CamelStream *) mstream);
-
- /* Stream image into pixbuf loader */
- loader = gdk_pixbuf_loader_new ();
- error = !gdk_pixbuf_loader_write (loader, mstream->buffer->data, mstream->buffer->len, NULL);
- gdk_pixbuf_loader_close (loader, NULL);
-
- if (!error) {
- pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
- attachment->pixbuf_cache = scale_pixbuf (pixbuf);
- pixbuf = attachment->pixbuf_cache;
- g_object_ref(pixbuf);
- } else {
- attachment->pixbuf_cache = NULL;
- g_warning ("GdkPixbufLoader Error");
- }
-
- /* Destroy everything */
- g_object_unref (loader);
- camel_object_unref (mstream);
- }
-}
-
-static void
-update (EAttachmentBar *bar)
-{
- struct _EAttachmentBarPrivate *priv;
- GnomeIconList *icon_list;
- int bar_width, bar_height;
- int i;
-
- priv = bar->priv;
- icon_list = GNOME_ICON_LIST (bar);
-
- gnome_icon_list_freeze (icon_list);
-
- gnome_icon_list_clear (icon_list);
-
- /* FIXME could be faster, but we don't care. */
- for (i = 0; i < priv->attachments->len; i++) {
- EAttachment *attachment;
- CamelContentType *content_type;
- char *size_string, *label;
- GdkPixbuf *pixbuf = NULL;
- char *desc;
-
- attachment = priv->attachments->pdata[i];
-
- if (!attachment->is_available_local || !attachment->body) {
- if ((pixbuf = e_icon_factory_get_icon("mail-attachment", E_ICON_SIZE_DIALOG))) {
- attachment->index = gnome_icon_list_append_pixbuf (icon_list, pixbuf, NULL, "");
- g_object_unref (pixbuf);
- }
- continue;
- }
-
- content_type = camel_mime_part_get_content_type (attachment->body);
- /* Get the image out of the attachment
- and create a thumbnail for it */
- if ((pixbuf = attachment->pixbuf_cache)) {
- g_object_ref(pixbuf);
- } else if (camel_content_type_is(content_type, "image", "*")) {
- CamelDataWrapper *wrapper;
- CamelStreamMem *mstream;
- GdkPixbufLoader *loader;
- gboolean error = TRUE;
-
- wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (attachment->body));
- mstream = (CamelStreamMem *) camel_stream_mem_new ();
-
- camel_data_wrapper_decode_to_stream (wrapper, (CamelStream *) mstream);
-
- /* Stream image into pixbuf loader */
- loader = gdk_pixbuf_loader_new ();
- error = !gdk_pixbuf_loader_write (loader, mstream->buffer->data, mstream->buffer->len, NULL);
- gdk_pixbuf_loader_close (loader, NULL);
-
- if (!error) {
- pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
- attachment->pixbuf_cache = scale_pixbuf (pixbuf);
- pixbuf = attachment->pixbuf_cache;
- g_object_ref (pixbuf);
- } else {
- pixbuf = NULL;
- g_warning ("GdkPixbufLoader Error");
- }
-
- /* Destroy everything */
- g_object_unref (loader);
- camel_object_unref (mstream);
- } else if (!bar->expand && (pixbuf = get_system_thumbnail (attachment, content_type))) {
- attachment->pixbuf_cache = scale_pixbuf (pixbuf);
- pixbuf = attachment->pixbuf_cache;
- g_object_ref (pixbuf);
- }
-
- desc = camel_mime_part_get_description (attachment->body);
-
- if (!desc || *desc == '\0') {
- if (attachment->file_name) {
- desc = g_filename_to_utf8 (attachment->file_name, -1, NULL, NULL, NULL);
- } else {
- desc = camel_mime_part_get_filename (attachment->body);
- if (desc)
- desc = g_strdup (desc);
- }
- } else {
- desc = g_strdup (desc);
- }
-
- if (!desc)
- desc = g_strdup (_("attachment"));
-
- if (attachment->size && (size_string = g_format_size_for_display (attachment->size))) {
- label = g_strdup_printf ("%s (%s)", desc, size_string);
- g_free (desc);
- g_free (size_string);
- } else {
- label = g_strdup (desc);
- g_free (desc);
- }
-
- if (pixbuf == NULL) {
- char *mime_type;
-
- mime_type = camel_content_type_simple (content_type);
- pixbuf = e_icon_for_mime_type (mime_type, 48);
- if (pixbuf == NULL) {
- g_warning("cannot find icon for mime type %s (installation problem?)", mime_type);
- pixbuf = e_icon_factory_get_icon("mail-attachment", E_ICON_SIZE_DIALOG);
- }
- g_free (mime_type);
-
- /* remember this picture and use it later again */
- if (pixbuf)
- attachment->pixbuf_cache = g_object_ref (pixbuf);
- }
-
- if (pixbuf) {
- GdkPixbuf *pixbuf_orig = pixbuf;
- pixbuf = gdk_pixbuf_add_alpha (pixbuf_orig, TRUE, 255, 255, 255);
-
- /* gdk_pixbuf_add_alpha returns a newly allocated pixbuf,
- free the original one.
- */
- g_object_unref (pixbuf_orig);
-
- /* In case of a attachment bar, in a signed/encrypted part, display the status as a emblem*/
- if (attachment->sign) {
- /* Show the signature status at the right-bottom.*/
- GdkPixbuf *sign = NULL;
- int x, y;
-
- if (attachment->sign == CAMEL_CIPHER_VALIDITY_SIGN_BAD)
- sign = e_icon_factory_get_icon ("stock_signature-bad", E_ICON_SIZE_MENU);
- else if (attachment->sign == CAMEL_CIPHER_VALIDITY_SIGN_GOOD)
- sign = e_icon_factory_get_icon ("stock_signature-ok", E_ICON_SIZE_MENU);
- else
- sign = e_icon_factory_get_icon ("stock_signature", E_ICON_SIZE_MENU);
-
- x = gdk_pixbuf_get_width (pixbuf) - 17;
- y = gdk_pixbuf_get_height (pixbuf) - 17;
-
- gdk_pixbuf_copy_area (sign, 0, 0, 16, 16, pixbuf, x, y);
- g_object_unref (sign);
- }
-
- if (attachment->encrypt) {
- /* Show the encryption status at the top left.*/
- GdkPixbuf *encrypt = e_icon_factory_get_icon ("stock_lock-ok", E_ICON_SIZE_MENU);
-
- gdk_pixbuf_copy_area (encrypt, 0, 0, 16, 16, pixbuf, 1, 1);
- g_object_unref (encrypt);
- }
-
- gnome_icon_list_append_pixbuf (icon_list, pixbuf, NULL, label);
- g_object_unref (pixbuf);
- }
-
- g_free (label);
- }
-
- gnome_icon_list_thaw (icon_list);
-
- /* Resize */
- if (bar->expand) {
- gtk_widget_get_size_request ((GtkWidget *) bar, &bar_width, &bar_height);
-
- if (bar->priv->attachments->len) {
- int per_col, rows, height, width;
-
- calculate_height_width(bar, &width, &height);
- per_col = bar_width / width;
- per_col = (per_col ? per_col : 1);
- rows = (bar->priv->attachments->len + per_col -1) / per_col;
- gtk_widget_set_size_request ((GtkWidget *) bar, bar_width, rows * height);
- }
- }
-}
-
-static void
-update_remote_file (EAttachment *attachment, EAttachmentBar *bar)
-{
- GnomeIconList *icon_list;
- GnomeIconTextItem *item;
- char *msg, *base;
-
- if (attachment->percentage == -1) {
- update (bar);
- return;
- }
-
- base = g_path_get_basename(attachment->file_name);
- msg = g_strdup_printf("%s (%d%%)", base, attachment->percentage);
- g_free(base);
-
- icon_list = GNOME_ICON_LIST (bar);
-
- gnome_icon_list_freeze (icon_list);
-
- item = gnome_icon_list_get_icon_text_item (icon_list, attachment->index);
- if (!item->is_text_allocated)
- g_free (item->text);
-
- gnome_icon_text_item_configure (item, item->x, item->y, item->width, item->fontname, msg, item->is_editable, TRUE);
-
- gnome_icon_list_thaw (icon_list);
-}
-
-void
-e_attachment_bar_remove_selected (EAttachmentBar *bar)
-{
- struct _EAttachmentBarPrivate *priv;
- EAttachment *attachment;
- int id, left, nrem = 0;
- GList *items;
- GPtrArray *temp_arr;
-
- g_return_if_fail (E_IS_ATTACHMENT_BAR (bar));
-
- priv = bar->priv;
-
- if (!(items = gnome_icon_list_get_selection ((GnomeIconList *) bar)))
- return;
-
- temp_arr = g_ptr_array_new ();
- while (items != NULL) {
- if ((id = GPOINTER_TO_INT (items->data) - nrem) < priv->attachments->len) {
- attachment = E_ATTACHMENT(g_ptr_array_index (priv->attachments, id));
- g_ptr_array_add (temp_arr, (gpointer)attachment);
- g_ptr_array_remove_index (priv->attachments, id);
- nrem++;
- }
-
- items = items->next;
- }
-
- g_ptr_array_foreach (temp_arr, (GFunc)g_object_unref, NULL);
- g_ptr_array_free (temp_arr, TRUE);
-
- update (bar);
-
- g_signal_emit (bar, signals[CHANGED], 0);
-
- id++;
-
- if ((left = gnome_icon_list_get_num_icons ((GnomeIconList *) bar)) > 0)
- gnome_icon_list_focus_icon ((GnomeIconList *) bar, left > id ? id : left - 1);
-}
-
-void
-e_attachment_bar_set_width(EAttachmentBar *bar, int bar_width)
-{
- int per_col, rows, height, width;
-
- calculate_height_width(bar, &width, &height);
- per_col = bar_width / width;
- per_col = (per_col ? per_col : 1);
- rows = (bar->priv->attachments->len + per_col - 1) / per_col;
- gtk_widget_set_size_request ((GtkWidget *)bar, bar_width, rows * height);
-}
-
-void
-e_attachment_bar_edit_selected (EAttachmentBar *bar)
-{
- struct _EAttachmentBarPrivate *priv;
- EAttachment *attachment;
- GList *items;
- int id;
-
- g_return_if_fail (E_IS_ATTACHMENT_BAR (bar));
-
- priv = bar->priv;
-
- items = gnome_icon_list_get_selection ((GnomeIconList *) bar);
- while (items != NULL) {
- if ((id = GPOINTER_TO_INT (items->data)) < priv->attachments->len) {
- attachment = priv->attachments->pdata[id];
- e_attachment_edit (attachment, GTK_WIDGET (bar));
- }
-
- items = items->next;
- }
-}
-
-GtkWidget **
-e_attachment_bar_get_selector(EAttachmentBar *bar)
-{
- g_return_val_if_fail (E_IS_ATTACHMENT_BAR (bar), NULL);
-
- return &bar->priv->attach;
-}
-
-/**
- * e_attachment_bar_get_selected:
- * @bar: an #EAttachmentBar object
- *
- * Returns a newly allocated #GSList of ref'd #EAttachment objects
- * representing the selected items in the #EAttachmentBar Icon List.
- **/
-GSList *
-e_attachment_bar_get_selected (EAttachmentBar *bar)
-{
- struct _EAttachmentBarPrivate *priv;
- GSList *attachments = NULL;
- EAttachment *attachment;
- GList *items;
- int id;
-
- g_return_val_if_fail (E_IS_ATTACHMENT_BAR (bar), NULL);
-
- priv = bar->priv;
-
- items = gnome_icon_list_get_selection ((GnomeIconList *) bar);
-
- while (items != NULL) {
- if ((id = GPOINTER_TO_INT (items->data)) < priv->attachments->len) {
- attachment = priv->attachments->pdata[id];
- attachments = g_slist_prepend (attachments, attachment);
- g_object_ref (attachment);
- }
-
- items = items->next;
- }
-
- attachments = g_slist_reverse (attachments);
-
- return attachments;
-}
-
-/* FIXME: Cleanup this, since there is a api to get selected attachments */
-/**
- * e_attachment_bar_get_attachment:
- * @bar: an #EAttachmentBar object
- * @id: Index of the desired attachment or -1 to request all selected attachments
- *
- * Returns a newly allocated #GSList of ref'd #EAttachment objects
- * representing the requested item(s) in the #EAttachmentBar Icon
- * List.
- **/
-GSList *
-e_attachment_bar_get_attachment (EAttachmentBar *bar, int id)
-{
- struct _EAttachmentBarPrivate *priv;
- EAttachment *attachment;
- GSList *attachments;
-
- g_return_val_if_fail (E_IS_ATTACHMENT_BAR (bar), NULL);
-
- priv = bar->priv;
-
- if (id == -1 || id > priv->attachments->len)
- return e_attachment_bar_get_selected (bar);
-
- attachment = priv->attachments->pdata[id];
- attachments = g_slist_prepend (NULL, attachment);
- g_object_ref (attachment);
-
- return attachments;
-}
-
-
-/**
- * e_attachment_bar_get_all_attachments:
- * @bar: an #EAttachmentBar object
- *
- * Returns a newly allocated #GSList of ref'd #EAttachment objects.
- **/
-GSList *
-e_attachment_bar_get_all_attachments (EAttachmentBar *bar)
-{
- struct _EAttachmentBarPrivate *priv;
- GSList *attachments = NULL;
- EAttachment *attachment;
- int i;
-
- g_return_val_if_fail (E_IS_ATTACHMENT_BAR (bar), NULL);
-
- priv = bar->priv;
-
- for (i = priv->attachments->len - 1; i >= 0; i--) {
- attachment = priv->attachments->pdata[i];
- if (attachment->is_available_local) {
- attachments = g_slist_prepend (attachments, attachment);
- g_object_ref (attachment);
- }
- }
-
- return attachments;
-}
-
-/* Just the GSList has to be freed by the caller */
-GSList *
-e_attachment_bar_get_parts (EAttachmentBar *bar)
-{
- struct _EAttachmentBarPrivate *priv;
- EAttachment *attachment;
- GSList *parts = NULL;
- int i;
-
- g_return_val_if_fail (E_IS_ATTACHMENT_BAR (bar), NULL);
-
- priv = bar->priv;
-
- for (i = 0; i < priv->attachments->len; i++) {
- attachment = priv->attachments->pdata[i];
- if (attachment->is_available_local)
- parts = g_slist_prepend (parts, attachment->body);
- }
-
- return parts;
-}
-
-/* GtkObject methods. */
-
-static void
-destroy (GtkObject *object)
-{
- EAttachmentBar *bar = (EAttachmentBar *) object;
- struct _EAttachmentBarPrivate *priv = bar->priv;
- EAttachment *attachment;
- int i;
-
- if ((priv = bar->priv)) {
- priv->batch_unref = TRUE;
- for (i = 0; i < priv->attachments->len; i++) {
- attachment = priv->attachments->pdata[i];
- g_object_weak_unref ((GObject *) attachment, (GWeakNotify) attachment_destroy, bar);
- g_object_unref (attachment);
- }
- g_ptr_array_free (priv->attachments, TRUE);
-
- if (priv->attach)
- gtk_widget_destroy (priv->attach);
-
- if (priv->recent)
- gtk_widget_destroy (priv->recent);
-
- if (priv->path)
- g_free (priv->path);
-
- g_free (priv);
- bar->priv = NULL;
- }
-
- if (GTK_OBJECT_CLASS (parent_class)->destroy != NULL)
- (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
-}
-
-static char *
-temp_save_part (CamelMimePart *part, gboolean readonly)
-{
- const char *filename;
- char *tmpdir, *path, *mfilename = NULL, *utf8_mfilename = NULL;
- CamelStream *stream;
- CamelDataWrapper *wrapper;
-
- if (!(tmpdir = e_mkdtemp ("evolution-tmp-XXXXXX")))
- return NULL;
-
- if (!(filename = camel_mime_part_get_filename (part))) {
- /* This is the default filename used for temporary file creation */
- filename = _("Unknown");
- } else {
- utf8_mfilename = g_strdup (filename);
- e_filename_make_safe (utf8_mfilename);
- mfilename = g_filename_from_utf8 ((const char *) utf8_mfilename, -1, NULL, NULL, NULL);
- g_free (utf8_mfilename);
- filename = (const char *) mfilename;
- }
-
- path = g_build_filename (tmpdir, filename, NULL);
- g_free (tmpdir);
- g_free (mfilename);
-
- wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (part));
- if (readonly)
- stream = camel_stream_fs_new_with_name (path, O_RDWR|O_CREAT|O_TRUNC, 0444);
- else
- stream = camel_stream_fs_new_with_name (path, O_RDWR|O_CREAT|O_TRUNC, 0644);
-
- if (!stream) {
- /* TODO handle error conditions */
- g_message ("DEBUG: could not open the file to write\n");
- g_free (path);
- return NULL;
- }
-
- if (camel_data_wrapper_decode_to_stream (wrapper, (CamelStream *) stream) == -1) {
- g_free (path);
- camel_stream_close (stream);
- camel_object_unref (stream);
- g_message ("DEBUG: could not write to file\n");
- return NULL;
- }
-
- camel_stream_close(stream);
- camel_object_unref(stream);
-
- return path;
-}
-
-static void
-eab_drag_data_get(EAttachmentBar *bar, GdkDragContext *drag, GtkSelectionData *data, guint info, guint time)
-{
- struct _EAttachmentBarPrivate *priv = bar->priv;
- EAttachment *attachment;
- char *path, **uris;
- int len, n, i = 0;
- CamelURL *url;
- GList *items;
-
- if (info)
- return;
-
- items = gnome_icon_list_get_selection (GNOME_ICON_LIST (bar));
- len = g_list_length (items);
-
- uris = g_malloc0 (sizeof (char *) * (len + 1));
-
- for ( ; items != NULL; items = items->next) {
- if (!((n = GPOINTER_TO_INT (items->data)) < priv->attachments->len))
- continue;
-
- attachment = priv->attachments->pdata[n];
-
- if (!attachment->is_available_local)
- continue;
-
- if (attachment->store_uri) {
- uris[i++] = attachment->store_uri;
- continue;
- }
-
- /* If we are not able to save, ignore it */
- if (!(path = temp_save_part (attachment->body, FALSE)))
- continue;
-
- url = camel_url_new ("file://", NULL);
- camel_url_set_path (url, path);
- attachment->store_uri = camel_url_to_string (url, 0);
- camel_url_free (url);
- g_free (path);
-
- uris[i++] = attachment->store_uri;
- }
-
- uris[i] = NULL;
-
- gtk_selection_data_set_uris (data, uris);
-
- g_free (uris);
-
- return;
-}
-
-static gboolean
-eab_button_release_event(EAttachmentBar *bar, GdkEventButton *event, gpointer dummy)
-{
- GnomeIconList *icon_list = GNOME_ICON_LIST(bar);
- GList *selected;
- int length;
- GtkTargetEntry drag_types[] = {
- { "text/uri-list", 0, 0 },
- };
-
- if (event && event->button == 1) {
- selected = gnome_icon_list_get_selection(icon_list);
- length = g_list_length (selected);
- if (length)
- gtk_drag_source_set((GtkWidget *)bar, GDK_BUTTON1_MASK, drag_types, G_N_ELEMENTS(drag_types), GDK_ACTION_COPY);
- else
- gtk_drag_source_unset((GtkWidget *)bar);
- }
-
- return FALSE;
-}
-
-static gboolean
-eab_button_press_event(EAttachmentBar *bar, GdkEventButton *event, gpointer dummy)
-{
- GnomeIconList *icon_list = GNOME_ICON_LIST(bar);
- GList *selected = NULL, *tmp;
- int length, icon_number;
- gboolean take_selected = FALSE;
- GtkTargetEntry drag_types[] = {
- { "text/uri-list", 0, 0 },
- };
-
- selected = gnome_icon_list_get_selection(icon_list);
- length = g_list_length (selected);
-
- if (event) {
- icon_number = gnome_icon_list_get_icon_at(icon_list, event->x, event->y);
- if (icon_number < 0) {
- /* When nothing is selected, deselect all */
- gnome_icon_list_unselect_all (icon_list);
- length = 0;
- selected = NULL;
- }
-
- if (event->button == 1) {
- /* If something is selected, then allow drag or else help to select */
- if (length)
- gtk_drag_source_set((GtkWidget *)bar, GDK_BUTTON1_MASK, drag_types, G_N_ELEMENTS(drag_types), GDK_ACTION_COPY);
- else
- gtk_drag_source_unset((GtkWidget *)bar);
- return FALSE;
- }
-
- /* If not r-click dont progress any more.*/
- if (event->button != 3)
- return FALSE;
-
- /* When a r-click on something, if it is in the already selected list, consider a r-click of multiple things
- * or deselect all and select only this for r-click
- */
- if (icon_number >= 0) {
- for (tmp = selected; tmp; tmp = tmp->next) {
- if (GPOINTER_TO_INT(tmp->data) == icon_number)
- take_selected = TRUE;
- }
-
- if (!take_selected) {
- gnome_icon_list_unselect_all(icon_list);
- gnome_icon_list_select_icon(icon_list, icon_number);
- }
- }
- }
-
- return FALSE;
-}
-
-static gboolean
-eab_icon_clicked_cb (EAttachmentBar *bar, GdkEvent *event, gpointer *dummy)
-{
- EAttachment *attachment;
- gboolean ret = FALSE;
- CamelURL *url;
- char *path;
- GSList *p;
-
- if (E_IS_ATTACHMENT_BAR (bar) && event->type == GDK_2BUTTON_PRESS) {
- p = e_attachment_bar_get_selected (bar);
- /* check if has body already, remote files can take longer to fetch */
- if (p && p->next == NULL && ((EAttachment *)p->data)->body) {
- attachment = p->data;
-
- /* Check if the file is stored already */
- if (!attachment->store_uri) {
- path = temp_save_part (attachment->body, TRUE);
- url = camel_url_new ("file://", NULL);
- camel_url_set_path (url, path);
- attachment->store_uri = camel_url_to_string (url, 0);
- camel_url_free (url);
- g_free (path);
- }
-
- /* FIXME Pass a parent window. */
- e_show_uri (NULL, attachment->store_uri);
-
- ret = TRUE;
- }
-
- if (p) {
- g_slist_foreach (p, (GFunc) g_object_unref, NULL);
- g_slist_free (p);
- }
- }
-
- return ret;
-}
-
-/* Initialization. */
-
-static void
-class_init (EAttachmentBarClass *klass)
-{
- GtkObjectClass *object_class;
-
- object_class = GTK_OBJECT_CLASS (klass);
-
- parent_class = g_type_class_ref (gnome_icon_list_get_type ());
-
- object_class->destroy = destroy;
-
- /* Setup signals. */
-
- signals[CHANGED] =
- g_signal_new ("changed",
- E_TYPE_ATTACHMENT_BAR,
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (EAttachmentBarClass, changed),
- NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
-}
-
-static void
-init (EAttachmentBar *bar)
-{
- struct _EAttachmentBarPrivate *priv;
-
- priv = g_new (struct _EAttachmentBarPrivate, 1);
-
- priv->attach = NULL;
- priv->batch_unref = FALSE;
- priv->attachments = g_ptr_array_new ();
-
- priv->recent = gtk_recent_chooser_menu_new ();
- gtk_recent_chooser_menu_set_show_numbers (GTK_RECENT_CHOOSER_MENU (priv->recent), TRUE);
- gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (priv->recent), GTK_RECENT_SORT_MRU);
- gtk_recent_chooser_set_show_not_found (GTK_RECENT_CHOOSER (priv->recent), FALSE);
- gtk_recent_chooser_set_show_private (GTK_RECENT_CHOOSER (priv->recent), FALSE);
- gtk_recent_chooser_set_show_icons (GTK_RECENT_CHOOSER (priv->recent), TRUE);
- gtk_recent_chooser_set_show_tips (GTK_RECENT_CHOOSER (priv->recent), TRUE);
-
- priv->path = NULL;
-
- bar->priv = priv;
- bar->expand = FALSE;
-}
-
-
-GType
-e_attachment_bar_get_type (void)
-{
- static GType type = 0;
-
- if (type == 0) {
- static const GTypeInfo info = {
- sizeof (EAttachmentBarClass),
- NULL, NULL,
- (GClassInitFunc) class_init,
- NULL, NULL,
- sizeof (EAttachmentBar),
- 0,
- (GInstanceInitFunc) init,
- };
-
- type = g_type_register_static (GNOME_TYPE_ICON_LIST, "EAttachmentBar", &info, 0);
- }
-
- return type;
-}
-
-GtkWidget *
-e_attachment_bar_new (GtkAdjustment *adj)
-{
- EAttachmentBar *new;
- GnomeIconList *icon_list;
- int icon_width, window_height;
-
- new = g_object_new (e_attachment_bar_get_type (), NULL);
-
- icon_list = GNOME_ICON_LIST (new);
-
- calculate_height_width (new, &icon_width, &window_height);
-
- gnome_icon_list_construct (icon_list, icon_width, adj, 0);
-
- gtk_widget_set_size_request (GTK_WIDGET (new), icon_width * 4, window_height);
-
- GTK_WIDGET_SET_FLAGS (new, GTK_CAN_FOCUS);
-
- gnome_icon_list_set_separators (icon_list, ICON_SEPARATORS);
- gnome_icon_list_set_row_spacing (icon_list, ICON_ROW_SPACING);
- gnome_icon_list_set_col_spacing (icon_list, ICON_COL_SPACING);
- gnome_icon_list_set_icon_border (icon_list, ICON_BORDER);
- gnome_icon_list_set_text_spacing (icon_list, ICON_TEXT_SPACING);
- gnome_icon_list_set_selection_mode (icon_list, GTK_SELECTION_MULTIPLE);
-
- atk_object_set_name (gtk_widget_get_accessible (GTK_WIDGET (new)),
- _("Attachment Bar"));
-
- g_signal_connect (new, "button_release_event", G_CALLBACK(eab_button_release_event), NULL);
- g_signal_connect (new, "button_press_event", G_CALLBACK(eab_button_press_event), NULL);
- g_signal_connect (new, "drag-data-get", G_CALLBACK(eab_drag_data_get), NULL);
- g_signal_connect (icon_list, "event", G_CALLBACK (eab_icon_clicked_cb), NULL);
-
- return GTK_WIDGET (new);
-}
-
-static char *
-get_default_charset (void)
-{
- GConfClient *gconf;
- const char *locale;
- char *charset;
-
- gconf = gconf_client_get_default ();
- charset = gconf_client_get_string (gconf, "/apps/evolution/mail/composer/charset", NULL);
-
- if (!charset || charset[0] == '\0') {
- g_free (charset);
- charset = gconf_client_get_string (gconf, "/apps/evolution/mail/format/charset", NULL);
- if (charset && charset[0] == '\0') {
- g_free (charset);
- charset = NULL;
- }
- }
-
- g_object_unref (gconf);
-
- if (!charset && (locale = camel_iconv_locale_charset ()))
- charset = g_strdup (locale);
-
- return charset ? charset : g_strdup ("us-ascii");
-}
-
-static void
-attach_to_multipart (CamelMultipart *multipart,
- EAttachment *attachment,
- const char *default_charset)
-{
- CamelContentType *content_type;
- CamelDataWrapper *content;
-
- if (!attachment->body)
- return;
-
- content_type = camel_mime_part_get_content_type (attachment->body);
- content = camel_medium_get_content_object (CAMEL_MEDIUM (attachment->body));
-
- if (!CAMEL_IS_MULTIPART (content)) {
- if (camel_content_type_is (content_type, "text", "*")) {
- CamelTransferEncoding encoding;
- CamelStreamFilter *filter_stream;
- CamelMimeFilterBestenc *bestenc;
- CamelStream *stream;
- const char *charset;
- char *buf = NULL;
- char *type;
-
- charset = camel_content_type_param (content_type, "charset");
-
- stream = camel_stream_null_new ();
- filter_stream = camel_stream_filter_new_with_stream (stream);
- bestenc = camel_mime_filter_bestenc_new (CAMEL_BESTENC_GET_ENCODING);
- camel_stream_filter_add (filter_stream, CAMEL_MIME_FILTER (bestenc));
- camel_object_unref (stream);
-
- camel_data_wrapper_decode_to_stream (content, CAMEL_STREAM (filter_stream));
- camel_object_unref (filter_stream);
-
- encoding = camel_mime_filter_bestenc_get_best_encoding (bestenc, CAMEL_BESTENC_8BIT);
- camel_mime_part_set_encoding (attachment->body, encoding);
-
- if (encoding == CAMEL_TRANSFER_ENCODING_7BIT) {
- /* the text fits within us-ascii so this is safe */
- /* FIXME: check that this isn't iso-2022-jp? */
- default_charset = "us-ascii";
- } else if (!charset) {
- if (!default_charset)
- default_charset = buf = get_default_charset ();
-
- /* FIXME: We should really check that this fits within the
- default_charset and if not find one that does and/or
- allow the user to specify? */
- }
-
- if (!charset) {
- /* looks kinda nasty, but this is how ya have to do it */
- camel_content_type_set_param (content_type, "charset", default_charset);
- type = camel_content_type_format (content_type);
- camel_mime_part_set_content_type (attachment->body, type);
- g_free (type);
- g_free (buf);
- }
-
- camel_object_unref (bestenc);
- } else if (!CAMEL_IS_MIME_MESSAGE (content)) {
- camel_mime_part_set_encoding (attachment->body, CAMEL_TRANSFER_ENCODING_BASE64);
- }
- }
-
- camel_multipart_add_part (multipart, attachment->body);
-}
-
-void
-e_attachment_bar_to_multipart (EAttachmentBar *bar, CamelMultipart *multipart, const char *default_charset)
-{
- struct _EAttachmentBarPrivate *priv;
- EAttachment *attachment;
- int i;
-
- g_return_if_fail (E_IS_ATTACHMENT_BAR (bar));
- g_return_if_fail (CAMEL_IS_MULTIPART (multipart));
-
- priv = bar->priv;
-
- for (i = 0; i < priv->attachments->len; i++) {
- attachment = priv->attachments->pdata[i];
- if (attachment->is_available_local)
- attach_to_multipart (multipart, attachment, default_charset);
- }
-}
-
-guint
-e_attachment_bar_get_num_attachments (EAttachmentBar *bar)
-{
- g_return_val_if_fail (E_IS_ATTACHMENT_BAR (bar), 0);
-
- return bar->priv->attachments->len;
-}
-
-void
-e_attachment_bar_attach (EAttachmentBar *bar, const char *file_name, const char *disposition)
-{
- g_return_if_fail (E_IS_ATTACHMENT_BAR (bar));
- g_return_if_fail (file_name != NULL && disposition != NULL);
-
- add_from_file (bar, file_name, disposition);
-}
-
-void
-e_attachment_bar_add_attachment (EAttachmentBar *bar, EAttachment *attachment)
-{
- g_return_if_fail (E_IS_ATTACHMENT_BAR (bar));
-
- add_common (bar, attachment);
-}
-
-void
-e_attachment_bar_add_attachment_silent (EAttachmentBar *bar, EAttachment *attachment)
-{
- g_return_if_fail (E_IS_ATTACHMENT_BAR (bar));
- g_return_if_fail (attachment != NULL);
-
- g_ptr_array_add (bar->priv->attachments, attachment);
- g_object_weak_ref ((GObject *) attachment, (GWeakNotify) attachment_destroy, bar);
- g_signal_connect (attachment, "changed", G_CALLBACK (attachment_changed_cb), bar);
-
-
- g_signal_emit (bar, signals[CHANGED], 0);
-}
-
-void
-e_attachment_bar_refresh (EAttachmentBar *bar)
-{
- update (bar);
-
-}
-
-int
-e_attachment_bar_get_download_count (EAttachmentBar *bar)
-{
- struct _EAttachmentBarPrivate *priv;
- EAttachment *attachment;
- int i, n = 0;
-
- g_return_val_if_fail (E_IS_ATTACHMENT_BAR (bar), 0);
-
- priv = bar->priv;
-
- for (i = 0; i < priv->attachments->len; i++) {
- attachment = priv->attachments->pdata[i];
- if (!attachment->is_available_local)
- n++;
- }
-
- return n;
-}
-
-void
-e_attachment_bar_attach_remote_file (EAttachmentBar *bar, const char *url, const char *disposition)
-{
- EAttachment *attachment;
- CamelException ex;
- GtkWindow *parent;
-
- g_return_if_fail (E_IS_ATTACHMENT_BAR (bar));
-
- if (!bar->priv->path)
- bar->priv->path = e_mkdtemp ("attach-XXXXXX");
-
- parent = (GtkWindow *) gtk_widget_get_toplevel ((GtkWidget *) bar);
- camel_exception_init (&ex);
- if ((attachment = e_attachment_new_remote_file (parent, url, disposition, bar->priv->path, &ex))) {
- add_common (bar, attachment);
- g_signal_connect (attachment, "update", G_CALLBACK (update_remote_file), bar);
- } else {
- e_error_run (parent, "mail-composer:no-attach",
- url, camel_exception_get_description (&ex), NULL);
- camel_exception_clear (&ex);
- }
-}
-
-void
-e_attachment_bar_attach_mime_part (EAttachmentBar *bar, CamelMimePart *part)
-{
- g_return_if_fail (E_IS_ATTACHMENT_BAR (bar));
-
- add_from_mime_part (bar, part);
-}
-
-/* FIXME: Remove this API if nobody uses it */
-void
-e_attachment_bar_bonobo_ui_populate_with_recent (BonoboUIComponent *uic, const char *path,
- EAttachmentBar *bar,
- BonoboUIVerbFn verb_cb, gpointer user_data)
-{
- struct _EAttachmentBarPrivate *priv;
- GList *items, *l;
- gint limit, i;
- GString *menuitems;
- char *encoded_label, *label;
-
- g_return_if_fail (E_IS_ATTACHMENT_BAR (bar));
-
- priv = bar->priv;
- limit = gtk_recent_chooser_get_limit (GTK_RECENT_CHOOSER (priv->recent));
- items = gtk_recent_chooser_get_items (GTK_RECENT_CHOOSER (priv->recent));
-
- menuitems = g_string_new ("<submenu");
- g_string_append (menuitems, " name=\"RecentDocsSubmenu\"");
- g_string_append_printf (menuitems, " sensitive=\"%s\"", items ? "1" : "0");
- g_string_append_printf (menuitems, " label=\"%s\"", _("Recent _Documents"));
- g_string_append (menuitems, ">\n");
-
- for (l = g_list_first (items), i = 1; l && i <= limit; l = l->next, ++i) {
- GtkRecentInfo *info = ((GtkRecentInfo *)(l->data));
- const gchar *info_dn = gtk_recent_info_get_display_name (info);
- char *display_name, *u;
-
- /* escape _'s in the display name so that it doesn't become an underline in a GtkLabel */
- if ((u = strchr (info_dn, '_'))) {
- int extra = 1;
- char *d;
- const char *s;
-
- while ((u = strchr (u + 1, '_')))
- extra++;
-
- d = display_name = g_alloca (strlen (info_dn) + extra + 1);
- s = info_dn;
- while (*s != '\0') {
- if (*s == '_')
- *d++ = '_';
- *d++ = *s++;
- }
- *d = '\0';
- } else
- display_name = (char *) info_dn;
-
- /* Add menu item */
- label = g_strdup (display_name);
- encoded_label = bonobo_ui_util_encode_str (label);
- g_string_append_printf (menuitems,
- " <menuitem name=\"Recent-%d\" verb=\"\" label=\"%s\"/>\n",
- i, encoded_label);
- g_free (encoded_label);
- g_free (label);
- }
-
- g_string_append (menuitems, "</submenu>\n");
-
- bonobo_ui_component_set (uic, path, menuitems->str, NULL);
-
- g_string_free (menuitems, TRUE);
-
- /* Add uri prop */
- for (l = g_list_first (items), i = 1; l && i <= limit; l = l->next, ++i) {
- GtkRecentInfo *info = ((GtkRecentInfo *)(l->data));
- const gchar *info_uri = gtk_recent_info_get_uri (info);
- label = g_strdup_printf ("/commands/Recent-%d", i);
- bonobo_ui_component_set_prop (uic, label, "uri", info_uri, NULL);
- g_free (label);
- }
-
- /* Add verb */
- for (l = g_list_first (items), i = 1; l && i <= limit; l = l->next, ++i) {
- label = g_strdup_printf ("Recent-%d", i);
- bonobo_ui_component_add_verb (uic, label, verb_cb, user_data);
- g_free (label);
- }
-
- for (l = g_list_first (items); l; l = l->next)
- gtk_recent_info_unref ((GtkRecentInfo *)(l->data));
- g_list_free (items);
-}
-
-static void
-action_recent_cb (GtkAction *action,
- EAttachmentBar *attachment_bar)
-{
- GtkRecentChooser *chooser;
- GFile *file;
- gchar *uri;
-
- chooser = GTK_RECENT_CHOOSER (action);
-
- /* Wish: gtk_recent_chooser_get_current_file() */
- uri = gtk_recent_chooser_get_current_uri (chooser);
- file = g_file_new_for_uri (uri);
- g_free (uri);
-
- if (g_file_is_native (file))
- e_attachment_bar_attach (
- E_ATTACHMENT_BAR (attachment_bar),
- g_file_get_path (file), "attachment");
- else
- e_attachment_bar_attach_remote_file (
- E_ATTACHMENT_BAR (attachment_bar),
- g_file_get_uri (file), "attachment");
-
- g_object_unref (file);
-}
-
-GtkAction *
-e_attachment_bar_recent_action_new (EAttachmentBar *bar,
- const gchar *action_name,
- const gchar *action_label)
-{
- GtkAction *action;
- GtkRecentChooser *chooser;
-
- g_return_val_if_fail (E_IS_ATTACHMENT_BAR (bar), NULL);
-
- action = gtk_recent_action_new (
- action_name, action_label, NULL, NULL);
- gtk_recent_action_set_show_numbers (GTK_RECENT_ACTION (action), TRUE);
-
- chooser = GTK_RECENT_CHOOSER (action);
- gtk_recent_chooser_set_show_icons (chooser, TRUE);
- gtk_recent_chooser_set_show_not_found (chooser, FALSE);
- gtk_recent_chooser_set_show_private (chooser, FALSE);
- gtk_recent_chooser_set_show_tips (chooser, TRUE);
- gtk_recent_chooser_set_sort_type (chooser, GTK_RECENT_SORT_MRU);
-
- g_signal_connect (
- action, "item-activated",
- G_CALLBACK (action_recent_cb), bar);
-
- return action;
-}
-
diff --git a/widgets/misc/e-attachment-bar.h b/widgets/misc/e-attachment-bar.h
deleted file mode 100644
index 7f8b4795d1..0000000000
--- a/widgets/misc/e-attachment-bar.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * 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:
- * Ettore Perazzoli <ettore@ximian.com>
- * Srinivasa Ragavan <sragavan@novell.com>
- *
- * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
- *
- */
-
-#ifndef __E_ATTACHMENT_BAR_H__
-#define __E_ATTACHMENT_BAR_H__
-
-#include <libgnomeui/gnome-icon-list.h>
-
-#include <bonobo/bonobo-ui-node.h>
-#include <bonobo/bonobo-ui-util.h>
-
-#include <camel/camel-multipart.h>
-#include "e-attachment.h"
-
-#ifdef __cplusplus
-extern "C" {
-#pragma }
-#endif /* __cplusplus */
-
-#define E_TYPE_ATTACHMENT_BAR \
- (e_attachment_bar_get_type ())
-#define E_ATTACHMENT_BAR(obj) \
- (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_ATTACHMENT_BAR, EAttachmentBar))
-#define E_ATTACHMENT_BAR_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_ATTACHMENT_BAR, EAttachmentBarClass))
-#define E_IS_ATTACHMENT_BAR(obj) \
- (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_ATTACHMENT_BAR))
-#define E_IS_ATTACHMENT_BAR_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_TYPE ((obj), E_TYPE_ATTACHMENT_BAR))
-
-typedef struct _EAttachmentBar EAttachmentBar;
-typedef struct _EAttachmentBarClass EAttachmentBarClass;
-
-struct _EAttachmentBar {
- GnomeIconList parent;
- gboolean expand;
-
- struct _EAttachmentBarPrivate *priv;
-};
-
-struct _EAttachmentBarClass {
- GnomeIconListClass parent_class;
-
- void (* changed) (EAttachmentBar *bar);
-};
-
-
-GType e_attachment_bar_get_type (void);
-
-GtkWidget *e_attachment_bar_new (GtkAdjustment *adj);
-void e_attachment_bar_to_multipart (EAttachmentBar *bar, CamelMultipart *multipart,
- const char *default_charset);
-guint e_attachment_bar_get_num_attachments (EAttachmentBar *bar);
-void e_attachment_bar_attach (EAttachmentBar *bar, const char *file_name, const char *disposition);
-void e_attachment_bar_attach_mime_part (EAttachmentBar *bar, CamelMimePart *part);
-int e_attachment_bar_get_download_count (EAttachmentBar *bar);
-void e_attachment_bar_attach_remote_file (EAttachmentBar *bar, const char *url, const char *disposition);
-GSList *e_attachment_bar_get_attachment (EAttachmentBar *bar, int id);
-void e_attachment_bar_add_attachment (EAttachmentBar *bar, EAttachment *attachment);
-void e_attachment_bar_edit_selected (EAttachmentBar *bar);
-void e_attachment_bar_remove_selected (EAttachmentBar *bar);
-GtkWidget ** e_attachment_bar_get_selector(EAttachmentBar *bar);
-GSList *e_attachment_bar_get_parts (EAttachmentBar *bar);
-GSList *e_attachment_bar_get_selected (EAttachmentBar *bar);
-void e_attachment_bar_set_width(EAttachmentBar *bar, int bar_width);
-GSList * e_attachment_bar_get_all_attachments (EAttachmentBar *bar);
-void e_attachment_bar_create_attachment_cache (EAttachment *attachment);
-void
-e_attachment_bar_bonobo_ui_populate_with_recent (BonoboUIComponent *uic, const char *path,
- EAttachmentBar *bar,
- BonoboUIVerbFn verb_cb, gpointer user_data);
-GtkAction *
-e_attachment_bar_recent_action_new (EAttachmentBar *bar,
- const gchar *action_name,
- const gchar *action_label);
-void
-e_attachment_bar_add_attachment_silent (EAttachmentBar *bar, EAttachment *attachment);
-void
-e_attachment_bar_refresh (EAttachmentBar *bar);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif /* __E_ATTACHMENT_BAR_H__ */
diff --git a/widgets/misc/e-attachment.c b/widgets/misc/e-attachment.c
index 4f5e9ace34..f472a26ff3 100644
--- a/widgets/misc/e-attachment.c
+++ b/widgets/misc/e-attachment.c
@@ -1,4 +1,5 @@
/*
+ * e-attachment.c
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -14,162 +15,845 @@
* License along with the program; if not, see <http://www.gnu.org/licenses/>
*
*
- * Authors:
- * Ettore Perazzoli <ettore@ximian.com>
- * Jeffrey Stedfast <fejj@ximian.com>
- * Srinivasa Ragavan <sragavan@novell.com>
- *
* Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
*
*/
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#ifdef G_OS_WIN32
-/* Include <windows.h> early (as the gio stuff below will
- * include it anyway, sigh) to workaround the DATADIR problem.
- * <windows.h> (and the headers it includes) stomps all over the
- * namespace like a baboon on crack, and especially the DATADIR enum
- * in objidl.h causes problems.
- */
-#undef DATADIR
-#define DATADIR crap_DATADIR
-#include <windows.h>
-#undef DATADIR
-#endif
+#include "e-attachment.h"
-#include <sys/stat.h>
-#include <string.h>
#include <errno.h>
-
-#include <camel/camel.h>
-
+#include <config.h>
#include <glib/gi18n.h>
-#include <glib/gstdio.h>
-
-#include <libebook/e-vcard.h>
+#include <camel/camel-iconv.h>
+#include <camel/camel-data-wrapper.h>
+#include <camel/camel-mime-message.h>
+#include <camel/camel-stream-filter.h>
+#include <camel/camel-stream-mem.h>
+#include <camel/camel-stream-null.h>
+#include <camel/camel-stream-vfs.h>
#include "e-util/e-util.h"
-#include "e-util/e-error.h"
#include "e-util/e-mktemp.h"
-#include "e-util/e-util-private.h"
-
-#include "e-attachment.h"
+#include "e-attachment-store.h"
+
+#define E_ATTACHMENT_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_ATTACHMENT, EAttachmentPrivate))
+
+/* Fallback Icon */
+#define DEFAULT_ICON_NAME "mail-attachment"
+
+/* Emblems */
+#define EMBLEM_CANCELLED "gtk-cancel"
+#define EMBLEM_LOADING "emblem-downloads"
+#define EMBLEM_SAVING "document-save"
+#define EMBLEM_ENCRYPT_WEAK "security-low"
+#define EMBLEM_ENCRYPT_STRONG "security-high"
+#define EMBLEM_ENCRYPT_UNKNOWN "security-medium"
+#define EMBLEM_SIGN_BAD "stock_signature_bad"
+#define EMBLEM_SIGN_GOOD "stock_signature-ok"
+#define EMBLEM_SIGN_UNKNOWN "stock_signature"
+
+/* Attributes needed for EAttachmentStore columns. */
+#define ATTACHMENT_QUERY "standard::*,preview::*,thumbnail::*"
+
+struct _EAttachmentPrivate {
+ GFile *file;
+ GFileInfo *file_info;
+ GCancellable *cancellable;
+ CamelMimePart *mime_part;
+ guint emblem_timeout_id;
+ gchar *disposition;
+ gint percent;
+
+ guint can_show : 1;
+ guint loading : 1;
+ guint saving : 1;
+ guint shown : 1;
+
+ camel_cipher_validity_encrypt_t encrypted;
+ camel_cipher_validity_sign_t signed_;
+
+ /* This is a reference to our row in an EAttachmentStore,
+ * serving as a means of broadcasting "row-changed" signals.
+ * If we are removed from the store, we lazily free the
+ * reference when it is found to be to be invalid. */
+ GtkTreeRowReference *reference;
+};
enum {
- CHANGED,
- UPDATE,
- LAST_SIGNAL
+ PROP_0,
+ PROP_CAN_SHOW,
+ PROP_DISPOSITION,
+ PROP_ENCRYPTED,
+ PROP_FILE,
+ PROP_FILE_INFO,
+ PROP_LOADING,
+ PROP_MIME_PART,
+ PROP_PERCENT,
+ PROP_REFERENCE,
+ PROP_SAVING,
+ PROP_SHOWN,
+ PROP_SIGNED
};
-static guint signals[LAST_SIGNAL] = { 0 };
+static gpointer parent_class;
-static GObjectClass *parent_class = NULL;
+static gchar *
+attachment_get_default_charset (void)
+{
+ GConfClient *client;
+ const gchar *key;
+ gchar *charset;
+
+ /* XXX This doesn't really belong here. */
+
+ client = gconf_client_get_default ();
+ key = "/apps/evolution/mail/composer/charset";
+ charset = gconf_client_get_string (client, key, NULL);
+ if (charset == NULL || *charset == '\0') {
+ g_free (charset);
+ key = "/apps/evolution/mail/format/charset";
+ charset = gconf_client_get_string (client, key, NULL);
+ if (charset == NULL || *charset == '\0') {
+ g_free (charset);
+ charset = NULL;
+ }
+ }
+ g_object_unref (client);
+
+ if (charset == NULL)
+ charset = g_strdup (camel_iconv_locale_charset ());
+
+ if (charset == NULL)
+ charset = g_strdup ("us-ascii");
+
+ return charset;
+}
static void
-changed (EAttachment *attachment)
+attachment_update_file_info_columns (EAttachment *attachment)
{
- g_signal_emit (attachment, signals[CHANGED], 0);
-}
+ GtkTreeRowReference *reference;
+ GtkTreeModel *model;
+ GtkTreePath *path;
+ GtkTreeIter iter;
+ GFileInfo *file_info;
+ const gchar *content_type;
+ const gchar *description;
+ const gchar *display_name;
+ gchar *content_desc;
+ gchar *display_size;
+ gchar *caption;
+ goffset size;
+
+ reference = e_attachment_get_reference (attachment);
+ if (!gtk_tree_row_reference_valid (reference))
+ return;
+
+ file_info = e_attachment_get_file_info (attachment);
+ if (file_info == NULL)
+ return;
+
+ model = gtk_tree_row_reference_get_model (reference);
+ path = gtk_tree_row_reference_get_path (reference);
+ gtk_tree_model_get_iter (model, &iter, path);
+ gtk_tree_path_free (path);
+
+ content_type = g_file_info_get_content_type (file_info);
+ display_name = g_file_info_get_display_name (file_info);
+ size = g_file_info_get_size (file_info);
+ content_desc = g_content_type_get_description (content_type);
+ display_size = g_format_size_for_display (size);
-/* GtkObject methods. */
+ description = e_attachment_get_description (attachment);
+ if (description == NULL || *description == '\0')
+ description = display_name;
+
+ if (size > 0)
+ caption = g_strdup_printf (
+ "%s\n(%s)", description, display_size);
+ else
+ caption = g_strdup (description);
+
+ gtk_list_store_set (
+ GTK_LIST_STORE (model), &iter,
+ E_ATTACHMENT_STORE_COLUMN_CAPTION, caption,
+ E_ATTACHMENT_STORE_COLUMN_CONTENT_TYPE, content_desc,
+ E_ATTACHMENT_STORE_COLUMN_DESCRIPTION, description,
+ E_ATTACHMENT_STORE_COLUMN_SIZE, size,
+ -1);
+
+ g_free (content_desc);
+ g_free (display_size);
+ g_free (caption);
+}
static void
-finalise (GObject *object)
+attachment_update_icon_column (EAttachment *attachment)
{
- EAttachment *attachment = (EAttachment *) object;
- GtkWidget *dialog;
+ GtkTreeRowReference *reference;
+ GtkTreeModel *model;
+ GtkTreePath *path;
+ GtkTreeIter iter;
+ GFileInfo *file_info;
+ GCancellable *cancellable;
+ GIcon *icon = NULL;
+ const gchar *emblem_name = NULL;
+ const gchar *thumbnail_path = NULL;
- if (attachment->editor_gui != NULL) {
- dialog = glade_xml_get_widget (attachment->editor_gui, "dialog");
- g_signal_emit_by_name (dialog, "response", GTK_RESPONSE_CLOSE);
+ reference = e_attachment_get_reference (attachment);
+ if (!gtk_tree_row_reference_valid (reference))
+ return;
+
+ model = gtk_tree_row_reference_get_model (reference);
+ path = gtk_tree_row_reference_get_path (reference);
+ gtk_tree_model_get_iter (model, &iter, path);
+ gtk_tree_path_free (path);
+
+ cancellable = attachment->priv->cancellable;
+ file_info = e_attachment_get_file_info (attachment);
+
+ if (file_info != NULL) {
+ icon = g_file_info_get_icon (file_info);
+ thumbnail_path = g_file_info_get_attribute_byte_string (
+ file_info, G_FILE_ATTRIBUTE_THUMBNAIL_PATH);
}
- if (attachment->is_available_local) {
- camel_object_unref (attachment->body);
- if (attachment->pixbuf_cache != NULL)
- g_object_unref (attachment->pixbuf_cache);
- } else {
- if (attachment->cancellable) {
- /* the operation is still running, so cancel it */
- g_cancellable_cancel (attachment->cancellable);
- attachment->cancellable = NULL;
+ /* Prefer the thumbnail if we have one. */
+ if (thumbnail_path != NULL && *thumbnail_path != '\0') {
+ GFile *file;
+
+ file = g_file_new_for_path (thumbnail_path);
+ icon = g_file_icon_new (file);
+ g_object_unref (file);
+
+ /* Else use the standard icon for the content type. */
+ } else if (icon != NULL)
+ g_object_ref (icon);
+
+ /* Last ditch fallback. (GFileInfo not yet loaded?) */
+ else
+ icon = g_themed_icon_new (DEFAULT_ICON_NAME);
+
+ /* Pick an emblem, limit one. Choices listed by priority. */
+
+ if (g_cancellable_is_cancelled (cancellable))
+ emblem_name = EMBLEM_CANCELLED;
+
+ else if (e_attachment_get_loading (attachment))
+ emblem_name = EMBLEM_LOADING;
+
+ else if (e_attachment_get_saving (attachment))
+ emblem_name = EMBLEM_SAVING;
+
+ else if (e_attachment_get_encrypted (attachment))
+ switch (e_attachment_get_encrypted (attachment)) {
+ case CAMEL_CIPHER_VALIDITY_ENCRYPT_WEAK:
+ emblem_name = EMBLEM_ENCRYPT_WEAK;
+ break;
+
+ case CAMEL_CIPHER_VALIDITY_ENCRYPT_ENCRYPTED:
+ emblem_name = EMBLEM_ENCRYPT_UNKNOWN;
+ break;
+
+ case CAMEL_CIPHER_VALIDITY_ENCRYPT_STRONG:
+ emblem_name = EMBLEM_ENCRYPT_STRONG;
+ break;
+
+ default:
+ g_warn_if_reached ();
+ break;
}
- g_free (attachment->description);
+
+ else if (e_attachment_get_signed (attachment))
+ switch (e_attachment_get_signed (attachment)) {
+ case CAMEL_CIPHER_VALIDITY_SIGN_GOOD:
+ emblem_name = EMBLEM_SIGN_GOOD;
+ break;
+
+ case CAMEL_CIPHER_VALIDITY_SIGN_BAD:
+ emblem_name = EMBLEM_SIGN_BAD;
+ break;
+
+ case CAMEL_CIPHER_VALIDITY_SIGN_UNKNOWN:
+ case CAMEL_CIPHER_VALIDITY_SIGN_NEED_PUBLIC_KEY:
+ emblem_name = EMBLEM_SIGN_UNKNOWN;
+ break;
+
+ default:
+ g_warn_if_reached ();
+ break;
+ }
+
+ if (emblem_name != NULL) {
+ GIcon *emblemed_icon;
+ GEmblem *emblem;
+
+ emblemed_icon = g_themed_icon_new (emblem_name);
+ emblem = g_emblem_new (emblemed_icon);
+ g_object_unref (emblemed_icon);
+
+ emblemed_icon = g_emblemed_icon_new (icon, emblem);
+ g_object_unref (emblem);
+ g_object_unref (icon);
+
+ icon = emblemed_icon;
}
- g_free (attachment->file_name);
- g_free (attachment->store_uri);
+ gtk_list_store_set (
+ GTK_LIST_STORE (model), &iter,
+ E_ATTACHMENT_STORE_COLUMN_ICON, icon,
+ -1);
- G_OBJECT_CLASS (parent_class)->finalize (object);
+ g_object_unref (icon);
}
+static void
+attachment_update_progress_columns (EAttachment *attachment)
+{
+ GtkTreeRowReference *reference;
+ GtkTreeModel *model;
+ GtkTreePath *path;
+ GtkTreeIter iter;
+ gboolean loading;
+ gboolean saving;
+ gint percent;
+
+ reference = e_attachment_get_reference (attachment);
+ if (!gtk_tree_row_reference_valid (reference))
+ return;
-/* Signals. */
+ model = gtk_tree_row_reference_get_model (reference);
+ path = gtk_tree_row_reference_get_path (reference);
+ gtk_tree_model_get_iter (model, &iter, path);
+ gtk_tree_path_free (path);
+
+ /* Don't show progress bars until we have progress to report. */
+ percent = e_attachment_get_percent (attachment);
+ loading = e_attachment_get_loading (attachment) && (percent > 0);
+ saving = e_attachment_get_saving (attachment) && (percent > 0);
+
+ gtk_list_store_set (
+ GTK_LIST_STORE (model), &iter,
+ E_ATTACHMENT_STORE_COLUMN_LOADING, loading,
+ E_ATTACHMENT_STORE_COLUMN_PERCENT, percent,
+ E_ATTACHMENT_STORE_COLUMN_SAVING, saving,
+ -1);
+}
static void
-real_changed (EAttachment *attachment)
+attachment_set_file_info (EAttachment *attachment,
+ GFileInfo *file_info)
{
- g_return_if_fail (E_IS_ATTACHMENT (attachment));
+ GtkTreeRowReference *reference;
+ GIcon *icon;
+
+ reference = e_attachment_get_reference (attachment);
+
+ if (file_info != NULL)
+ g_object_ref (file_info);
+
+ if (attachment->priv->file_info != NULL)
+ g_object_unref (attachment->priv->file_info);
+
+ attachment->priv->file_info = file_info;
+
+ /* If the GFileInfo contains a GThemedIcon, append a
+ * fallback icon name to ensure we display something. */
+ icon = g_file_info_get_icon (file_info);
+ if (G_IS_THEMED_ICON (icon))
+ g_themed_icon_append_name (
+ G_THEMED_ICON (icon), DEFAULT_ICON_NAME);
+
+ g_object_notify (G_OBJECT (attachment), "file-info");
+
+ /* Tell the EAttachmentStore its total size changed. */
+ if (gtk_tree_row_reference_valid (reference)) {
+ GtkTreeModel *model;
+ model = gtk_tree_row_reference_get_model (reference);
+ g_object_notify (G_OBJECT (model), "total-size");
+ }
}
static void
-real_update_attachment (EAttachment *attachment, char *msg)
+attachment_set_loading (EAttachment *attachment,
+ gboolean loading)
{
- g_return_if_fail (E_IS_ATTACHMENT (attachment));
+ GtkTreeRowReference *reference;
+
+ reference = e_attachment_get_reference (attachment);
+
+ attachment->priv->percent = 0;
+ attachment->priv->loading = loading;
+
+ g_object_freeze_notify (G_OBJECT (attachment));
+ g_object_notify (G_OBJECT (attachment), "percent");
+ g_object_notify (G_OBJECT (attachment), "loading");
+ g_object_thaw_notify (G_OBJECT (attachment));
+
+ if (gtk_tree_row_reference_valid (reference)) {
+ GtkTreeModel *model;
+ model = gtk_tree_row_reference_get_model (reference);
+ g_object_notify (G_OBJECT (model), "num-loading");
+ }
+}
+
+static void
+attachment_set_saving (EAttachment *attachment,
+ gboolean saving)
+{
+ attachment->priv->percent = 0;
+ attachment->priv->saving = saving;
+
+ g_object_freeze_notify (G_OBJECT (attachment));
+ g_object_notify (G_OBJECT (attachment), "percent");
+ g_object_notify (G_OBJECT (attachment), "saving");
+ g_object_thaw_notify (G_OBJECT (attachment));
+}
+
+static void
+attachment_progress_cb (goffset current_num_bytes,
+ goffset total_num_bytes,
+ EAttachment *attachment)
+{
+ attachment->priv->percent =
+ (current_num_bytes * 100) / total_num_bytes;
+
+ g_object_notify (G_OBJECT (attachment), "percent");
+}
+
+static gboolean
+attachment_cancelled_timeout_cb (EAttachment *attachment)
+{
+ attachment->priv->emblem_timeout_id = 0;
+ g_cancellable_reset (attachment->priv->cancellable);
+
+ attachment_update_icon_column (attachment);
+
+ return FALSE;
+}
+
+static void
+attachment_cancelled_cb (EAttachment *attachment)
+{
+ /* Reset the GCancellable after one second. This causes a
+ * cancel emblem to be briefly shown on the attachment icon
+ * as visual feedback that an operation was cancelled. */
+
+ if (attachment->priv->emblem_timeout_id > 0)
+ g_source_remove (attachment->priv->emblem_timeout_id);
+
+ attachment->priv->emblem_timeout_id = g_timeout_add_seconds (
+ 1, (GSourceFunc) attachment_cancelled_timeout_cb, attachment);
+
+ attachment_update_icon_column (attachment);
+}
+
+static void
+attachment_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_CAN_SHOW:
+ e_attachment_set_can_show (
+ E_ATTACHMENT (object),
+ g_value_get_boolean (value));
+ return;
+
+ case PROP_DISPOSITION:
+ e_attachment_set_disposition (
+ E_ATTACHMENT (object),
+ g_value_get_string (value));
+ return;
+
+ case PROP_ENCRYPTED:
+ e_attachment_set_encrypted (
+ E_ATTACHMENT (object),
+ g_value_get_int (value));
+ return;
+
+ case PROP_FILE:
+ e_attachment_set_file (
+ E_ATTACHMENT (object),
+ g_value_get_object (value));
+ return;
+
+ case PROP_SHOWN:
+ e_attachment_set_shown (
+ E_ATTACHMENT (object),
+ g_value_get_boolean (value));
+ return;
+
+ case PROP_MIME_PART:
+ e_attachment_set_mime_part (
+ E_ATTACHMENT (object),
+ g_value_get_boxed (value));
+ return;
+
+ case PROP_REFERENCE:
+ e_attachment_set_reference (
+ E_ATTACHMENT (object),
+ g_value_get_boxed (value));
+ return;
+
+ case PROP_SIGNED:
+ e_attachment_set_signed (
+ E_ATTACHMENT (object),
+ g_value_get_int (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+attachment_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_CAN_SHOW:
+ g_value_set_boolean (
+ value, e_attachment_get_can_show (
+ E_ATTACHMENT (object)));
+ return;
+
+ case PROP_DISPOSITION:
+ g_value_set_string (
+ value, e_attachment_get_disposition (
+ E_ATTACHMENT (object)));
+ return;
+
+ case PROP_ENCRYPTED:
+ g_value_set_int (
+ value, e_attachment_get_encrypted (
+ E_ATTACHMENT (object)));
+ return;
+
+ case PROP_FILE:
+ g_value_set_object (
+ value, e_attachment_get_file (
+ E_ATTACHMENT (object)));
+ return;
+
+ case PROP_FILE_INFO:
+ g_value_set_object (
+ value, e_attachment_get_file_info (
+ E_ATTACHMENT (object)));
+ return;
+
+ case PROP_SHOWN:
+ g_value_set_boolean (
+ value, e_attachment_get_shown (
+ E_ATTACHMENT (object)));
+ return;
+
+ case PROP_LOADING:
+ g_value_set_boolean (
+ value, e_attachment_get_loading (
+ E_ATTACHMENT (object)));
+ return;
+
+ case PROP_MIME_PART:
+ g_value_set_boxed (
+ value, e_attachment_get_mime_part (
+ E_ATTACHMENT (object)));
+ return;
+
+ case PROP_PERCENT:
+ g_value_set_int (
+ value, e_attachment_get_percent (
+ E_ATTACHMENT (object)));
+ return;
+
+ case PROP_REFERENCE:
+ g_value_set_boxed (
+ value, e_attachment_get_reference (
+ E_ATTACHMENT (object)));
+ return;
+
+ case PROP_SAVING:
+ g_value_set_boolean (
+ value, e_attachment_get_saving (
+ E_ATTACHMENT (object)));
+ return;
+
+ case PROP_SIGNED:
+ g_value_set_int (
+ value, e_attachment_get_signed (
+ E_ATTACHMENT (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
+static void
+attachment_dispose (GObject *object)
+{
+ EAttachmentPrivate *priv;
+
+ priv = E_ATTACHMENT_GET_PRIVATE (object);
+
+ if (priv->file != NULL) {
+ g_object_unref (priv->file);
+ priv->file = NULL;
+ }
+
+ if (priv->file_info != NULL) {
+ g_object_unref (priv->file_info);
+ priv->file_info = NULL;
+ }
+
+ if (priv->cancellable != NULL) {
+ g_object_unref (priv->cancellable);
+ priv->cancellable = NULL;
+ }
+
+ if (priv->mime_part != NULL) {
+ camel_object_unref (priv->mime_part);
+ priv->mime_part = NULL;
+ }
+
+ if (priv->emblem_timeout_id > 0) {
+ g_source_remove (priv->emblem_timeout_id);
+ priv->emblem_timeout_id = 0;
+ }
+
+ /* This accepts NULL arguments. */
+ gtk_tree_row_reference_free (priv->reference);
+ priv->reference = NULL;
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
static void
-class_init (EAttachmentClass *klass)
+attachment_finalize (GObject *object)
+{
+ EAttachmentPrivate *priv;
+
+ priv = E_ATTACHMENT_GET_PRIVATE (object);
+
+ g_free (priv->disposition);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+attachment_class_init (EAttachmentClass *class)
{
GObjectClass *object_class;
- object_class = (GObjectClass*) klass;
- parent_class = g_type_class_ref (G_TYPE_OBJECT);
-
- object_class->finalize = finalise;
- klass->changed = real_changed;
- klass->update = real_update_attachment;
-
- signals[CHANGED] = g_signal_new ("changed",
- E_TYPE_ATTACHMENT,
- G_SIGNAL_RUN_FIRST,
- G_STRUCT_OFFSET (EAttachmentClass, changed),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
- signals[UPDATE] = g_signal_new ("update",
- E_TYPE_ATTACHMENT,
- G_SIGNAL_RUN_FIRST,
- G_STRUCT_OFFSET (EAttachmentClass, update),
- NULL,
- NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
-
-}
-
-static void
-init (EAttachment *attachment)
-{
- attachment->editor_gui = NULL;
- attachment->body = NULL;
- attachment->size = 0;
- attachment->pixbuf_cache = NULL;
- attachment->index = -1;
- attachment->file_name = NULL;
- attachment->percentage = -1;
- attachment->description = NULL;
- attachment->disposition = FALSE;
- attachment->sign = CAMEL_CIPHER_VALIDITY_SIGN_NONE;
- attachment->encrypt = CAMEL_CIPHER_VALIDITY_ENCRYPT_NONE;
- attachment->store_uri = NULL;
- attachment->cancellable = NULL;
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EAttachmentPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = attachment_set_property;
+ object_class->get_property = attachment_get_property;
+ object_class->dispose = attachment_dispose;
+ object_class->finalize = attachment_finalize;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_CAN_SHOW,
+ g_param_spec_boolean (
+ "can-show",
+ "Can Show",
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_DISPOSITION,
+ g_param_spec_string (
+ "disposition",
+ "Disposition",
+ NULL,
+ "attachment",
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+
+ /* FIXME Define a GEnumClass for this. */
+ g_object_class_install_property (
+ object_class,
+ PROP_ENCRYPTED,
+ g_param_spec_int (
+ "encrypted",
+ "Encrypted",
+ NULL,
+ CAMEL_CIPHER_VALIDITY_ENCRYPT_NONE,
+ CAMEL_CIPHER_VALIDITY_ENCRYPT_STRONG,
+ CAMEL_CIPHER_VALIDITY_ENCRYPT_NONE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_FILE,
+ g_param_spec_object (
+ "file",
+ "File",
+ NULL,
+ G_TYPE_FILE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_FILE_INFO,
+ g_param_spec_object (
+ "file-info",
+ "File Info",
+ NULL,
+ G_TYPE_FILE_INFO,
+ G_PARAM_READABLE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_LOADING,
+ g_param_spec_boolean (
+ "loading",
+ "Loading",
+ NULL,
+ FALSE,
+ G_PARAM_READABLE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_MIME_PART,
+ g_param_spec_boxed (
+ "mime-part",
+ "MIME Part",
+ NULL,
+ E_TYPE_CAMEL_OBJECT,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_PERCENT,
+ g_param_spec_int (
+ "percent",
+ "Percent",
+ NULL,
+ 0,
+ 100,
+ 0,
+ G_PARAM_READABLE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_REFERENCE,
+ g_param_spec_boxed (
+ "reference",
+ "Reference",
+ NULL,
+ GTK_TYPE_TREE_ROW_REFERENCE,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_SAVING,
+ g_param_spec_boolean (
+ "saving",
+ "Saving",
+ NULL,
+ FALSE,
+ G_PARAM_READABLE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_SHOWN,
+ g_param_spec_boolean (
+ "shown",
+ "Shown",
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+
+ /* FIXME Define a GEnumClass for this. */
+ g_object_class_install_property (
+ object_class,
+ PROP_SIGNED,
+ g_param_spec_int (
+ "signed",
+ "Signed",
+ NULL,
+ CAMEL_CIPHER_VALIDITY_SIGN_NONE,
+ CAMEL_CIPHER_VALIDITY_SIGN_NEED_PUBLIC_KEY,
+ CAMEL_CIPHER_VALIDITY_SIGN_NONE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+}
+
+static void
+attachment_init (EAttachment *attachment)
+{
+ attachment->priv = E_ATTACHMENT_GET_PRIVATE (attachment);
+ attachment->priv->cancellable = g_cancellable_new ();
+ attachment->priv->encrypted = CAMEL_CIPHER_VALIDITY_ENCRYPT_NONE;
+ attachment->priv->signed_ = CAMEL_CIPHER_VALIDITY_SIGN_NONE;
+
+ g_signal_connect (
+ attachment, "notify::encrypted",
+ G_CALLBACK (attachment_update_icon_column), NULL);
+
+ g_signal_connect (
+ attachment, "notify::file-info",
+ G_CALLBACK (attachment_update_file_info_columns), NULL);
+
+ g_signal_connect (
+ attachment, "notify::file-info",
+ G_CALLBACK (attachment_update_icon_column), NULL);
+
+ g_signal_connect (
+ attachment, "notify::loading",
+ G_CALLBACK (attachment_update_icon_column), NULL);
+
+ g_signal_connect (
+ attachment, "notify::loading",
+ G_CALLBACK (attachment_update_progress_columns), NULL);
+
+ g_signal_connect (
+ attachment, "notify::percent",
+ G_CALLBACK (attachment_update_progress_columns), NULL);
+
+ g_signal_connect (
+ attachment, "notify::reference",
+ G_CALLBACK (attachment_update_file_info_columns), NULL);
+
+ g_signal_connect (
+ attachment, "notify::reference",
+ G_CALLBACK (attachment_update_icon_column), NULL);
+
+ g_signal_connect (
+ attachment, "notify::reference",
+ G_CALLBACK (attachment_update_progress_columns), NULL);
+
+ g_signal_connect (
+ attachment, "notify::saving",
+ G_CALLBACK (attachment_update_icon_column), NULL);
+
+ g_signal_connect (
+ attachment, "notify::saving",
+ G_CALLBACK (attachment_update_progress_columns), NULL);
+
+ g_signal_connect (
+ attachment, "notify::signed",
+ G_CALLBACK (attachment_update_icon_column), NULL);
+
+ g_signal_connect_swapped (
+ attachment->priv->cancellable, "cancelled",
+ G_CALLBACK (attachment_cancelled_cb), attachment);
}
GType
@@ -177,707 +861,1814 @@ e_attachment_get_type (void)
{
static GType type = 0;
- if (type == 0) {
- static const GTypeInfo info = {
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo type_info = {
sizeof (EAttachmentClass),
- NULL,
- NULL,
- (GClassInitFunc) class_init,
- NULL,
- NULL,
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) attachment_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
sizeof (EAttachment),
- 0,
- (GInstanceInitFunc) init,
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) attachment_init,
+ NULL /* value_table */
};
- type = g_type_register_static (G_TYPE_OBJECT, "EAttachment", &info, 0);
+ type = g_type_register_static (
+ G_TYPE_OBJECT, "EAttachment", &type_info, 0);
}
return type;
}
-/**
- * file_ext_is:
- * @param file_name: path for file
- * @param ext: desired extension, with a dot
- * @return if file_name has extension ext or not
- **/
+EAttachment *
+e_attachment_new (void)
+{
+ return g_object_new (E_TYPE_ATTACHMENT, NULL);
+}
-static gboolean
-file_ext_is (const char *file_name, const char *ext)
+EAttachment *
+e_attachment_new_for_path (const gchar *path)
{
- int i, dot = -1;
+ EAttachment *attachment;
+ GFile *file;
- if (!file_name || !ext)
- return FALSE;
+ g_return_val_if_fail (path != NULL, NULL);
- for (i = 0; file_name[i]; i++) {
- if (file_name [i] == '.')
- dot = i;
- }
+ file = g_file_new_for_path (path);
+ attachment = g_object_new (E_TYPE_ATTACHMENT, "file", file, NULL);
+ g_object_unref (file);
- if (dot > 0) {
- return 0 == g_ascii_strcasecmp (file_name + dot, ext);
- }
+ return attachment;
+}
- return FALSE;
+EAttachment *
+e_attachment_new_for_uri (const gchar *uri)
+{
+ EAttachment *attachment;
+ GFile *file;
+
+ g_return_val_if_fail (uri != NULL, NULL);
+
+ file = g_file_new_for_uri (uri);
+ attachment = g_object_new (E_TYPE_ATTACHMENT, "file", file, NULL);
+ g_object_unref (file);
+
+ return attachment;
}
-static char *
-attachment_guess_mime_type (const char *file_name)
+EAttachment *
+e_attachment_new_for_message (CamelMimeMessage *message)
{
- char *type;
- gchar *content = NULL;
+ CamelDataWrapper *wrapper;
+ CamelMimePart *mime_part;
+ EAttachment *attachment;
+ GString *description;
+ const gchar *subject;
- type = e_util_guess_mime_type (file_name, TRUE);
+ g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), NULL);
- if (type && strcmp (type, "text/directory") == 0 &&
- file_ext_is (file_name, ".vcf") &&
- g_file_get_contents (file_name, &content, NULL, NULL) &&
- content) {
- EVCard *vc = e_vcard_new_from_string (content);
+ mime_part = camel_mime_part_new ();
+ camel_mime_part_set_disposition (mime_part, "inline");
+ subject = camel_mime_message_get_subject (message);
- if (vc) {
- g_free (type);
- g_object_unref (G_OBJECT (vc));
+ description = g_string_new (_("Attached message"));
+ if (subject != NULL)
+ g_string_append_printf (description, " - %s", subject);
+ camel_mime_part_set_description (mime_part, description->str);
+ g_string_free (description, TRUE);
+
+ wrapper = CAMEL_DATA_WRAPPER (message);
+ camel_medium_set_content_object (CAMEL_MEDIUM (mime_part), wrapper);
+ camel_mime_part_set_content_type (mime_part, "message/rfc822");
+
+ attachment = e_attachment_new ();
+ e_attachment_set_mime_part (attachment, mime_part);
+ camel_object_unref (mime_part);
+
+ return attachment;
+}
+
+void
+e_attachment_add_to_multipart (EAttachment *attachment,
+ CamelMultipart *multipart,
+ const gchar *default_charset)
+{
+ CamelContentType *content_type;
+ CamelDataWrapper *wrapper;
+ CamelMimePart *mime_part;
+
+ /* XXX EMsgComposer might be a better place for this function. */
+
+ g_return_if_fail (E_IS_ATTACHMENT (attachment));
+ g_return_if_fail (CAMEL_IS_MULTIPART (multipart));
+
+ /* Still loading? Too bad. */
+ mime_part = e_attachment_get_mime_part (attachment);
+ if (mime_part == NULL)
+ return;
+
+ content_type = camel_mime_part_get_content_type (mime_part);
+ wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (mime_part));
+
+ if (CAMEL_IS_MULTIPART (wrapper))
+ goto exit;
+
+ /* For text content, determine the best encoding and character set. */
+ if (camel_content_type_is (content_type, "text", "*")) {
+ CamelTransferEncoding encoding;
+ CamelStreamFilter *filtered_stream;
+ CamelMimeFilterBestenc *filter;
+ CamelStream *stream;
+ const gchar *charset;
+
+ charset = camel_content_type_param (content_type, "charset");
+
+ /* Determine the best encoding by writing the MIME
+ * part to a NULL stream with a "bestenc" filter. */
+ stream = camel_stream_null_new ();
+ filtered_stream = camel_stream_filter_new_with_stream (stream);
+ filter = camel_mime_filter_bestenc_new (
+ CAMEL_BESTENC_GET_ENCODING);
+ camel_stream_filter_add (
+ filtered_stream, CAMEL_MIME_FILTER (filter));
+ camel_data_wrapper_decode_to_stream (
+ wrapper, CAMEL_STREAM (filtered_stream));
+ camel_object_unref (filtered_stream);
+ camel_object_unref (stream);
+
+ /* Retrieve the best encoding from the filter. */
+ encoding = camel_mime_filter_bestenc_get_best_encoding (
+ filter, CAMEL_BESTENC_8BIT);
+ camel_mime_part_set_encoding (mime_part, encoding);
+ camel_object_unref (filter);
+
+ if (encoding == CAMEL_TRANSFER_ENCODING_7BIT) {
+ /* The text fits within us-ascii, so this is safe.
+ * FIXME Check that this isn't iso-2022-jp? */
+ default_charset = "us-ascii";
+
+ } else if (charset == NULL && default_charset == NULL) {
+ default_charset = attachment_get_default_charset ();
+ /* FIXME Check that this fits within the
+ * default_charset and if not, find one
+ * that does and/or allow the user to
+ * specify. */
+ }
- type = g_strdup ("text/x-vcard");
+ if (charset == NULL) {
+ gchar *type;
+
+ camel_content_type_set_param (
+ content_type, "charset", default_charset);
+ type = camel_content_type_format (content_type);
+ camel_mime_part_set_content_type (mime_part, type);
+ g_free (type);
}
+ /* Otherwise, unless it's a message/rfc822, Base64 encode it. */
+ } else if (!CAMEL_IS_MIME_MESSAGE (wrapper))
+ camel_mime_part_set_encoding (
+ mime_part, CAMEL_TRANSFER_ENCODING_BASE64);
+
+exit:
+ camel_multipart_add_part (multipart, mime_part);
+}
+
+void
+e_attachment_cancel (EAttachment *attachment)
+{
+ g_return_if_fail (E_IS_ATTACHMENT (attachment));
+
+ g_cancellable_cancel (attachment->priv->cancellable);
+}
+
+gboolean
+e_attachment_get_can_show (EAttachment *attachment)
+{
+ g_return_val_if_fail (E_IS_ATTACHMENT (attachment), FALSE);
+
+ return attachment->priv->can_show;
+}
+
+void
+e_attachment_set_can_show (EAttachment *attachment,
+ gboolean can_show)
+{
+ g_return_if_fail (E_IS_ATTACHMENT (attachment));
+
+ attachment->priv->can_show = can_show;
+
+ g_object_notify (G_OBJECT (attachment), "can-show");
+}
+
+const gchar *
+e_attachment_get_disposition (EAttachment *attachment)
+{
+ g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL);
+
+ return attachment->priv->disposition;
+}
+
+void
+e_attachment_set_disposition (EAttachment *attachment,
+ const gchar *disposition)
+{
+ g_return_if_fail (E_IS_ATTACHMENT (attachment));
+
+ g_free (attachment->priv->disposition);
+ attachment->priv->disposition = g_strdup (disposition);
+
+ g_object_notify (G_OBJECT (attachment), "disposition");
+}
+
+GFile *
+e_attachment_get_file (EAttachment *attachment)
+{
+ g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL);
+
+ return attachment->priv->file;
+}
+
+void
+e_attachment_set_file (EAttachment *attachment,
+ GFile *file)
+{
+ g_return_if_fail (E_IS_ATTACHMENT (attachment));
+
+ if (file != NULL) {
+ g_return_if_fail (G_IS_FILE (file));
+ g_object_ref (file);
}
- g_free (content);
+ if (attachment->priv->file != NULL)
+ g_object_unref (attachment->priv->file);
- if (type) {
- /* Check if returned mime_type is valid */
- CamelContentType *ctype = camel_content_type_decode (type);
+ attachment->priv->file = file;
- if (!ctype) {
- g_free (type);
- type = NULL;
- } else
- camel_content_type_unref (ctype);
+ g_object_notify (G_OBJECT (attachment), "file");
+}
+
+GFileInfo *
+e_attachment_get_file_info (EAttachment *attachment)
+{
+ g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL);
+
+ return attachment->priv->file_info;
+}
+
+gboolean
+e_attachment_get_loading (EAttachment *attachment)
+{
+ g_return_val_if_fail (E_IS_ATTACHMENT (attachment), FALSE);
+
+ return attachment->priv->loading;
+}
+
+CamelMimePart *
+e_attachment_get_mime_part (EAttachment *attachment)
+{
+ g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL);
+
+ return attachment->priv->mime_part;
+}
+
+void
+e_attachment_set_mime_part (EAttachment *attachment,
+ CamelMimePart *mime_part)
+{
+ g_return_if_fail (E_IS_ATTACHMENT (attachment));
+
+ if (mime_part != NULL) {
+ g_return_if_fail (CAMEL_IS_MIME_PART (mime_part));
+ camel_object_ref (mime_part);
}
- return type;
+ if (attachment->priv->mime_part != NULL)
+ camel_object_unref (attachment->priv->mime_part);
+
+ attachment->priv->mime_part = mime_part;
+
+ g_object_notify (G_OBJECT (attachment), "mime-part");
}
-
-/**
- * e_attachment_new:
- * @file_name: filename to attach
- * @disposition: Content-Disposition of the attachment
- * @ex: exception
- *
- * Return value: the new attachment, or %NULL on error
- **/
-EAttachment *
-e_attachment_new (const char *file_name, const char *disposition, CamelException *ex)
+gint
+e_attachment_get_percent (EAttachment *attachment)
{
- EAttachment *new;
- CamelMimePart *part;
- CamelDataWrapper *wrapper;
- CamelStream *stream;
- struct stat statbuf;
- char *mime_type;
- char *filename;
- CamelURL *url;
+ g_return_val_if_fail (E_IS_ATTACHMENT (attachment), 0);
+
+ return attachment->priv->percent;
+}
+
+GtkTreeRowReference *
+e_attachment_get_reference (EAttachment *attachment)
+{
+ g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL);
+
+ return attachment->priv->reference;
+}
+
+void
+e_attachment_set_reference (EAttachment *attachment,
+ GtkTreeRowReference *reference)
+{
+ g_return_if_fail (E_IS_ATTACHMENT (attachment));
+
+ if (reference != NULL)
+ reference = gtk_tree_row_reference_copy (reference);
+
+ gtk_tree_row_reference_free (attachment->priv->reference);
+ attachment->priv->reference = reference;
+
+ g_object_notify (G_OBJECT (attachment), "reference");
+}
+
+gboolean
+e_attachment_get_saving (EAttachment *attachment)
+{
+ g_return_val_if_fail (E_IS_ATTACHMENT (attachment), FALSE);
+
+ return attachment->priv->saving;
+}
+
+gboolean
+e_attachment_get_shown (EAttachment *attachment)
+{
+ g_return_val_if_fail (E_IS_ATTACHMENT (attachment), FALSE);
+
+ return attachment->priv->shown;
+}
+
+void
+e_attachment_set_shown (EAttachment *attachment,
+ gboolean shown)
+{
+ g_return_if_fail (E_IS_ATTACHMENT (attachment));
+
+ attachment->priv->shown = shown;
+
+ g_object_notify (G_OBJECT (attachment), "shown");
+}
+
+camel_cipher_validity_encrypt_t
+e_attachment_get_encrypted (EAttachment *attachment)
+{
+ g_return_val_if_fail (
+ E_IS_ATTACHMENT (attachment),
+ CAMEL_CIPHER_VALIDITY_ENCRYPT_NONE);
- g_return_val_if_fail (file_name != NULL, NULL);
+ return attachment->priv->encrypted;
+}
+
+void
+e_attachment_set_encrypted (EAttachment *attachment,
+ camel_cipher_validity_encrypt_t encrypted)
+{
+ g_return_if_fail (E_IS_ATTACHMENT (attachment));
+
+ attachment->priv->encrypted = encrypted;
+
+ g_object_notify (G_OBJECT (attachment), "encrypted");
+}
- if (g_stat (file_name, &statbuf) < 0) {
- camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
- _("Cannot attach file %s: %s"),
- file_name, g_strerror (errno));
+camel_cipher_validity_sign_t
+e_attachment_get_signed (EAttachment *attachment)
+{
+ g_return_val_if_fail (
+ E_IS_ATTACHMENT (attachment),
+ CAMEL_CIPHER_VALIDITY_SIGN_NONE);
+
+ return attachment->priv->signed_;
+}
+
+void
+e_attachment_set_signed (EAttachment *attachment,
+ camel_cipher_validity_sign_t signed_)
+{
+ g_return_if_fail (E_IS_ATTACHMENT (attachment));
+
+ attachment->priv->signed_ = signed_;
+
+ g_object_notify (G_OBJECT (attachment), "signed");
+}
+
+const gchar *
+e_attachment_get_description (EAttachment *attachment)
+{
+ GFileInfo *file_info;
+ const gchar *attribute;
+
+ g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL);
+
+ attribute = G_FILE_ATTRIBUTE_STANDARD_DESCRIPTION;
+ file_info = e_attachment_get_file_info (attachment);
+
+ if (file_info == NULL)
return NULL;
- }
- /* return if it's not a regular file */
- if (!S_ISREG (statbuf.st_mode)) {
- camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
- _("Cannot attach file %s: not a regular file"),
- file_name);
+ return g_file_info_get_attribute_string (file_info, attribute);
+}
+
+const gchar *
+e_attachment_get_thumbnail_path (EAttachment *attachment)
+{
+ GFileInfo *file_info;
+ const gchar *attribute;
+
+ g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL);
+
+ attribute = G_FILE_ATTRIBUTE_THUMBNAIL_PATH;
+ file_info = e_attachment_get_file_info (attachment);
+
+ if (file_info == NULL)
return NULL;
- }
- if (!(stream = camel_stream_fs_new_with_name (file_name, O_RDONLY, 0))) {
- camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
- _("Cannot attach file %s: %s"),
- file_name, g_strerror (errno));
+ return g_file_info_get_attribute_byte_string (file_info, attribute);
+}
+
+gboolean
+e_attachment_is_rfc822 (EAttachment *attachment)
+{
+ GFileInfo *file_info;
+ const gchar *content_type;
+ gchar *mime_type;
+ gboolean is_rfc822;
+
+ g_return_val_if_fail (E_IS_ATTACHMENT (attachment), FALSE);
+
+ file_info = e_attachment_get_file_info (attachment);
+ if (file_info == NULL)
+ return FALSE;
+
+ content_type = g_file_info_get_content_type (file_info);
+ if (content_type == NULL)
+ return FALSE;
+
+ mime_type = g_content_type_get_mime_type (content_type);
+ is_rfc822 = (g_ascii_strcasecmp (mime_type, "message/rfc822") == 0);
+ g_free (mime_type);
+
+ return is_rfc822;
+}
+
+GList *
+e_attachment_list_apps (EAttachment *attachment)
+{
+ GList *app_info_list;
+ GFileInfo *file_info;
+ const gchar *content_type;
+ const gchar *display_name;
+ gchar *allocated;
+
+ g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL);
+
+ file_info = e_attachment_get_file_info (attachment);
+ if (file_info == NULL)
return NULL;
- }
- if ((mime_type = attachment_guess_mime_type (file_name))) {
- if (!g_ascii_strcasecmp (mime_type, "message/rfc822")) {
- wrapper = (CamelDataWrapper *) camel_mime_message_new ();
- } else {
- wrapper = camel_data_wrapper_new ();
- }
+ content_type = g_file_info_get_content_type (file_info);
+ display_name = g_file_info_get_display_name (file_info);
+ g_return_val_if_fail (content_type != NULL, NULL);
+
+ app_info_list = g_app_info_get_all_for_type (content_type);
+
+ if (app_info_list != NULL || display_name == NULL)
+ goto exit;
+
+ if (!g_content_type_is_unknown (content_type))
+ goto exit;
- camel_data_wrapper_construct_from_stream (wrapper, stream);
- camel_data_wrapper_set_mime_type (wrapper, mime_type);
- g_free (mime_type);
- } else {
+ allocated = g_content_type_guess (display_name, NULL, 0, NULL);
+ app_info_list = g_app_info_get_all_for_type (allocated);
+ g_free (allocated);
+
+exit:
+ return app_info_list;
+}
+
+/************************* e_attachment_load_async() *************************/
+
+typedef struct _LoadContext LoadContext;
+
+struct _LoadContext {
+ EAttachment *attachment;
+ GSimpleAsyncResult *simple;
+
+ GInputStream *input_stream;
+ GOutputStream *output_stream;
+ GFileInfo *file_info;
+ goffset total_num_bytes;
+ gssize bytes_read;
+ gchar buffer[4096];
+};
+
+/* Forward Declaration */
+static void
+attachment_load_stream_read_cb (GInputStream *input_stream,
+ GAsyncResult *result,
+ LoadContext *load_context);
+
+static LoadContext *
+attachment_load_context_new (EAttachment *attachment,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ LoadContext *load_context;
+ GSimpleAsyncResult *simple;
+
+ simple = g_simple_async_result_new (
+ G_OBJECT (attachment), callback,
+ user_data, e_attachment_load_async);
+
+ load_context = g_slice_new0 (LoadContext);
+ load_context->attachment = g_object_ref (attachment);
+ load_context->simple = simple;
+
+ attachment_set_loading (load_context->attachment, TRUE);
+
+ return load_context;
+}
+
+static void
+attachment_load_context_free (LoadContext *load_context)
+{
+ /* Do not free the GSimpleAsyncResult. */
+ g_object_unref (load_context->attachment);
+
+ if (load_context->input_stream != NULL)
+ g_object_unref (load_context->input_stream);
+
+ if (load_context->output_stream != NULL)
+ g_object_unref (load_context->output_stream);
+
+ if (load_context->file_info != NULL)
+ g_object_unref (load_context->file_info);
+
+ g_slice_free (LoadContext, load_context);
+}
+
+static gboolean
+attachment_load_check_for_error (LoadContext *load_context,
+ GError *error)
+{
+ GSimpleAsyncResult *simple;
+
+ if (error == NULL)
+ return FALSE;
+
+ /* Steal the result. */
+ simple = load_context->simple;
+ load_context->simple = NULL;
+
+ g_simple_async_result_set_from_error (simple, error);
+ g_simple_async_result_complete (simple);
+ g_error_free (error);
+
+ attachment_load_context_free (load_context);
+
+ return TRUE;
+}
+
+static void
+attachment_load_finish (LoadContext *load_context)
+{
+ GFileInfo *file_info;
+ EAttachment *attachment;
+ GMemoryOutputStream *output_stream;
+ GSimpleAsyncResult *simple;
+ CamelDataWrapper *wrapper;
+ CamelMimePart *mime_part;
+ CamelStream *stream;
+ const gchar *attribute;
+ const gchar *content_type;
+ const gchar *display_name;
+ const gchar *description;
+ const gchar *disposition;
+ gchar *mime_type;
+ gpointer data;
+ gsize size;
+
+ /* Steal the result. */
+ simple = load_context->simple;
+ load_context->simple = NULL;
+
+ file_info = load_context->file_info;
+ attachment = load_context->attachment;
+ output_stream = G_MEMORY_OUTPUT_STREAM (load_context->output_stream);
+
+ if (e_attachment_is_rfc822 (attachment))
+ wrapper = (CamelDataWrapper *) camel_mime_message_new ();
+ else
wrapper = camel_data_wrapper_new ();
- camel_data_wrapper_construct_from_stream (wrapper, stream);
- camel_data_wrapper_set_mime_type (wrapper, "application/octet-stream");
- }
+ content_type = g_file_info_get_content_type (file_info);
+ mime_type = g_content_type_get_mime_type (content_type);
+
+ data = g_memory_output_stream_get_data (output_stream);
+ size = g_memory_output_stream_get_data_size (output_stream);
+
+ stream = camel_stream_mem_new_with_buffer (data, size);
+ camel_data_wrapper_construct_from_stream (wrapper, stream);
+ camel_data_wrapper_set_mime_type (wrapper, mime_type);
+ camel_stream_close (stream);
camel_object_unref (stream);
- part = camel_mime_part_new ();
- camel_medium_set_content_object (CAMEL_MEDIUM (part), wrapper);
+ mime_part = camel_mime_part_new ();
+ camel_medium_set_content_object (CAMEL_MEDIUM (mime_part), wrapper);
+
camel_object_unref (wrapper);
+ g_free (mime_type);
- camel_mime_part_set_disposition (part, disposition);
- filename = g_path_get_basename (file_name);
- camel_mime_part_set_filename (part, filename);
-
-#if 0
- /* Note: Outlook 2002 is broken with respect to Content-Ids on
- non-multipart/related parts, so as an interoperability
- workaround, don't set a Content-Id on these parts. Fixes
- bug #10032 */
- /* set the Content-Id */
- content_id = camel_header_msgid_generate ();
- camel_mime_part_set_content_id (part, content_id);
- g_free (content_id);
-#endif
+ display_name = g_file_info_get_display_name (file_info);
+ if (display_name != NULL)
+ camel_mime_part_set_filename (mime_part, display_name);
- new = g_object_new (E_TYPE_ATTACHMENT, NULL);
- new->editor_gui = NULL;
- new->body = part;
- new->size = statbuf.st_size;
- new->guessed_type = TRUE;
- new->cancellable = NULL;
- new->is_available_local = TRUE;
- new->file_name = filename;
+ attribute = G_FILE_ATTRIBUTE_STANDARD_DESCRIPTION;
+ description = g_file_info_get_attribute_string (file_info, attribute);
+ if (description != NULL)
+ camel_mime_part_set_description (mime_part, description);
- url = camel_url_new ("file://", NULL);
- camel_url_set_path (url, file_name);
- new->store_uri = camel_url_to_string (url, 0);
- camel_url_free (url);
+ disposition = e_attachment_get_disposition (attachment);
+ if (disposition != NULL)
+ camel_mime_part_set_disposition (mime_part, disposition);
- return new;
-}
+ g_simple_async_result_set_op_res_gpointer (
+ simple, mime_part, (GDestroyNotify) camel_object_unref);
+
+ g_simple_async_result_complete (simple);
+ attachment_load_context_free (load_context);
+}
-typedef struct {
+static void
+attachment_load_write_cb (GOutputStream *output_stream,
+ GAsyncResult *result,
+ LoadContext *load_context)
+{
EAttachment *attachment;
- char *file_name;
- char *uri;
- GtkWindow *parent; /* for error dialog */
-
- guint64 file_size; /* zero indicates unknown size */
- GInputStream *istream; /* read from here ... */
- GOutputStream *ostream; /* ...and write into this. */
- gboolean was_error;
GCancellable *cancellable;
+ GInputStream *input_stream;
+ gssize bytes_written;
+ GError *error = NULL;
+
+ bytes_written = g_output_stream_write_finish (
+ output_stream, result, &error);
- void *buffer; /* read into this, not more than buffer_size bytes */
- gsize buffer_size;
-} DownloadInfo;
+ if (attachment_load_check_for_error (load_context, error))
+ return;
+
+ attachment = load_context->attachment;
+ cancellable = attachment->priv->cancellable;
+ input_stream = load_context->input_stream;
+
+ attachment_progress_cb (
+ g_seekable_tell (G_SEEKABLE (output_stream)),
+ load_context->total_num_bytes, attachment);
+
+ if (bytes_written < load_context->bytes_read) {
+ g_memmove (
+ load_context->buffer,
+ load_context->buffer + bytes_written,
+ load_context->bytes_read - bytes_written);
+ load_context->bytes_read -= bytes_written;
+
+ g_output_stream_write_async (
+ output_stream,
+ load_context->buffer,
+ load_context->bytes_read,
+ G_PRIORITY_DEFAULT, cancellable,
+ (GAsyncReadyCallback) attachment_load_write_cb,
+ load_context);
+ } else
+ g_input_stream_read_async (
+ input_stream,
+ load_context->buffer,
+ sizeof (load_context->buffer),
+ G_PRIORITY_DEFAULT, cancellable,
+ (GAsyncReadyCallback) attachment_load_stream_read_cb,
+ load_context);
+}
static void
-download_info_free (DownloadInfo *download_info)
+attachment_load_stream_read_cb (GInputStream *input_stream,
+ GAsyncResult *result,
+ LoadContext *load_context)
{
- /* if there was an error, then free attachment too */
- if (download_info->was_error)
- g_object_unref (download_info->attachment);
+ EAttachment *attachment;
+ GCancellable *cancellable;
+ GOutputStream *output_stream;
+ gssize bytes_read;
+ GError *error = NULL;
- if (download_info->ostream)
- g_object_unref (download_info->ostream);
+ bytes_read = g_input_stream_read_finish (
+ input_stream, result, &error);
- if (download_info->istream)
- g_object_unref (download_info->istream);
+ if (attachment_load_check_for_error (load_context, error))
+ return;
- if (download_info->cancellable)
- g_object_unref (download_info->cancellable);
+ if (bytes_read == 0) {
+ attachment_load_finish (load_context);
+ return;
+ }
- g_free (download_info->file_name);
- g_free (download_info->uri);
- g_free (download_info->buffer);
- g_free (download_info);
+ attachment = load_context->attachment;
+ cancellable = attachment->priv->cancellable;
+ output_stream = load_context->output_stream;
+ load_context->bytes_read = bytes_read;
+
+ g_output_stream_write_async (
+ output_stream,
+ load_context->buffer,
+ load_context->bytes_read,
+ G_PRIORITY_DEFAULT, cancellable,
+ (GAsyncReadyCallback) attachment_load_write_cb,
+ load_context);
}
static void
-data_ready_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
+attachment_load_file_read_cb (GFile *file,
+ GAsyncResult *result,
+ LoadContext *load_context)
{
- DownloadInfo *download_info = (DownloadInfo *)user_data;
+ EAttachment *attachment;
+ GCancellable *cancellable;
+ GFileInputStream *input_stream;
+ GOutputStream *output_stream;
GError *error = NULL;
- gssize read;
- g_return_if_fail (download_info != NULL);
+ /* Input stream might be NULL, so don't use cast macro. */
+ input_stream = g_file_read_finish (file, result, &error);
+ load_context->input_stream = (GInputStream *) input_stream;
- if (g_cancellable_is_cancelled (download_info->cancellable)) {
- /* finish the operation and close both streams */
- g_input_stream_read_finish (G_INPUT_STREAM (source_object), res, NULL);
+ if (attachment_load_check_for_error (load_context, error))
+ return;
- g_output_stream_close (download_info->ostream, NULL, NULL);
- g_input_stream_close (download_info->istream, NULL, NULL);
+ /* Load the contents into a GMemoryOutputStream. */
+ output_stream = g_memory_output_stream_new (
+ NULL, 0, g_realloc, g_free);
+
+ attachment = load_context->attachment;
+ cancellable = attachment->priv->cancellable;
+ load_context->output_stream = output_stream;
+
+ g_input_stream_read_async (
+ load_context->input_stream,
+ load_context->buffer,
+ sizeof (load_context->buffer),
+ G_PRIORITY_DEFAULT, cancellable,
+ (GAsyncReadyCallback) attachment_load_stream_read_cb,
+ load_context);
+}
- /* The only way how to get this canceled is in EAttachment's finalize method,
- and because the download_info_free free's the attachment on error,
- then do not consider cancellation as an error. */
- download_info_free (download_info);
+static void
+attachment_load_query_info_cb (GFile *file,
+ GAsyncResult *result,
+ LoadContext *load_context)
+{
+ EAttachment *attachment;
+ GCancellable *cancellable;
+ GFileInfo *file_info;
+ GError *error = NULL;
+
+ attachment = load_context->attachment;
+ cancellable = attachment->priv->cancellable;
+
+ file_info = g_file_query_info_finish (file, result, &error);
+ attachment_set_file_info (attachment, file_info);
+ load_context->file_info = file_info;
+
+ if (attachment_load_check_for_error (load_context, error))
return;
+
+ load_context->total_num_bytes = g_file_info_get_size (file_info);
+
+ g_file_read_async (
+ file, G_PRIORITY_DEFAULT,
+ cancellable, (GAsyncReadyCallback)
+ attachment_load_file_read_cb, load_context);
+}
+
+static void
+attachment_load_from_mime_part (LoadContext *load_context)
+{
+ GFileInfo *file_info;
+ EAttachment *attachment;
+ GSimpleAsyncResult *simple;
+ CamelContentType *content_type;
+ CamelMimePart *mime_part;
+ const gchar *attribute;
+ const gchar *string;
+ gchar *allocated;
+ goffset size;
+
+ attachment = load_context->attachment;
+ mime_part = e_attachment_get_mime_part (attachment);
+
+ file_info = g_file_info_new ();
+ load_context->file_info = file_info;
+
+ content_type = camel_mime_part_get_content_type (mime_part);
+ allocated = camel_content_type_simple (content_type);
+ if (allocated != NULL) {
+ GIcon *icon;
+ gchar *cp;
+
+ /* GIO expects lowercase MIME types. */
+ for (cp = allocated; *cp != '\0'; cp++)
+ *cp = g_ascii_tolower (*cp);
+
+ /* Swap the MIME type for a content type. */
+ cp = g_content_type_from_mime_type (allocated);
+ g_free (allocated);
+ allocated = cp;
+
+ /* Use the MIME part's filename if we have to. */
+ if (g_content_type_is_unknown (allocated)) {
+ string = camel_mime_part_get_filename (mime_part);
+ if (string != NULL) {
+ g_free (allocated);
+ allocated = g_content_type_guess (
+ string, NULL, 0, NULL);
+ }
+ }
+
+ g_file_info_set_content_type (file_info, allocated);
+
+ icon = g_content_type_get_icon (allocated);
+ if (icon != NULL) {
+ g_file_info_set_icon (file_info, icon);
+ g_object_unref (icon);
+ }
}
+ g_free (allocated);
- read = g_input_stream_read_finish (G_INPUT_STREAM (source_object), res, &error);
+ string = camel_mime_part_get_filename (mime_part);
+ if (string == NULL)
+ /* Translators: Default attachment filename. */
+ string = _("attachment.dat");
+ g_file_info_set_display_name (file_info, string);
- if (!error)
- g_output_stream_write_all (download_info->ostream, download_info->buffer, read, NULL, download_info->cancellable, &error);
+ attribute = G_FILE_ATTRIBUTE_STANDARD_DESCRIPTION;
+ string = camel_mime_part_get_description (mime_part);
+ if (string != NULL)
+ g_file_info_set_attribute_string (
+ file_info, attribute, string);
- if (error) {
- download_info->was_error = error->domain != G_IO_ERROR || error->code != G_IO_ERROR_CANCELLED;
- if (download_info->was_error)
- e_error_run (download_info->parent, "mail-composer:no-attach", download_info->uri, error->message, NULL);
+ size = (goffset) camel_mime_part_get_content_size (mime_part);
+ g_file_info_set_size (file_info, size);
- g_error_free (error);
+ string = camel_mime_part_get_disposition (mime_part);
+ e_attachment_set_disposition (attachment, string);
+
+ attachment_set_file_info (attachment, file_info);
- download_info->attachment->cancellable = NULL;
- download_info_free (download_info);
+ /* Steal the result. */
+ simple = load_context->simple;
+ load_context->simple = NULL;
+
+ camel_object_ref (mime_part);
+ g_simple_async_result_set_op_res_gpointer (
+ simple, mime_part,
+ (GDestroyNotify) camel_object_unref);
+ g_simple_async_result_complete_in_idle (simple);
+
+ attachment_load_context_free (load_context);
+}
+
+void
+e_attachment_load_async (EAttachment *attachment,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ LoadContext *load_context;
+ GCancellable *cancellable;
+ CamelMimePart *mime_part;
+ GFile *file;
+
+ g_return_if_fail (E_IS_ATTACHMENT (attachment));
+ g_return_if_fail (callback != NULL);
+
+ if (e_attachment_get_loading (attachment)) {
+ g_simple_async_report_error_in_idle (
+ G_OBJECT (attachment), callback, user_data,
+ G_IO_ERROR, G_IO_ERROR_BUSY,
+ _("A load operation is already in progress"));
+ return;
+ }
+
+ if (e_attachment_get_saving (attachment)) {
+ g_simple_async_report_error_in_idle (
+ G_OBJECT (attachment), callback, user_data,
+ G_IO_ERROR, G_IO_ERROR_BUSY,
+ _("A save operation is already in progress"));
return;
}
- if (read == 0) {
- CamelException ex;
+ file = e_attachment_get_file (attachment);
+ mime_part = e_attachment_get_mime_part (attachment);
+ g_return_if_fail (file != NULL || mime_part != NULL);
- /* done with reading */
- g_output_stream_close (download_info->ostream, NULL, NULL);
- g_input_stream_close (download_info->istream, NULL, NULL);
+ load_context = attachment_load_context_new (
+ attachment, callback, user_data);
- download_info->attachment->cancellable = NULL;
+ cancellable = attachment->priv->cancellable;
+ g_cancellable_reset (cancellable);
- camel_exception_init (&ex);
- e_attachment_build_remote_file (download_info->file_name, download_info->attachment, "attachment", &ex);
+ if (file != NULL)
+ g_file_query_info_async (
+ file, ATTACHMENT_QUERY,
+ G_FILE_QUERY_INFO_NONE,G_PRIORITY_DEFAULT,
+ cancellable, (GAsyncReadyCallback)
+ attachment_load_query_info_cb, load_context);
- if (camel_exception_is_set (&ex)) {
- download_info->was_error = TRUE;
- e_error_run (download_info->parent, "mail-composer:no-attach", download_info->uri, camel_exception_get_description (&ex), NULL);
- camel_exception_clear (&ex);
- }
+ else if (mime_part != NULL)
+ attachment_load_from_mime_part (load_context);
+
+}
+
+gboolean
+e_attachment_load_finish (EAttachment *attachment,
+ GAsyncResult *result,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+ CamelMimePart *mime_part;
+
+ g_return_val_if_fail (E_IS_ATTACHMENT (attachment), FALSE);
+ g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), FALSE);
+
+ simple = G_SIMPLE_ASYNC_RESULT (result);
+ mime_part = g_simple_async_result_get_op_res_gpointer (simple);
+ if (mime_part != NULL)
+ e_attachment_set_mime_part (attachment, mime_part);
+ g_simple_async_result_propagate_error (simple, error);
+ g_object_unref (simple);
+
+ attachment_set_loading (attachment, FALSE);
+
+ return (mime_part != NULL);
+}
- download_info->attachment->percentage = -1;
- download_info->attachment->is_available_local = TRUE;
- g_signal_emit (download_info->attachment, signals[UPDATE], 0);
+void
+e_attachment_load_handle_error (EAttachment *attachment,
+ GAsyncResult *result,
+ GtkWindow *parent)
+{
+ GtkWidget *dialog;
+ GFileInfo *file_info;
+ GtkTreeRowReference *reference;
+ const gchar *display_name;
+ const gchar *primary_text;
+ GError *error = NULL;
- download_info_free (download_info);
+ g_return_if_fail (E_IS_ATTACHMENT (attachment));
+ g_return_if_fail (G_IS_ASYNC_RESULT (result));
+ g_return_if_fail (GTK_IS_WINDOW (parent));
+
+ if (e_attachment_load_finish (attachment, result, &error))
return;
- } else if (download_info->file_size) {
- download_info->attachment->percentage = read * 100 / download_info->file_size;
- download_info->file_size -= MIN (download_info->file_size, read);
- g_signal_emit (download_info->attachment, signals[UPDATE], 0);
- } else {
- download_info->attachment->percentage = 0;
- g_signal_emit (download_info->attachment, signals[UPDATE], 0);
+
+ /* XXX Calling EAttachmentStore functions from here violates
+ * the abstraction, but for now it's not hurting anything. */
+ reference = e_attachment_get_reference (attachment);
+ if (gtk_tree_row_reference_valid (reference)) {
+ GtkTreeModel *model;
+
+ model = gtk_tree_row_reference_get_model (reference);
+
+ e_attachment_store_remove_attachment (
+ E_ATTACHMENT_STORE (model), attachment);
}
- /* read next chunk */
- g_input_stream_read_async (download_info->istream, download_info->buffer, download_info->buffer_size, G_PRIORITY_DEFAULT, download_info->cancellable, data_ready_cb, download_info);
+ /* Ignore cancellations. */
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ return;
+
+ file_info = e_attachment_get_file_info (attachment);
+
+ if (file_info != NULL)
+ display_name = g_file_info_get_display_name (file_info);
+ else
+ display_name = NULL;
+
+ if (display_name != NULL)
+ primary_text = g_strdup_printf (
+ _("Could not load '%s'"), display_name);
+ else
+ primary_text = g_strdup_printf (
+ _("Could not load the attachment"));
+
+ dialog = gtk_message_dialog_new_with_markup (
+ parent, GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
+ "<big><b>%s</b></big>", primary_text);
+
+ gtk_message_dialog_format_secondary_text (
+ GTK_MESSAGE_DIALOG (dialog), "%s", error->message);
+
+ gtk_dialog_run (GTK_DIALOG (dialog));
+
+ gtk_widget_destroy (dialog);
+ g_error_free (error);
+}
+
+/************************* e_attachment_open_async() *************************/
+
+typedef struct _OpenContext OpenContext;
+
+struct _OpenContext {
+ EAttachment *attachment;
+ GSimpleAsyncResult *simple;
+
+ GAppInfo *app_info;
+};
+
+static OpenContext *
+attachment_open_context_new (EAttachment *attachment,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ OpenContext *open_context;
+ GSimpleAsyncResult *simple;
+
+ simple = g_simple_async_result_new (
+ G_OBJECT (attachment), callback,
+ user_data, e_attachment_open_async);
+
+ open_context = g_slice_new0 (OpenContext);
+ open_context->attachment = g_object_ref (attachment);
+ open_context->simple = simple;
+
+ return open_context;
+}
+
+static void
+attachment_open_context_free (OpenContext *open_context)
+{
+ /* Do not free the GSimpleAsyncResult. */
+ g_object_unref (open_context->attachment);
+
+ if (open_context->app_info != NULL)
+ g_object_unref (open_context->app_info);
+
+ g_slice_free (OpenContext, open_context);
}
static gboolean
-download_to_local_path (DownloadInfo *download_info, CamelException *ex)
+attachment_open_check_for_error (OpenContext *open_context,
+ GError *error)
{
- GError *error = NULL;
- GFile *src = g_file_new_for_uri (download_info->uri);
- GFile *des = g_file_new_for_path (download_info->file_name);
- gboolean res = FALSE;
+ GSimpleAsyncResult *simple;
- g_return_val_if_fail (src != NULL && des != NULL, FALSE);
+ if (error == NULL)
+ return FALSE;
- download_info->ostream = G_OUTPUT_STREAM (g_file_replace (des, NULL, FALSE, G_FILE_CREATE_NONE, NULL, &error));
+ /* Steal the result. */
+ simple = open_context->simple;
+ open_context->simple = NULL;
- if (download_info->ostream && !error) {
- GFileInfo *fi;
+ g_simple_async_result_set_from_error (simple, error);
+ g_simple_async_result_complete (simple);
+ g_error_free (error);
- fi = g_file_query_info (src, G_FILE_ATTRIBUTE_STANDARD_SIZE, G_FILE_QUERY_INFO_NONE, NULL, NULL);
+ attachment_open_context_free (open_context);
- if (fi) {
- download_info->file_size = g_file_info_get_attribute_uint64 (fi, G_FILE_ATTRIBUTE_STANDARD_SIZE);
- g_object_unref (fi);
- } else {
- download_info->file_size = 0;
- }
+ return TRUE;
+}
- download_info->istream = G_INPUT_STREAM (g_file_read (src, NULL, &error));
+static void
+attachment_open_file (GFile *file,
+ OpenContext *open_context)
+{
+ GdkAppLaunchContext *context;
+ GSimpleAsyncResult *simple;
+ GList *file_list;
+ gboolean success;
+ GError *error = NULL;
- if (download_info->istream && !error) {
- download_info->cancellable = g_cancellable_new ();
- download_info->attachment->cancellable = download_info->cancellable;
- download_info->buffer_size = 10240; /* max 10KB chunk */
- download_info->buffer = g_malloc (sizeof (char) * download_info->buffer_size);
+ /* Steal the result. */
+ simple = open_context->simple;
+ open_context->simple = NULL;
- g_input_stream_read_async (download_info->istream, download_info->buffer, download_info->buffer_size, G_PRIORITY_DEFAULT, download_info->cancellable, data_ready_cb, download_info);
+ /* Find a default app based on content type. */
+ if (open_context->app_info == NULL) {
+ EAttachment *attachment;
+ GFileInfo *file_info;
+ const gchar *content_type;
- res = TRUE;
- }
+ attachment = open_context->attachment;
+ file_info = e_attachment_get_file_info (attachment);
+ if (file_info == NULL)
+ goto exit;
+
+ content_type = g_file_info_get_content_type (file_info);
+ if (content_type == NULL)
+ goto exit;
+
+ open_context->app_info = g_app_info_get_default_for_type (
+ content_type, FALSE);
}
- if (error) {
- /* propagate error */
- if (ex)
- camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, error->message);
+ if (open_context->app_info == NULL)
+ goto exit;
+
+ context = gdk_app_launch_context_new ();
+ file_list = g_list_prepend (NULL, file);
+
+ success = g_app_info_launch (
+ open_context->app_info, file_list,
+ G_APP_LAUNCH_CONTEXT (context), &error);
+ g_simple_async_result_set_op_res_gboolean (simple, success);
+
+ g_list_free (file_list);
+ g_object_unref (context);
+
+exit:
+ if (error != NULL) {
+ g_simple_async_result_set_from_error (simple, error);
g_error_free (error);
- download_info->was_error = TRUE;
- download_info_free (download_info);
}
- g_object_unref (src);
- g_object_unref (des);
+ g_simple_async_result_complete (simple);
+ attachment_open_context_free (open_context);
+}
- return res;
+static void
+attachment_open_save_finished_cb (EAttachment *attachment,
+ GAsyncResult *result,
+ OpenContext *open_context)
+{
+ GFile *file;
+ GError *error = NULL;
+
+ file = e_attachment_save_finish (attachment, result, &error);
+
+ if (attachment_open_check_for_error (open_context, error))
+ return;
+
+ attachment_open_file (file, open_context);
+ g_object_unref (file);
}
-EAttachment *
-e_attachment_new_remote_file (GtkWindow *error_dlg_parent, const char *uri, const char *disposition, const char *path, CamelException *ex)
+static void
+attachment_open_save_temporary (OpenContext *open_context)
{
- EAttachment *new;
- DownloadInfo *download_info;
- CamelURL *url;
- char *base;
+ GFile *file;
+ gchar *template;
+ gchar *path;
+ GError *error = NULL;
- g_return_val_if_fail (uri != NULL, NULL);
+ errno = 0;
- url = camel_url_new (uri, NULL);
- base = g_path_get_basename (url->path);
- camel_url_free (url);
-
- new = g_object_new (E_TYPE_ATTACHMENT, NULL);
- new->editor_gui = NULL;
- new->body = NULL;
- new->size = 0;
- new->guessed_type = FALSE;
- new->cancellable = NULL;
- new->is_available_local = FALSE;
- new->percentage = 0;
- new->file_name = g_build_filename (path, base, NULL);
-
- g_free (base);
-
- download_info = g_new0 (DownloadInfo, 1);
- download_info->attachment = new;
- download_info->file_name = g_strdup (new->file_name);
- download_info->uri = g_strdup (uri);
- download_info->parent = error_dlg_parent;
- download_info->was_error = FALSE;
-
- /* it frees all on the error, so do not free it twice */
- if (!download_to_local_path (download_info, ex))
- return NULL;
+ /* XXX This could trigger a blocking temp directory cleanup. */
+ template = g_strdup_printf (PACKAGE "-%s-XXXXXX", g_get_user_name ());
+ path = e_mktemp (template);
+ g_free (template);
- return new;
+ /* XXX Let's hope errno got set properly. */
+ if (path == NULL)
+ g_set_error (
+ &error, G_FILE_ERROR,
+ g_file_error_from_errno (errno),
+ "%s", g_strerror (errno));
+
+ /* We already know if there's an error, but this does the cleanup. */
+ if (attachment_open_check_for_error (open_context, error))
+ return;
+
+ file = g_file_new_for_path (path);
+
+ g_free (path);
+
+ e_attachment_save_async (
+ open_context->attachment, file, (GAsyncReadyCallback)
+ attachment_open_save_finished_cb, open_context);
+
+ g_object_unref (file);
+}
+
+void
+e_attachment_open_async (EAttachment *attachment,
+ GAppInfo *app_info,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ OpenContext *open_context;
+ CamelMimePart *mime_part;
+ GFile *file;
+
+ g_return_if_fail (E_IS_ATTACHMENT (attachment));
+ g_return_if_fail (callback != NULL);
+
+ file = e_attachment_get_file (attachment);
+ mime_part = e_attachment_get_mime_part (attachment);
+ g_return_if_fail (file != NULL || mime_part != NULL);
+
+ open_context = attachment_open_context_new (
+ attachment, callback, user_data);
+
+ if (G_IS_APP_INFO (app_info))
+ open_context->app_info = g_object_ref (app_info);
+
+ /* If the attachment already references a GFile, we can launch
+ * the application directly. Otherwise we have to save the MIME
+ * part to a temporary file and launch the application from that. */
+ if (file != NULL) {
+ attachment_open_file (file, open_context);
+
+ } else if (mime_part != NULL)
+ attachment_open_save_temporary (open_context);
}
+gboolean
+e_attachment_open_finish (EAttachment *attachment,
+ GAsyncResult *result,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+ gboolean success;
+
+ g_return_val_if_fail (E_IS_ATTACHMENT (attachment), FALSE);
+ g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), FALSE);
+
+ simple = G_SIMPLE_ASYNC_RESULT (result);
+ success = g_simple_async_result_get_op_res_gboolean (simple);
+ g_simple_async_result_propagate_error (simple, error);
+ g_object_unref (simple);
+
+ return success;
+}
void
-e_attachment_build_remote_file (const char *file_name, EAttachment *attachment, const char *disposition, CamelException *ex)
+e_attachment_open_handle_error (EAttachment *attachment,
+ GAsyncResult *result,
+ GtkWindow *parent)
{
- CamelMimePart *part;
- CamelDataWrapper *wrapper;
- CamelStream *stream;
- struct stat statbuf;
- char *mime_type;
- char *filename;
- CamelURL *url;
-
- g_return_if_fail (file_name != NULL);
-
- if (g_stat (file_name, &statbuf) == -1) {
- camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
- _("Cannot attach file %s: %s"),
- file_name, g_strerror (errno));
- g_message ("Cannot attach file %s: %s\n", file_name, g_strerror (errno));
- return;
- }
+ GtkWidget *dialog;
+ GFileInfo *file_info;
+ const gchar *display_name;
+ const gchar *primary_text;
+ GError *error = NULL;
- /* return if it's not a regular file */
- if (!S_ISREG (statbuf.st_mode)) {
- camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
- _("Cannot attach file %s: not a regular file"),
- file_name);
- g_message ("Cannot attach file %s: not a regular file", file_name);
+ g_return_if_fail (E_IS_ATTACHMENT (attachment));
+ g_return_if_fail (G_IS_ASYNC_RESULT (result));
+ g_return_if_fail (GTK_IS_WINDOW (parent));
+
+ if (e_attachment_open_finish (attachment, result, &error))
return;
- }
- if (!(stream = camel_stream_fs_new_with_name (file_name, O_RDONLY, 0))) {
- camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
- _("Cannot attach file %s: %s"),
- file_name, g_strerror (errno));
+ /* Ignore cancellations. */
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
return;
- }
- if ((mime_type = attachment_guess_mime_type (file_name))) {
- if (!g_ascii_strcasecmp (mime_type, "message/rfc822")) {
- wrapper = (CamelDataWrapper *) camel_mime_message_new ();
- } else {
- wrapper = camel_data_wrapper_new ();
- }
+ file_info = e_attachment_get_file_info (attachment);
- camel_data_wrapper_construct_from_stream (wrapper, stream);
- camel_data_wrapper_set_mime_type (wrapper, mime_type);
- g_free (mime_type);
- } else {
- wrapper = camel_data_wrapper_new ();
- camel_data_wrapper_construct_from_stream (wrapper, stream);
- camel_data_wrapper_set_mime_type (wrapper, "application/octet-stream");
- }
+ if (file_info != NULL)
+ display_name = g_file_info_get_display_name (file_info);
+ else
+ display_name = NULL;
- camel_object_unref (stream);
+ if (display_name != NULL)
+ primary_text = g_strdup_printf (
+ _("Could not open '%s'"), display_name);
+ else
+ primary_text = g_strdup_printf (
+ _("Could not open the attachment"));
- part = camel_mime_part_new ();
- camel_medium_set_content_object (CAMEL_MEDIUM (part), wrapper);
- camel_object_unref (wrapper);
+ dialog = gtk_message_dialog_new_with_markup (
+ parent, GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
+ "<big><b>%s</b></big>", primary_text);
- if (attachment->disposition)
- camel_mime_part_set_disposition (part, "inline");
- else
- camel_mime_part_set_disposition (part, "attachment");
+ gtk_message_dialog_format_secondary_text (
+ GTK_MESSAGE_DIALOG (dialog), "%s", error->message);
- if (!attachment->file_name)
- filename = g_path_get_basename (file_name);
- else
- filename = g_path_get_basename (attachment->file_name);
+ gtk_dialog_run (GTK_DIALOG (dialog));
- camel_mime_part_set_filename (part, filename);
+ gtk_widget_destroy (dialog);
+ g_error_free (error);
+}
- if (attachment->description) {
- camel_mime_part_set_description (part, attachment->description);
- g_free (attachment->description);
- attachment->description = NULL;
- }
+/************************* e_attachment_save_async() *************************/
- attachment->editor_gui = NULL;
- attachment->body = part;
- attachment->size = statbuf.st_size;
- attachment->guessed_type = TRUE;
- g_free (attachment->file_name);
- attachment->file_name = filename;
+typedef struct _SaveContext SaveContext;
- url = camel_url_new ("file://", NULL);
- camel_url_set_path (url, file_name);
- attachment->store_uri = camel_url_to_string (url, 0);
- camel_url_free (url);
+struct _SaveContext {
+ EAttachment *attachment;
+ GSimpleAsyncResult *simple;
+
+ GFile *directory;
+ GFile *destination;
+ GInputStream *input_stream;
+ GOutputStream *output_stream;
+ goffset total_num_bytes;
+ gssize bytes_read;
+ gchar buffer[4096];
+ gint count;
+};
-}
+/* Forward Declaration */
+static void
+attachment_save_read_cb (GInputStream *input_stream,
+ GAsyncResult *result,
+ SaveContext *save_context);
+
+static SaveContext *
+attachment_save_context_new (EAttachment *attachment,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ SaveContext *save_context;
+ GSimpleAsyncResult *simple;
+ simple = g_simple_async_result_new (
+ G_OBJECT (attachment), callback,
+ user_data, e_attachment_save_async);
-/**
- * e_attachment_new_from_mime_part:
- * @part: a CamelMimePart
- *
- * Return value: a new EAttachment based on the mime part
- **/
-EAttachment *
-e_attachment_new_from_mime_part (CamelMimePart *part)
+ save_context = g_slice_new0 (SaveContext);
+ save_context->attachment = g_object_ref (attachment);
+ save_context->simple = simple;
+
+ attachment_set_saving (save_context->attachment, TRUE);
+
+ return save_context;
+}
+
+static void
+attachment_save_context_free (SaveContext *save_context)
{
- EAttachment *new;
+ /* Do not free the GSimpleAsyncResult. */
+ g_object_unref (save_context->attachment);
- g_return_val_if_fail (CAMEL_IS_MIME_PART (part), NULL);
+ if (save_context->directory != NULL)
+ g_object_unref (save_context->directory);
- new = g_object_new (E_TYPE_ATTACHMENT, NULL);
- new->editor_gui = NULL;
- camel_object_ref (part);
- new->body = part;
- new->guessed_type = FALSE;
- new->is_available_local = TRUE;
- new->size = camel_mime_part_get_content_size (part);
- new->file_name = g_strdup (camel_mime_part_get_filename(part));
+ if (save_context->destination != NULL)
+ g_object_unref (save_context->destination);
- return new;
+ if (save_context->input_stream != NULL)
+ g_object_unref (save_context->input_stream);
+
+ if (save_context->output_stream != NULL)
+ g_object_unref (save_context->output_stream);
+
+ g_slice_free (SaveContext, save_context);
}
-
-/* The attachment property dialog. */
+static gboolean
+attachment_save_check_for_error (SaveContext *save_context,
+ GError *error)
+{
+ GSimpleAsyncResult *simple;
-typedef struct {
- GtkWidget *dialog;
- GtkEntry *file_name_entry;
- GtkEntry *description_entry;
- GtkEntry *mime_type_entry;
- GtkToggleButton *disposition_checkbox;
+ if (error == NULL)
+ return FALSE;
+
+ /* Steal the result. */
+ simple = save_context->simple;
+ save_context->simple = NULL;
+
+ g_simple_async_result_set_from_error (simple, error);
+ g_simple_async_result_complete (simple);
+ g_error_free (error);
+
+ attachment_save_context_free (save_context);
+
+ return TRUE;
+}
+
+static GFile *
+attachment_save_new_candidate (SaveContext *save_context)
+{
+ GFile *candidate;
+ GFileInfo *file_info;
EAttachment *attachment;
-} DialogData;
+ const gchar *display_name;
+ gchar *basename;
+
+ attachment = save_context->attachment;
+ file_info = e_attachment_get_file_info (attachment);
+
+ if (file_info != NULL)
+ display_name = g_file_info_get_display_name (file_info);
+ if (display_name == NULL)
+ /* Translators: Default attachment filename. */
+ display_name = _("attachment.dat");
+
+ if (save_context->count == 0)
+ basename = g_strdup (display_name);
+ else {
+ GString *string;
+ const gchar *ext;
+ gsize length;
+
+ string = g_string_sized_new (strlen (display_name));
+ ext = g_utf8_strchr (display_name, -1, '.');
+
+ if (ext != NULL)
+ length = ext - display_name;
+ else
+ length = strlen (display_name);
+
+ g_string_append_len (string, display_name, length);
+ g_string_append_printf (string, " (%d)", save_context->count);
+ g_string_append (string, (ext != NULL) ? ext : "");
+
+ basename = g_string_free (string, FALSE);
+ }
+
+ save_context->count++;
+
+ candidate = g_file_get_child (save_context->directory, basename);
+
+ g_free (basename);
+
+ return candidate;
+}
static void
-destroy_dialog_data (DialogData *data)
+attachment_save_write_cb (GOutputStream *output_stream,
+ GAsyncResult *result,
+ SaveContext *save_context)
{
- g_free (data);
-}
+ EAttachment *attachment;
+ GCancellable *cancellable;
+ GInputStream *input_stream;
+ gssize bytes_written;
+ GError *error = NULL;
-/*
- * fixme: I am converting EVERYTHING to/from UTF-8, although mime types
- * are in ASCII. This is not strictly necessary, but we want to be
- * consistent and possibly check for errors somewhere.
- */
+ bytes_written = g_output_stream_write_finish (
+ output_stream, result, &error);
+
+ if (attachment_save_check_for_error (save_context, error))
+ return;
+
+ attachment = save_context->attachment;
+ cancellable = attachment->priv->cancellable;
+ input_stream = save_context->input_stream;
+
+ if (bytes_written < save_context->bytes_read) {
+ g_memmove (
+ save_context->buffer,
+ save_context->buffer + bytes_written,
+ save_context->bytes_read - bytes_written);
+ save_context->bytes_read -= bytes_written;
+
+ g_output_stream_write_async (
+ output_stream,
+ save_context->buffer,
+ save_context->bytes_read,
+ G_PRIORITY_DEFAULT, cancellable,
+ (GAsyncReadyCallback) attachment_save_write_cb,
+ save_context);
+ } else
+ g_input_stream_read_async (
+ input_stream,
+ save_context->buffer,
+ sizeof (save_context->buffer),
+ G_PRIORITY_DEFAULT, cancellable,
+ (GAsyncReadyCallback) attachment_save_read_cb,
+ save_context);
+}
static void
-set_entry (GladeXML *xml, const char *widget_name, const char *value)
+attachment_save_read_cb (GInputStream *input_stream,
+ GAsyncResult *result,
+ SaveContext *save_context)
{
- GtkEntry *entry;
+ EAttachment *attachment;
+ GCancellable *cancellable;
+ GOutputStream *output_stream;
+ gssize bytes_read;
+ GError *error = NULL;
- entry = GTK_ENTRY (glade_xml_get_widget (xml, widget_name));
- if (entry == NULL)
- g_warning ("Entry for `%s' not found.", widget_name);
- else
- gtk_entry_set_text (entry, value ? value : "");
+ bytes_read = g_input_stream_read_finish (
+ input_stream, result, &error);
+
+ if (attachment_save_check_for_error (save_context, error))
+ return;
+
+ if (bytes_read == 0) {
+ GSimpleAsyncResult *simple;
+ GFile *destination;
+
+ /* Steal the result. */
+ simple = save_context->simple;
+ save_context->simple = NULL;
+
+ /* Steal the destination. */
+ destination = save_context->destination;
+ save_context->destination = NULL;
+
+ g_simple_async_result_set_op_res_gpointer (
+ simple, destination, (GDestroyNotify) g_object_unref);
+ g_simple_async_result_complete (simple);
+
+ attachment_save_context_free (save_context);
+
+ return;
+ }
+
+ attachment = save_context->attachment;
+ cancellable = attachment->priv->cancellable;
+ output_stream = save_context->output_stream;
+ save_context->bytes_read = bytes_read;
+
+ attachment_progress_cb (
+ g_seekable_tell (G_SEEKABLE (input_stream)),
+ save_context->total_num_bytes, attachment);
+
+ g_output_stream_write_async (
+ output_stream,
+ save_context->buffer,
+ save_context->bytes_read,
+ G_PRIORITY_DEFAULT, cancellable,
+ (GAsyncReadyCallback) attachment_save_write_cb,
+ save_context);
}
static void
-connect_widget (GladeXML *gui, const char *name, const char *signal_name,
- GCallback func, gpointer data)
+attachment_save_got_output_stream (SaveContext *save_context)
{
- GtkWidget *widget;
+ GCancellable *cancellable;
+ GInputStream *input_stream;
+ CamelDataWrapper *wrapper;
+ CamelMimePart *mime_part;
+ CamelStream *stream;
+ EAttachment *attachment;
+ GByteArray *buffer;
+
+ attachment = save_context->attachment;
+ cancellable = attachment->priv->cancellable;
+ mime_part = e_attachment_get_mime_part (attachment);
+
+ /* Decode the MIME part to an in-memory buffer. We have to do
+ * this because CamelStream is synchronous-only, and using threads
+ * is dangerous because CamelDataWrapper is not reentrant. */
+ buffer = g_byte_array_new ();
+ stream = camel_stream_mem_new ();
+ camel_stream_mem_set_byte_array (CAMEL_STREAM_MEM (stream), buffer);
+ wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (mime_part));
+ camel_data_wrapper_decode_to_stream (wrapper, stream);
+ camel_object_unref (stream);
- widget = glade_xml_get_widget (gui, name);
- g_signal_connect (widget, signal_name, func, data);
+ /* Load the buffer into a GMemoryInputStream. */
+ input_stream = g_memory_input_stream_new_from_data (
+ buffer->data, (gssize) buffer->len,
+ (GDestroyNotify) g_free);
+ save_context->input_stream = input_stream;
+ save_context->total_num_bytes = (goffset) buffer->len;
+ g_byte_array_free (buffer, FALSE);
+
+ g_input_stream_read_async (
+ input_stream,
+ save_context->buffer,
+ sizeof (save_context->buffer),
+ G_PRIORITY_DEFAULT, cancellable,
+ (GAsyncReadyCallback) attachment_save_read_cb,
+ save_context);
}
static void
-close_cb (GtkWidget *widget, gpointer data)
+attachment_save_create_cb (GFile *destination,
+ GAsyncResult *result,
+ SaveContext *save_context)
{
EAttachment *attachment;
- DialogData *dialog_data;
+ GCancellable *cancellable;
+ GFileOutputStream *output_stream;
+ GError *error = NULL;
+
+ /* Output stream might be NULL, so don't use cast macro. */
+ output_stream = g_file_create_finish (destination, result, &error);
+ save_context->output_stream = (GOutputStream *) output_stream;
+
+ attachment = save_context->attachment;
+ cancellable = attachment->priv->cancellable;
+
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_EXISTS)) {
+ destination = attachment_save_new_candidate (save_context);
- dialog_data = (DialogData *) data;
- attachment = dialog_data->attachment;
+ g_file_create_async (
+ destination, G_FILE_CREATE_NONE,
+ G_PRIORITY_DEFAULT, cancellable,
+ (GAsyncReadyCallback) attachment_save_create_cb,
+ save_context);
- gtk_widget_destroy (dialog_data->dialog);
- g_object_unref (attachment->editor_gui);
- attachment->editor_gui = NULL;
+ g_object_unref (destination);
+ g_error_free (error);
+ return;
+ }
+
+ if (attachment_save_check_for_error (save_context, error))
+ return;
+
+ save_context->destination = g_object_ref (destination);
+ attachment_save_got_output_stream (save_context);
+}
+
+static void
+attachment_save_replace_cb (GFile *destination,
+ GAsyncResult *result,
+ SaveContext *save_context)
+{
+ GFileOutputStream *output_stream;
+ GError *error = NULL;
- destroy_dialog_data (dialog_data);
+ /* Output stream might be NULL, so don't use cast macro. */
+ output_stream = g_file_replace_finish (destination, result, &error);
+ save_context->output_stream = (GOutputStream *) output_stream;
+
+ if (attachment_save_check_for_error (save_context, error))
+ return;
+
+ save_context->destination = g_object_ref (destination);
+ attachment_save_got_output_stream (save_context);
}
static void
-ok_cb (GtkWidget *widget, gpointer data)
+attachment_save_query_info_cb (GFile *destination,
+ GAsyncResult *result,
+ SaveContext *save_context)
{
- DialogData *dialog_data;
EAttachment *attachment;
- const char *str;
-
- dialog_data = (DialogData *) data;
- attachment = dialog_data->attachment;
-
- str = gtk_entry_get_text (dialog_data->file_name_entry);
- if (attachment->is_available_local)
- camel_mime_part_set_filename (attachment->body, str);
- g_free (attachment->file_name);
- attachment->file_name = g_strdup (str);
-
- str = gtk_entry_get_text (dialog_data->description_entry);
- if (attachment->is_available_local) {
- camel_mime_part_set_description (attachment->body, str);
- } else {
- g_free (attachment->description);
- attachment->description = g_strdup (str);
+ GCancellable *cancellable;
+ GFileInfo *file_info;
+ GFileType file_type;
+ GError *error = NULL;
+
+ attachment = save_context->attachment;
+ cancellable = attachment->priv->cancellable;
+
+ file_info = g_file_query_info_finish (destination, result, &error);
+
+ /* G_IO_ERROR_NOT_FOUND just means we're creating a new file. */
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) {
+ g_error_free (error);
+ goto replace;
}
- str = gtk_entry_get_text (dialog_data->mime_type_entry);
- if (attachment->is_available_local) {
- camel_mime_part_set_content_type (attachment->body, str);
- camel_data_wrapper_set_mime_type(camel_medium_get_content_object(CAMEL_MEDIUM (attachment->body)), str);
+ if (attachment_save_check_for_error (save_context, error))
+ return;
+
+ file_type = g_file_info_get_file_type (file_info);
+ g_object_unref (file_info);
+
+ if (file_type == G_FILE_TYPE_DIRECTORY) {
+ save_context->directory = g_object_ref (destination);
+ destination = attachment_save_new_candidate (save_context);
+
+ g_file_create_async (
+ destination, G_FILE_CREATE_NONE,
+ G_PRIORITY_DEFAULT, cancellable,
+ (GAsyncReadyCallback) attachment_save_create_cb,
+ save_context);
+
+ g_object_unref (destination);
+
+ return;
}
- if (attachment->is_available_local) {
- switch (gtk_toggle_button_get_active (dialog_data->disposition_checkbox)) {
- case 0:
- camel_mime_part_set_disposition (attachment->body, "attachment");
- break;
- case 1:
- camel_mime_part_set_disposition (attachment->body, "inline");
- break;
- default:
- /* Hmmmm? */
- break;
- }
- } else {
- attachment->disposition = gtk_toggle_button_get_active (dialog_data->disposition_checkbox);
+replace:
+ g_file_replace_async (
+ destination, NULL, FALSE,
+#if GLIB_CHECK_VERSION(2,20,0)
+ G_FILE_CREATE_REPLACE_DESTINATION,
+#else
+ G_FILE_CREATE_NONE,
+#endif
+ G_PRIORITY_DEFAULT, cancellable,
+ (GAsyncReadyCallback) attachment_save_replace_cb,
+ save_context);
+}
+
+void
+e_attachment_save_async (EAttachment *attachment,
+ GFile *destination,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ SaveContext *save_context;
+ GCancellable *cancellable;
+
+ g_return_if_fail (E_IS_ATTACHMENT (attachment));
+ g_return_if_fail (G_IS_FILE (destination));
+ g_return_if_fail (callback != NULL);
+
+ if (e_attachment_get_loading (attachment)) {
+ g_simple_async_report_error_in_idle (
+ G_OBJECT (attachment), callback, user_data,
+ G_IO_ERROR, G_IO_ERROR_BUSY,
+ _("A load operation is already in progress"));
+ return;
}
- changed (attachment);
- close_cb (widget, data);
+ if (e_attachment_get_saving (attachment)) {
+ g_simple_async_report_error_in_idle (
+ G_OBJECT (attachment), callback, user_data,
+ G_IO_ERROR, G_IO_ERROR_BUSY,
+ _("A save operation is already in progress"));
+ return;
+ }
+
+ if (e_attachment_get_mime_part (attachment) == NULL) {
+ g_simple_async_report_error_in_idle (
+ G_OBJECT (attachment), callback, user_data,
+ G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
+ _("Attachment contents not loaded"));
+ return;
+ }
+
+ save_context = attachment_save_context_new (
+ attachment, callback, user_data);
+
+ cancellable = attachment->priv->cancellable;
+ g_cancellable_reset (cancellable);
+
+ /* First we need to know if destination is a directory. */
+ g_file_query_info_async (
+ destination, G_FILE_ATTRIBUTE_STANDARD_TYPE,
+ G_FILE_QUERY_INFO_NONE, G_PRIORITY_DEFAULT,
+ cancellable, (GAsyncReadyCallback)
+ attachment_save_query_info_cb, save_context);
}
-static void
-response_cb (GtkWidget *widget, gint response, gpointer data)
+GFile *
+e_attachment_save_finish (EAttachment *attachment,
+ GAsyncResult *result,
+ GError **error)
{
- if (response == GTK_RESPONSE_OK)
- ok_cb (widget, data);
- else
- close_cb (widget, data);
+ GSimpleAsyncResult *simple;
+ GFile *destination;
+
+ g_return_val_if_fail (E_IS_ATTACHMENT (attachment), FALSE);
+ g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), FALSE);
+
+ simple = G_SIMPLE_ASYNC_RESULT (result);
+ destination = g_simple_async_result_get_op_res_gpointer (simple);
+ if (destination != NULL)
+ g_object_ref (destination);
+ g_simple_async_result_propagate_error (simple, error);
+ g_object_unref (simple);
+
+ attachment_set_saving (attachment, FALSE);
+
+ return destination;
}
void
-e_attachment_edit (EAttachment *attachment, GtkWidget *parent)
+e_attachment_save_handle_error (EAttachment *attachment,
+ GAsyncResult *result,
+ GtkWindow *parent)
{
- CamelContentType *content_type;
- const char *disposition;
- DialogData *dialog_data;
- GladeXML *editor_gui;
- GtkWidget *window;
- char *type;
- char *filename;
+ GFile *file;
+ GFileInfo *file_info;
+ GtkWidget *dialog;
+ const gchar *display_name;
+ const gchar *primary_text;
+ GError *error = NULL;
g_return_if_fail (E_IS_ATTACHMENT (attachment));
+ g_return_if_fail (G_IS_ASYNC_RESULT (result));
+ g_return_if_fail (GTK_IS_WINDOW (parent));
+
+ file = e_attachment_save_finish (attachment, result, &error);
- if (attachment->editor_gui != NULL) {
- window = glade_xml_get_widget (attachment->editor_gui, "dialog");
- gdk_window_show (window->window);
+ if (file != NULL) {
+ g_object_unref (file);
return;
}
- filename = g_build_filename (EVOLUTION_GLADEDIR, "e-attachment.glade", NULL);
- editor_gui = glade_xml_new (filename, NULL, NULL);
- g_free (filename);
-
- if (editor_gui == NULL) {
- g_warning ("Cannot load `e-attachment.glade'");
+ /* Ignore cancellations. */
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
return;
- }
- attachment->editor_gui = editor_gui;
-
- gtk_window_set_transient_for (GTK_WINDOW (glade_xml_get_widget (editor_gui, "dialog")),
- GTK_WINDOW (gtk_widget_get_toplevel (parent)));
-
- dialog_data = g_new (DialogData, 1);
- dialog_data->attachment = attachment;
- dialog_data->dialog = glade_xml_get_widget (editor_gui, "dialog");
- dialog_data->file_name_entry = GTK_ENTRY (glade_xml_get_widget (editor_gui, "file_name_entry"));
- dialog_data->description_entry = GTK_ENTRY (glade_xml_get_widget (editor_gui, "description_entry"));
- dialog_data->mime_type_entry = GTK_ENTRY (glade_xml_get_widget (editor_gui, "mime_type_entry"));
- dialog_data->disposition_checkbox = GTK_TOGGLE_BUTTON (glade_xml_get_widget (editor_gui, "disposition_checkbox"));
-
- if (attachment->is_available_local && attachment->body) {
- set_entry (editor_gui, "file_name_entry", camel_mime_part_get_filename (attachment->body));
- set_entry (editor_gui, "description_entry", camel_mime_part_get_description (attachment->body));
- content_type = camel_mime_part_get_content_type (attachment->body);
- type = camel_content_type_simple (content_type);
- set_entry (editor_gui, "mime_type_entry", type);
- g_free (type);
-
- disposition = camel_mime_part_get_disposition (attachment->body);
- gtk_toggle_button_set_active (dialog_data->disposition_checkbox,
- disposition && !g_ascii_strcasecmp (disposition, "inline"));
- } else {
- set_entry (editor_gui, "file_name_entry", attachment->file_name);
- set_entry (editor_gui, "description_entry", attachment->description);
- if ((type = attachment_guess_mime_type (attachment->file_name))) {
- set_entry (editor_gui, "mime_type_entry", type);
- g_free (type);
- } else {
- set_entry (editor_gui, "mime_type_entry", "");
- }
+ file_info = e_attachment_get_file_info (attachment);
- gtk_toggle_button_set_active (dialog_data->disposition_checkbox, attachment->disposition);
- }
+ if (file_info != NULL)
+ display_name = g_file_info_get_display_name (file_info);
+ else
+ display_name = NULL;
+
+ if (display_name != NULL)
+ primary_text = g_strdup_printf (
+ _("Could not save '%s'"), display_name);
+ else
+ primary_text = g_strdup_printf (
+ _("Could not save the attachment"));
+
+ dialog = gtk_message_dialog_new_with_markup (
+ parent, GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
+ "<big><b>%s</b></big>", primary_text);
+
+ gtk_message_dialog_format_secondary_text (
+ GTK_MESSAGE_DIALOG (dialog), "%s", error->message);
- connect_widget (editor_gui, "dialog", "response", (GCallback)response_cb, dialog_data);
+ gtk_dialog_run (GTK_DIALOG (dialog));
- /* make sure that when the parent gets hidden/closed that our windows also close */
- parent = gtk_widget_get_toplevel (parent);
- gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog_data->dialog), TRUE);
+ gtk_widget_destroy (dialog);
+ g_error_free (error);
}
diff --git a/widgets/misc/e-attachment.h b/widgets/misc/e-attachment.h
index 7b45f24ae5..934e1e04b6 100644
--- a/widgets/misc/e-attachment.h
+++ b/widgets/misc/e-attachment.h
@@ -1,4 +1,6 @@
/*
+ * e-attachment.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
@@ -13,91 +15,131 @@
* License along with the program; if not, see <http://www.gnu.org/licenses/>
*
*
- * Authors:
- * Ettore Perazzoli <ettore@ximian.com>
- * Srinivasa Ragavan <sragavan@novell.com>
- *
* Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
*
*/
-#ifndef __E_ATTACHMENT_H__
-#define __E_ATTACHMENT_H__
+#ifndef E_ATTACHMENT_H
+#define E_ATTACHMENT_H
-#include <gio/gio.h>
#include <gtk/gtk.h>
-#include <glade/glade-xml.h>
-#include <camel/camel-mime-part.h>
-#include <camel/camel-exception.h>
#include <camel/camel-cipher-context.h>
-
-#ifdef __cplusplus
-extern "C" {
-#pragma }
-#endif /* __cplusplus */
-
-#define E_TYPE_ATTACHMENT (e_attachment_get_type ())
-#define E_ATTACHMENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_ATTACHMENT, EAttachment))
-#define E_ATTACHMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_ATTACHMENT, EAttachmentClass))
-#define E_IS_ATTACHMENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_ATTACHMENT))
-#define E_IS_ATTACHMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), E_TYPE_ATTACHMENT))
-
-
-typedef struct _EAttachment EAttachment;
-typedef struct _EAttachmentClass EAttachmentClass;
+#include <camel/camel-mime-part.h>
+#include <camel/camel-mime-message.h>
+#include <camel/camel-multipart.h>
+
+/* Standard GObject macros */
+#define E_TYPE_ATTACHMENT \
+ (e_attachment_get_type ())
+#define E_ATTACHMENT(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_ATTACHMENT, EAttachment))
+#define E_ATTACHMENT_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_ATTACHMENT, EAttachmentClass))
+#define E_IS_ATTACHMENT(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_ATTACHMENT))
+#define E_IS_ATTACHMENT_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_ATTACHMENT))
+#define E_ATTACHMENT_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_ATTACHMENT, EAttachmentClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EAttachment EAttachment;
+typedef struct _EAttachmentClass EAttachmentClass;
+typedef struct _EAttachmentPrivate EAttachmentPrivate;
struct _EAttachment {
GObject parent;
-
- GladeXML *editor_gui;
-
- CamelMimePart *body;
- gboolean guessed_type;
- gulong size;
-
- GdkPixbuf *pixbuf_cache;
-
- GCancellable *cancellable;
-
- gboolean is_available_local;
- int percentage;
- char *file_name;
- char *description;
- gboolean disposition;
- int index;
- char *store_uri;
-
- /* Status of signed/encrypted attachments */
- camel_cipher_validity_sign_t sign;
- camel_cipher_validity_encrypt_t encrypt;
+ EAttachmentPrivate *priv;
};
struct _EAttachmentClass {
GObjectClass parent_class;
-
- void (*changed) (EAttachment *attachment);
- void (*update) (EAttachment *attachment, char *msg);
};
-GType e_attachment_get_type (void);
-EAttachment *e_attachment_new (const char *file_name,
- const char *disposition,
- CamelException *ex);
-EAttachment * e_attachment_new_remote_file (GtkWindow *error_dlg_parent,
- const char *url,
- const char *disposition,
- const char *path,
- CamelException *ex);
-void e_attachment_build_remote_file (const char *filename,
- EAttachment *attachment,
- const char *disposition,
- CamelException *ex);
-EAttachment *e_attachment_new_from_mime_part (CamelMimePart *part);
-void e_attachment_edit (EAttachment *attachment,
- GtkWidget *parent);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif /* __E_ATTACHMENT_H__ */
+GType e_attachment_get_type (void);
+EAttachment * e_attachment_new (void);
+EAttachment * e_attachment_new_for_path (const gchar *path);
+EAttachment * e_attachment_new_for_uri (const gchar *uri);
+EAttachment * e_attachment_new_for_message (CamelMimeMessage *message);
+void e_attachment_add_to_multipart (EAttachment *attachment,
+ CamelMultipart *multipart,
+ const gchar *default_charset);
+void e_attachment_cancel (EAttachment *attachment);
+gboolean e_attachment_get_can_show (EAttachment *attachment);
+void e_attachment_set_can_show (EAttachment *attachment,
+ gboolean can_show);
+const gchar * e_attachment_get_disposition (EAttachment *attachment);
+void e_attachment_set_disposition (EAttachment *attachment,
+ const gchar *disposition);
+GFile * e_attachment_get_file (EAttachment *attachment);
+void e_attachment_set_file (EAttachment *attachment,
+ GFile *file);
+GFileInfo * e_attachment_get_file_info (EAttachment *attachment);
+gboolean e_attachment_get_loading (EAttachment *attachment);
+CamelMimePart * e_attachment_get_mime_part (EAttachment *attachment);
+void e_attachment_set_mime_part (EAttachment *attachment,
+ CamelMimePart *mime_part);
+gint e_attachment_get_percent (EAttachment *attachment);
+GtkTreeRowReference *
+ e_attachment_get_reference (EAttachment *attachment);
+void e_attachment_set_reference (EAttachment *attachment,
+ GtkTreeRowReference *reference);
+gboolean e_attachment_get_saving (EAttachment *attachment);
+gboolean e_attachment_get_shown (EAttachment *attachment);
+void e_attachment_set_shown (EAttachment *attachment,
+ gboolean shown);
+camel_cipher_validity_encrypt_t
+ e_attachment_get_encrypted (EAttachment *attachment);
+void e_attachment_set_encrypted (EAttachment *attachment,
+ camel_cipher_validity_encrypt_t encrypted);
+camel_cipher_validity_sign_t
+ e_attachment_get_signed (EAttachment *attachment);
+void e_attachment_set_signed (EAttachment *attachment,
+ camel_cipher_validity_sign_t signed_);
+const gchar * e_attachment_get_description (EAttachment *attachment);
+const gchar * e_attachment_get_thumbnail_path (EAttachment *attachment);
+gboolean e_attachment_is_rfc822 (EAttachment *attachment);
+GList * e_attachment_list_apps (EAttachment *attachment);
+
+/* Asynchronous Operations */
+void e_attachment_load_async (EAttachment *attachment,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean e_attachment_load_finish (EAttachment *attachment,
+ GAsyncResult *result,
+ GError **error);
+void e_attachment_open_async (EAttachment *attachment,
+ GAppInfo *app_info,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean e_attachment_open_finish (EAttachment *attachment,
+ GAsyncResult *result,
+ GError **error);
+void e_attachment_save_async (EAttachment *attachment,
+ GFile *destination,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+GFile * e_attachment_save_finish (EAttachment *attachment,
+ GAsyncResult *result,
+ GError **error);
+
+/* Handy GAsyncReadyCallback Functions */
+void e_attachment_load_handle_error (EAttachment *attachment,
+ GAsyncResult *result,
+ GtkWindow *parent);
+void e_attachment_open_handle_error (EAttachment *attachment,
+ GAsyncResult *result,
+ GtkWindow *parent);
+void e_attachment_save_handle_error (EAttachment *attachment,
+ GAsyncResult *result,
+ GtkWindow *parent);
+
+G_END_DECLS
+
+#endif /* E_ATTACHMENT_H */
diff --git a/widgets/misc/e-expander.c b/widgets/misc/e-expander.c
deleted file mode 100644
index 771598739d..0000000000
--- a/widgets/misc/e-expander.c
+++ /dev/null
@@ -1,1341 +0,0 @@
-/*
- * GTK - The GIMP Toolkit
- *
- * 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:
- * Mark McLoughlin <mark@skynet.ie>
- *
- * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
- * Copyright (C) 2003 Sun Microsystems, Inc.
- *
- */
-
-#include <config.h>
-
-#include "e-expander.h"
-#include "ea-widgets.h"
-
-#include <gdk/gdkkeysyms.h>
-
-#define DEFAULT_EXPANDER_SIZE 10
-#define DEFAULT_EXPANDER_SPACING 2
-
-/* ESTUFF */
-#ifndef _
-#define _(x) (x)
-#endif
-#define E_EXPANDER_GET_PRIVATE(expander) ((EExpanderPrivate *)g_object_get_data (G_OBJECT (expander), "e-expander-priv"))
-
-enum {
- PROP_0,
- PROP_EXPANDED,
- PROP_LABEL,
- PROP_USE_UNDERLINE,
- PROP_PADDING,
- PROP_LABEL_WIDGET
-};
-
-typedef struct {
- GtkWidget *label_widget;
- gint spacing;
-
- GtkExpanderStyle expander_style;
- guint animation_timeout;
-
- guint expanded : 1;
- guint use_underline : 1;
- guint button_down : 1;
-} EExpanderPrivate;
-
-static void e_expander_class_init (EExpanderClass *klass);
-static void e_expander_init (EExpander *expander);
-
-static void e_expander_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec);
-static void e_expander_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec);
-
-static void e_expander_destroy (GtkObject *object);
-
-static void e_expander_realize (GtkWidget *widget);
-static void e_expander_size_request (GtkWidget *widget,
- GtkRequisition *requisition);
-static void e_expander_size_allocate (GtkWidget *widget,
- GtkAllocation *allocation);
-static void e_expander_map (GtkWidget *widget);
-static gboolean e_expander_expose (GtkWidget *widget,
- GdkEventExpose *event);
-static gboolean e_expander_button_press (GtkWidget *widget,
- GdkEventButton *event);
-static gboolean e_expander_button_release (GtkWidget *widget,
- GdkEventButton *event);
-static gboolean e_expander_motion_notify (GtkWidget *widget,
- GdkEventMotion *event);
-static gboolean e_expander_enter_notify (GtkWidget *widget,
- GdkEventCrossing *event);
-static gboolean e_expander_leave_notify (GtkWidget *widget,
- GdkEventCrossing *event);
-static gboolean e_expander_focus (GtkWidget *widget,
- GtkDirectionType direction);
-
-static void e_expander_add (GtkContainer *container,
- GtkWidget *widget);
-static void e_expander_remove (GtkContainer *container,
- GtkWidget *widget);
-static void e_expander_forall (GtkContainer *container,
- gboolean include_internals,
- GtkCallback callback,
- gpointer callback_data);
-
-static void e_expander_activate (EExpander *expander);
-
-static GtkBinClass *parent_class = NULL;
-
-GType
-e_expander_get_type (void)
-{
- static GType expander_type = 0;
-
- if (!expander_type)
- {
- static const GTypeInfo expander_info =
- {
- sizeof (EExpanderClass),
- NULL, /* base_init */
- NULL, /* base_finalize */
- (GClassInitFunc) e_expander_class_init,
- NULL, /* class_finalize */
- NULL, /* class_data */
- sizeof (EExpander),
- 0, /* n_preallocs */
- (GInstanceInitFunc) e_expander_init,
- };
-
- expander_type = g_type_register_static (GTK_TYPE_BIN,
- "EExpander",
- &expander_info, 0);
- }
-
- return expander_type;
-}
-
-static void
-e_expander_class_init (EExpanderClass *klass)
-{
- GObjectClass *gobject_class;
- GtkObjectClass *gtkobject_class;
- GtkWidgetClass *widget_class;
- GtkContainerClass *container_class;
-
- parent_class = g_type_class_peek_parent (klass);
-
- gobject_class = (GObjectClass *) klass;
- gtkobject_class = (GtkObjectClass *) klass;
- widget_class = (GtkWidgetClass *) klass;
- container_class = (GtkContainerClass *) klass;
-
- gobject_class->set_property = e_expander_set_property;
- gobject_class->get_property = e_expander_get_property;
-
- gtkobject_class->destroy = e_expander_destroy;
-
- widget_class->realize = e_expander_realize;
- widget_class->size_request = e_expander_size_request;
- widget_class->size_allocate = e_expander_size_allocate;
- widget_class->map = e_expander_map;
- widget_class->expose_event = e_expander_expose;
- widget_class->button_press_event = e_expander_button_press;
- widget_class->button_release_event = e_expander_button_release;
- widget_class->motion_notify_event = e_expander_motion_notify;
- widget_class->enter_notify_event = e_expander_enter_notify;
- widget_class->leave_notify_event = e_expander_leave_notify;
- widget_class->focus = e_expander_focus;
-
- container_class->add = e_expander_add;
- container_class->remove = e_expander_remove;
- container_class->forall = e_expander_forall;
-
- klass->activate = e_expander_activate;
-
- /* ESTUFF g_type_class_add_private (klass, sizeof (EExpanderPrivate)); */
-
- g_object_class_install_property (gobject_class,
- PROP_EXPANDED,
- g_param_spec_boolean ("expanded",
- _("Expanded"),
- _("Whether or not the expander is expanded"),
- FALSE,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
-
- g_object_class_install_property (gobject_class,
- PROP_LABEL,
- g_param_spec_string ("label",
- _("Label"),
- _("Text of the expander's label"),
- NULL,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
-
- g_object_class_install_property (gobject_class,
- PROP_USE_UNDERLINE,
- g_param_spec_boolean ("use_underline",
- _("Use underline"),
- _("If set, an underline in the text indicates the next character should be used for the mnemonic accelerator key"),
- FALSE,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
-
- g_object_class_install_property (gobject_class,
- PROP_PADDING,
- g_param_spec_int ("spacing",
- _("Spacing"),
- _("Space to put between the label and the child"),
- 0,
- G_MAXINT,
- 0,
- G_PARAM_READWRITE));
-
- g_object_class_install_property (gobject_class,
- PROP_LABEL_WIDGET,
- g_param_spec_object ("label_widget",
- _("Label widget"),
- _("A widget to display in place of the usual expander label"),
- GTK_TYPE_WIDGET,
- G_PARAM_READWRITE));
-
- gtk_widget_class_install_style_property (widget_class,
- g_param_spec_int ("expander-size",
- _("Expander Size"),
- _("Size of the expander arrow"),
- 0,
- G_MAXINT,
- DEFAULT_EXPANDER_SIZE,
- G_PARAM_READABLE));
-
- gtk_widget_class_install_style_property (widget_class,
- g_param_spec_int ("expander-spacing",
- _("Indicator Spacing"),
- _("Spacing around expander arrow"),
- 0,
- G_MAXINT,
- DEFAULT_EXPANDER_SPACING,
- G_PARAM_READABLE));
-
- widget_class->activate_signal =
- g_signal_new ("activate",
- G_TYPE_FROM_CLASS (gobject_class),
- G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
- G_STRUCT_OFFSET (EExpanderClass, activate),
- NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
-
- e_expander_a11y_init();
-}
-
-static void
-e_expander_init (EExpander *expander)
-{
- EExpanderPrivate *priv;
-
- /* ESTUFF */
- priv = g_new0 (EExpanderPrivate, 1);
- g_object_set_data_full (G_OBJECT (expander), "e-expander-priv", priv, g_free);
-
- /* ESTUFF priv = E_EXPANDER_GET_PRIVATE (expander); */
-
- GTK_WIDGET_SET_FLAGS (expander, GTK_CAN_FOCUS);
- GTK_WIDGET_UNSET_FLAGS (expander, GTK_NO_WINDOW);
-
- priv->label_widget = NULL;
- priv->spacing = 0;
-
- priv->expander_style = GTK_EXPANDER_COLLAPSED;
- priv->animation_timeout = 0;
-
- priv->expanded = FALSE;
- priv->use_underline = FALSE;
- priv->button_down = FALSE;
-
-}
-
-static void
-e_expander_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- EExpander *expander = E_EXPANDER (object);
-
- switch (prop_id)
- {
- case PROP_EXPANDED:
- e_expander_set_expanded (expander, g_value_get_boolean (value));
- break;
- case PROP_LABEL:
- e_expander_set_label (expander, g_value_get_string (value));
- break;
- case PROP_USE_UNDERLINE:
- e_expander_set_use_underline (expander, g_value_get_boolean (value));
- break;
- case PROP_PADDING:
- e_expander_set_spacing (expander, g_value_get_int (value));
- break;
- case PROP_LABEL_WIDGET:
- e_expander_set_label_widget (expander, g_value_get_object (value));
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-e_expander_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- EExpander *expander = E_EXPANDER (object);
- EExpanderPrivate *priv;
-
- priv = E_EXPANDER_GET_PRIVATE (expander);
-
- switch (prop_id)
- {
- case PROP_EXPANDED:
- g_value_set_boolean (value, priv->expanded);
- break;
- case PROP_LABEL:
- g_value_set_string (value, e_expander_get_label (expander));
- break;
- case PROP_USE_UNDERLINE:
- g_value_set_boolean (value, priv->use_underline);
- break;
- case PROP_PADDING:
- g_value_set_int (value, priv->spacing);
- break;
- case PROP_LABEL_WIDGET:
- g_value_set_object (value,
- priv->label_widget ?
- G_OBJECT (priv->label_widget) : NULL);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-e_expander_destroy (GtkObject *object)
-{
- EExpander *expander = E_EXPANDER (object);
- EExpanderPrivate *priv;
-
- priv = E_EXPANDER_GET_PRIVATE (expander);
-
- if (priv->animation_timeout)
- g_source_remove (priv->animation_timeout);
- priv->animation_timeout = 0;
-
- GTK_OBJECT_CLASS (parent_class)->destroy (object);
-}
-
-static void
-e_expander_realize (GtkWidget *widget)
-{
- GdkWindowAttr attributes;
- gint attributes_mask;
- gint border_width;
-
- GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
-
- border_width = GTK_CONTAINER (widget)->border_width;
-
- attributes.x = widget->allocation.x + border_width;
- attributes.y = widget->allocation.y + border_width;
- attributes.width = widget->allocation.width - 2 * border_width;
- attributes.height = widget->allocation.height - 2 * border_width;
- attributes.window_type = GDK_WINDOW_CHILD;
- attributes.wclass = GDK_INPUT_OUTPUT;
- attributes.visual = gtk_widget_get_visual (widget);
- attributes.colormap = gtk_widget_get_colormap (widget);
- attributes.event_mask = gtk_widget_get_events (widget) |
- GDK_POINTER_MOTION_MASK |
- GDK_POINTER_MOTION_HINT_MASK |
- GDK_BUTTON_PRESS_MASK |
- GDK_BUTTON_RELEASE_MASK |
- GDK_EXPOSURE_MASK |
- GDK_ENTER_NOTIFY_MASK |
- GDK_LEAVE_NOTIFY_MASK;
-
- attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
-
- widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
- &attributes, attributes_mask);
- gdk_window_set_user_data (widget->window, widget);
-
- widget->style = gtk_style_attach (widget->style, widget->window);
- gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
-}
-
-static void
-e_expander_size_request (GtkWidget *widget,
- GtkRequisition *requisition)
-{
- EExpander *expander;
- GtkBin *bin;
- EExpanderPrivate *priv;
- gint border_width;
- gint expander_size;
- gint expander_spacing;
- gboolean interior_focus;
- gint focus_width;
- gint focus_pad;
-
- expander = E_EXPANDER (widget);
- bin = GTK_BIN (widget);
-
- priv = E_EXPANDER_GET_PRIVATE (expander);
-
- border_width = GTK_CONTAINER (widget)->border_width;
-
- gtk_widget_style_get (widget,
- "interior-focus", &interior_focus,
- "focus-line-width", &focus_width,
- "focus-padding", &focus_pad,
- "expander-size", &expander_size,
- "expander-spacing", &expander_spacing,
- NULL);
-
- requisition->width = expander_size + 2 * expander_spacing +
- 2 * focus_width + 2 * focus_pad;
- requisition->height = interior_focus ? (2 * focus_width + 2 * focus_pad) : 0;
-
- if (priv->label_widget && GTK_WIDGET_VISIBLE (priv->label_widget))
- {
- GtkRequisition label_requisition;
-
- gtk_widget_size_request (priv->label_widget, &label_requisition);
-
- requisition->width += label_requisition.width;
- requisition->height += label_requisition.height;
- }
-
- requisition->height = MAX (expander_size + 2 * expander_spacing, requisition->height);
-
- if (!interior_focus)
- requisition->height += 2 * focus_width + 2 * focus_pad;
-
- if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
- {
- GtkRequisition child_requisition;
-
- gtk_widget_size_request (bin->child, &child_requisition);
-
- if (!interior_focus)
- child_requisition.width += 2 * focus_width + 2 * focus_pad;
-
- requisition->width = MAX (requisition->width, child_requisition.width);
- requisition->height += child_requisition.height + priv->spacing;
- }
-
- requisition->width += 2 * border_width;
- requisition->height += 2 * border_width + 2 * priv->spacing;
-}
-
-static void
-e_expander_size_allocate (GtkWidget *widget,
- GtkAllocation *allocation)
-{
- EExpander *expander;
- GtkBin *bin;
- EExpanderPrivate *priv;
- GtkRequisition child_requisition;
- gboolean child_visible = FALSE;
- gint border_width;
- gint expander_size;
- gint expander_spacing;
- gboolean interior_focus;
- gint focus_width;
- gint focus_pad;
- gint label_height;
-
- expander = E_EXPANDER (widget);
- bin = GTK_BIN (widget);
-
- priv = E_EXPANDER_GET_PRIVATE (expander);
-
- border_width = GTK_CONTAINER (widget)->border_width;
-
- gtk_widget_style_get (widget,
- "interior-focus", &interior_focus,
- "focus-line-width", &focus_width,
- "focus-padding", &focus_pad,
- "expander-size", &expander_size,
- "expander-spacing", &expander_spacing,
- NULL);
-
- child_requisition.width = 0;
- child_requisition.height = 0;
- if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
- {
- child_visible = TRUE;
- gtk_widget_get_child_requisition (bin->child, &child_requisition);
- }
-
- widget->allocation = *allocation;
-
- if (GTK_WIDGET_REALIZED (widget))
- gdk_window_move_resize (widget->window,
- allocation->x + border_width,
- allocation->y + border_width,
- MAX (allocation->width - 2 * border_width, 0),
- MAX (allocation->height - 2 * border_width, 0));
-
- if (priv->label_widget && GTK_WIDGET_VISIBLE (priv->label_widget))
- {
- GtkAllocation label_allocation;
- GtkRequisition label_requisition;
- gboolean ltr;
-
- gtk_widget_get_child_requisition (priv->label_widget, &label_requisition);
-
- ltr = gtk_widget_get_direction (widget) != GTK_TEXT_DIR_RTL;
-
- label_allocation.x = focus_width + focus_pad;
- if (ltr)
- label_allocation.x += expander_size + 2 * expander_spacing;
- label_allocation.y = priv->spacing + focus_width + focus_pad;
-
- label_allocation.width = MIN (label_requisition.width,
- allocation->width - 2 * border_width -
- expander_size - 2 * expander_spacing -
- 2 * focus_width - 2 * focus_pad);
- label_allocation.width = MAX (label_allocation.width, 1);
-
- label_allocation.height = MIN (label_requisition.height,
- allocation->height - 2 * border_width -
- 2 * priv->spacing -
- 2 * focus_width - 2 * focus_pad -
- child_requisition.height -
- (child_visible ? priv->spacing : 0));
- label_allocation.height = MAX (label_allocation.height, 1);
-
- gtk_widget_size_allocate (priv->label_widget, &label_allocation);
-
- label_height = label_allocation.height;
- }
- else
- {
- label_height = 0;
- }
-
- if (child_visible)
- {
- GtkAllocation child_allocation;
- gint top_height;
-
- top_height = MAX (2 * expander_spacing + expander_size,
- label_height +
- (interior_focus ? 2 * focus_width + 2 * focus_pad : 0));
-
- child_allocation.x = 0;
- child_allocation.y = 2 * priv->spacing + top_height;
-
- if (!interior_focus)
- {
- child_allocation.x += focus_width + focus_pad;
- child_allocation.y += focus_width + focus_pad;
- }
-
- child_allocation.width = allocation->width - 2 * border_width -
- (!interior_focus ? 2 * focus_width + 2 * focus_pad : 0);
- child_allocation.width = MAX (child_allocation.width, 1);
-
- child_allocation.height = allocation->height - top_height -
- 2 * border_width -
- 3 * priv->spacing -
- (!interior_focus ? 2 * focus_width + 2 * focus_pad : 0);
- child_allocation.height = MAX (child_allocation.height, 1);
-
- gtk_widget_size_allocate (bin->child, &child_allocation);
- }
-}
-
-static void
-e_expander_map (GtkWidget *widget)
-{
- EExpanderPrivate *priv;
-
- priv = E_EXPANDER_GET_PRIVATE (widget);
-
- if (priv->label_widget)
- gtk_widget_map (priv->label_widget);
-
- GTK_WIDGET_CLASS (parent_class)->map (widget);
-}
-
-static GdkRectangle
-get_expander_bounds (EExpander *expander)
-{
- GtkWidget *widget;
- EExpanderPrivate *priv;
- GdkRectangle bounds;
- gint border_width;
- gint expander_size;
- gint expander_spacing;
- gboolean interior_focus;
- gint focus_width;
- gint focus_pad;
- gboolean ltr;
-
- widget = GTK_WIDGET (expander);
-
- priv = E_EXPANDER_GET_PRIVATE (expander);
-
- border_width = GTK_CONTAINER (expander)->border_width;
-
- gtk_widget_style_get (widget,
- "interior-focus", &interior_focus,
- "focus-line-width", &focus_width,
- "focus-padding", &focus_pad,
- "expander-size", &expander_size,
- "expander-spacing", &expander_spacing,
- NULL);
-
- ltr = gtk_widget_get_direction (widget) != GTK_TEXT_DIR_RTL;
-
-
- if (ltr)
- bounds.x = expander_spacing;
- else
- bounds.x = widget->allocation.width - 2 * border_width -
- expander_spacing - expander_size;
-
- if (priv->label_widget && GTK_WIDGET_VISIBLE (priv->label_widget))
- {
- GtkAllocation label_allocation;
-
- label_allocation = priv->label_widget->allocation;
-
- if (expander_size < label_allocation.height)
- bounds.y = label_allocation.y + (label_allocation.height - expander_size) / 2;
- else
- bounds.y = priv->spacing + expander_spacing;
- }
- else
- {
- bounds.y = priv->spacing + expander_spacing;
- }
-
- if (!interior_focus)
- {
- if (ltr)
- bounds.x += focus_width + focus_pad;
- else
- bounds.x -= focus_width + focus_pad;
- bounds.y += focus_width + focus_pad;
- }
-
- bounds.width = bounds.height = expander_size;
-
- return bounds;
-}
-
-static void
-e_expander_paint (EExpander *expander)
-{
- GtkWidget *widget;
- EExpanderPrivate *priv;
- gint x, y;
- GtkStateType state;
- GdkRectangle clip;
-
- widget = GTK_WIDGET (expander);
-
- priv = E_EXPANDER_GET_PRIVATE (expander);
-
- clip = get_expander_bounds (expander);
-
- x = clip.x + clip.width / 2;
- y = clip.y + clip.height / 2;
-
- state = widget->state;
- if (state != GTK_STATE_PRELIGHT)
- state = GTK_STATE_NORMAL;
-
- gtk_paint_expander (widget->style,
- widget->window,
- state,
- &clip,
- widget,
- "expander",
- x,
- y,
- priv->expander_style);
-}
-
-static void
-e_expander_paint_focus (EExpander *expander,
- GdkRectangle *area)
-{
- GtkWidget *widget;
- EExpanderPrivate *priv;
- gint x, y, width, height;
- gboolean interior_focus;
- gint focus_width;
- gint focus_pad;
- gint expander_size;
- gint expander_spacing;
- gboolean ltr;
-
- widget = GTK_WIDGET (expander);
-
- priv = E_EXPANDER_GET_PRIVATE (expander);
-
- gtk_widget_style_get (widget,
- "interior-focus", &interior_focus,
- "focus-line-width", &focus_width,
- "focus-padding", &focus_pad,
- "expander-size", &expander_size,
- "expander-spacing", &expander_spacing,
- NULL);
-
- ltr = gtk_widget_get_direction (widget) != GTK_TEXT_DIR_RTL;
-
- if (interior_focus)
- {
- if (ltr)
- x = expander_spacing * 2 + expander_size;
- else
- x = 0;
- y = priv->spacing;
-
- width = height = 2 * focus_pad + 2 * focus_width;
-
- if (priv->label_widget && GTK_WIDGET_VISIBLE (priv->label_widget))
- {
- GtkAllocation label_allocation = priv->label_widget->allocation;
-
- width += label_allocation.width;
- height += label_allocation.height;
- }
- }
- else
- {
- x = y = 0;
- width = widget->allocation.width - 2 * GTK_CONTAINER (widget)->border_width;
- height = widget->allocation.height - 2 * GTK_CONTAINER (widget)->border_width;
- }
-
- gtk_paint_focus (widget->style, widget->window, GTK_WIDGET_STATE (widget),
- area, widget, "expander",
- x, y, width, height);
-}
-
-static gboolean
-e_expander_expose (GtkWidget *widget,
- GdkEventExpose *event)
-{
- if (GTK_WIDGET_DRAWABLE (widget))
- {
- EExpander *expander = E_EXPANDER (widget);
-
- e_expander_paint (expander);
-
- if (GTK_WIDGET_HAS_FOCUS (expander))
- e_expander_paint_focus (expander, &event->area);
-
- GTK_WIDGET_CLASS (parent_class)->expose_event (widget, event);
- }
-
- return FALSE;
-}
-
-static gboolean
-is_in_expander_panel (EExpander *expander,
- GdkWindow *window,
- gint x,
- gint y)
-{
- GtkWidget *widget;
- GdkRectangle area;
-
- widget = GTK_WIDGET (expander);
-
- area = get_expander_bounds (expander);
-
- area.x = 0;
- area.width = widget->allocation.width;
-
- if (widget->window == window)
- {
- if (x >= area.x && x <= (area.x + area.width) &&
- y >= area.y && y <= (area.y + area.height))
- return TRUE;
- }
-
- return FALSE;
-}
-
-static gboolean
-e_expander_button_press (GtkWidget *widget,
- GdkEventButton *event)
-{
- EExpander *expander = E_EXPANDER (widget);
- EExpanderPrivate *priv;
-
- priv = E_EXPANDER_GET_PRIVATE (expander);
-
- if (event->button == 1 && !priv->button_down)
- {
- if (is_in_expander_panel (expander, event->window, event->x, event->y))
- {
- priv->button_down = TRUE;
- return TRUE;
- }
- }
-
- return FALSE;
-}
-
-static gboolean
-e_expander_button_release (GtkWidget *widget,
- GdkEventButton *event)
-{
- EExpander *expander = E_EXPANDER (widget);
- EExpanderPrivate *priv;
-
- priv = E_EXPANDER_GET_PRIVATE (expander);
-
- if (event->button == 1 && priv->button_down)
- {
- g_signal_emit_by_name (expander, "activate");
-
- priv->button_down = FALSE;
- return TRUE;
- }
-
- return FALSE;
-}
-
-static void
-e_expander_maybe_prelight (EExpander *expander)
-{
- GtkWidget *widget;
- EExpanderPrivate *priv;
- GtkStateType state = GTK_STATE_NORMAL;
-
- widget = GTK_WIDGET (expander);
-
- priv = E_EXPANDER_GET_PRIVATE (expander);
-
- if (!priv->button_down)
- {
- gint x, y;
-
- gdk_window_get_pointer (widget->window, &x, &y, NULL);
-
- if (is_in_expander_panel (expander, widget->window, x, y))
- state = GTK_STATE_PRELIGHT;
- }
-
- gtk_widget_set_state (widget, state);
-}
-
-static gboolean
-e_expander_motion_notify (GtkWidget *widget,
- GdkEventMotion *event)
-{
- e_expander_maybe_prelight (E_EXPANDER (widget));
-
- return FALSE;
-}
-
-static gboolean
-e_expander_enter_notify (GtkWidget *widget,
- GdkEventCrossing *event)
-{
- e_expander_maybe_prelight (E_EXPANDER (widget));
-
- return FALSE;
-}
-
-static gboolean
-e_expander_leave_notify (GtkWidget *widget,
- GdkEventCrossing *event)
-{
- gtk_widget_set_state (widget, GTK_STATE_NORMAL);
-
- return FALSE;
-}
-
-static gboolean
-focus_child_in (GtkWidget *widget,
- GtkDirectionType direction)
-{
- GtkWidget *child = gtk_bin_get_child (GTK_BIN (widget));
-
- if (!child)
- return FALSE;
-
- return gtk_widget_child_focus (child, direction);
-}
-
-static gboolean
-e_expander_focus (GtkWidget *widget,
- GtkDirectionType direction)
-{
- EExpanderPrivate *priv;
- GtkWidget *old_focus_child;
- gboolean widget_is_focus;
- gboolean label_can_focus;
-
- priv = E_EXPANDER_GET_PRIVATE (widget);
-
- widget_is_focus = gtk_widget_is_focus (widget);
- old_focus_child = GTK_CONTAINER (widget)->focus_child;
- label_can_focus = priv->label_widget && GTK_WIDGET_CAN_FOCUS (priv->label_widget);
-
- if (old_focus_child && old_focus_child == priv->label_widget)
- {
- switch (direction)
- {
- case GTK_DIR_TAB_BACKWARD:
- case GTK_DIR_LEFT:
- case GTK_DIR_UP:
- gtk_widget_grab_focus (widget);
- return TRUE;
- case GTK_DIR_DOWN:
- case GTK_DIR_TAB_FORWARD:
- case GTK_DIR_RIGHT:
- return focus_child_in (widget, direction);
- }
- }
- else if (old_focus_child)
- {
- if (gtk_widget_child_focus (old_focus_child, direction))
- return TRUE;
-
- switch (direction)
- {
- case GTK_DIR_TAB_BACKWARD:
- case GTK_DIR_LEFT:
- case GTK_DIR_UP:
- if (label_can_focus)
- gtk_widget_grab_focus (priv->label_widget);
- else
- gtk_widget_grab_focus (widget);
- return TRUE;
- case GTK_DIR_DOWN:
- case GTK_DIR_TAB_FORWARD:
- case GTK_DIR_RIGHT:
- return FALSE;
- }
- }
- else if (widget_is_focus)
- {
- switch (direction)
- {
- case GTK_DIR_TAB_BACKWARD:
- case GTK_DIR_LEFT:
- case GTK_DIR_UP:
- return FALSE;
- case GTK_DIR_DOWN:
- case GTK_DIR_TAB_FORWARD:
- case GTK_DIR_RIGHT:
- if (label_can_focus)
- {
- gtk_widget_grab_focus (priv->label_widget);
- return TRUE;
- }
-
- return focus_child_in (widget, direction);
- }
- }
- else
- {
- switch (direction)
- {
- case GTK_DIR_DOWN:
- case GTK_DIR_TAB_FORWARD:
- case GTK_DIR_TAB_BACKWARD:
- gtk_widget_grab_focus (widget);
- return TRUE;
- case GTK_DIR_UP:
- case GTK_DIR_LEFT:
- case GTK_DIR_RIGHT:
- if (!focus_child_in (widget, direction))
- {
- gtk_widget_grab_focus (widget);
- }
- return TRUE;
- }
- }
-
- g_return_val_if_reached(FALSE);
-}
-
-static void
-e_expander_add (GtkContainer *container,
- GtkWidget *widget)
-{
- GTK_CONTAINER_CLASS (parent_class)->add (container, widget);
-
- g_object_set (G_OBJECT (widget),
- "visible", E_EXPANDER_GET_PRIVATE (container)->expanded,
- NULL);
-}
-
-static void
-e_expander_remove (GtkContainer *container,
- GtkWidget *widget)
-{
- EExpander *expander = E_EXPANDER (container);
-
- if (E_EXPANDER_GET_PRIVATE (expander)->label_widget == widget)
- e_expander_set_label_widget (expander, NULL);
- else
- GTK_CONTAINER_CLASS (parent_class)->remove (container, widget);
-}
-
-static void
-e_expander_forall (GtkContainer *container,
- gboolean include_internals,
- GtkCallback callback,
- gpointer callback_data)
-{
- GtkBin *bin = GTK_BIN (container);
- EExpanderPrivate *priv;
-
- priv = E_EXPANDER_GET_PRIVATE (container);
-
- if (bin->child)
- (* callback) (bin->child, callback_data);
-
- if (priv->label_widget)
- (* callback) (priv->label_widget, callback_data);
-}
-
-static void
-e_expander_activate (EExpander *expander)
-{
- e_expander_set_expanded (expander,
- !E_EXPANDER_GET_PRIVATE (expander)->expanded);
-}
-
-GtkWidget *
-e_expander_new (const gchar *label)
-{
- return g_object_new (E_TYPE_EXPANDER, "label", label, NULL);
-}
-
-GtkWidget *
-e_expander_new_with_mnemonic (const gchar *label)
-{
- return g_object_new (E_TYPE_EXPANDER,
- "label", label,
- "use_underline", TRUE,
- NULL);
-}
-
-static gboolean
-e_expander_animation_timeout (EExpander *expander)
-{
- EExpanderPrivate *priv;
- GdkRectangle area;
- gboolean finish = FALSE;
-
- priv = E_EXPANDER_GET_PRIVATE (expander);
-
- if (GTK_WIDGET_REALIZED (expander))
- {
- area = get_expander_bounds (expander);
- gdk_window_invalidate_rect (GTK_WIDGET (expander)->window, &area, TRUE);
- }
-
- if (priv->expanded)
- {
- if (priv->expander_style == GTK_EXPANDER_COLLAPSED)
- {
- priv->expander_style = GTK_EXPANDER_SEMI_EXPANDED;
- }
- else
- {
- priv->expander_style = GTK_EXPANDER_EXPANDED;
- finish = TRUE;
- }
- }
- else
- {
- if (priv->expander_style == GTK_EXPANDER_EXPANDED)
- {
- priv->expander_style = GTK_EXPANDER_SEMI_COLLAPSED;
- }
- else
- {
- priv->expander_style = GTK_EXPANDER_COLLAPSED;
- finish = TRUE;
- }
- }
-
- if (finish)
- {
- priv->animation_timeout = 0;
- g_object_set (G_OBJECT (GTK_BIN (expander)->child),
- "visible", priv->expanded,
- NULL);
- }
-
- return !finish;
-}
-
-static void
-e_expander_start_animation (EExpander *expander)
-{
- EExpanderPrivate *priv;
-
- priv = E_EXPANDER_GET_PRIVATE (expander);
-
- if (priv->animation_timeout)
- g_source_remove (priv->animation_timeout);
-
- priv->animation_timeout =
- g_timeout_add (50,
- (GSourceFunc) e_expander_animation_timeout,
- expander);
-}
-
-void
-e_expander_set_expanded (EExpander *expander,
- gboolean expanded)
-{
- EExpanderPrivate *priv;
-
- g_return_if_fail (E_IS_EXPANDER (expander));
-
- priv = E_EXPANDER_GET_PRIVATE (expander);
-
- expanded = expanded != FALSE;
-
- if (priv->expanded != expanded)
- {
- priv->expanded = expanded;
-
- if (GTK_WIDGET_VISIBLE (expander))
- e_expander_start_animation (expander);
-
- else if (GTK_BIN (expander)->child)
- {
- priv->expander_style = expanded ? GTK_EXPANDER_EXPANDED :
- GTK_EXPANDER_COLLAPSED;
- g_object_set (G_OBJECT (GTK_BIN (expander)->child),
- "visible", priv->expanded,
- NULL);
- }
-
- gtk_widget_queue_resize (GTK_WIDGET (expander));
-
- g_object_notify (G_OBJECT (expander), "expanded");
- }
-}
-
-gboolean
-e_expander_get_expanded (EExpander *expander)
-{
- g_return_val_if_fail (E_IS_EXPANDER (expander), FALSE);
-
- return E_EXPANDER_GET_PRIVATE (expander)->expanded;
-}
-
-void
-e_expander_set_spacing (EExpander *expander,
- gint spacing)
-{
- EExpanderPrivate *priv;
-
- g_return_if_fail (E_IS_EXPANDER (expander));
- g_return_if_fail (spacing >= 0);
-
- priv = E_EXPANDER_GET_PRIVATE (expander);
-
- if (priv->spacing != spacing)
- {
- priv->spacing = spacing;
-
- gtk_widget_queue_resize (GTK_WIDGET (expander));
-
- g_object_notify (G_OBJECT (expander), "spacing");
- }
-}
-
-gint
-e_expander_get_spacing (EExpander *expander)
-{
- g_return_val_if_fail (E_IS_EXPANDER (expander), 0);
-
- return E_EXPANDER_GET_PRIVATE (expander)->spacing;
-}
-
-void
-e_expander_set_label (EExpander *expander,
- const gchar *label)
-{
- g_return_if_fail (E_IS_EXPANDER (expander));
-
- if (!label)
- {
- e_expander_set_label_widget (expander, NULL);
- }
- else
- {
- GtkWidget *child;
-
- child = gtk_label_new (label);
- gtk_label_set_use_underline (GTK_LABEL (child),
- E_EXPANDER_GET_PRIVATE (expander)->use_underline);
- gtk_widget_show (child);
-
- e_expander_set_label_widget (expander, child);
- }
-
- g_object_notify (G_OBJECT (expander), "label");
-}
-
-/**
- * e_expander_get_label:
- * @expander: a #EExpander
- *
- * If the expander's label widget is a #GtkLabel, return the
- * text in the label widget. (The frame will have a #GtkLabel
- * for the label widget if a non-%NULL argument was passed
- * to e_expander_new().)
- *
- * Return value: the text in the label, or %NULL if there
- * was no label widget or the lable widget was not
- * a #GtkLabel. This string is owned by GTK+ and
- * must not be modified or freed.
- **/
-G_CONST_RETURN char *
-e_expander_get_label (EExpander *expander)
-{
- EExpanderPrivate *priv;
-
- g_return_val_if_fail (E_IS_EXPANDER (expander), NULL);
-
- priv = E_EXPANDER_GET_PRIVATE (expander);
-
- if (priv->label_widget && GTK_IS_LABEL (priv->label_widget))
- return gtk_label_get_text (GTK_LABEL (priv->label_widget));
- else
- return NULL;
-}
-
-void
-e_expander_set_use_underline (EExpander *expander,
- gboolean use_underline)
-{
- EExpanderPrivate *priv;
-
- g_return_if_fail (E_IS_EXPANDER (expander));
-
- priv = E_EXPANDER_GET_PRIVATE (expander);
-
- use_underline = use_underline != FALSE;
-
- if (priv->use_underline != use_underline)
- {
- priv->use_underline = use_underline;
-
- if (priv->label_widget && GTK_IS_LABEL (priv->label_widget))
- gtk_label_set_use_underline (GTK_LABEL (priv->label_widget), use_underline);
-
- g_object_notify (G_OBJECT (expander), "use_underline");
- }
-}
-
-gboolean
-e_expander_get_use_underline (EExpander *expander)
-{
- g_return_val_if_fail (E_IS_EXPANDER (expander), FALSE);
-
- return E_EXPANDER_GET_PRIVATE (expander)->use_underline;
-}
-
-/**
- * e_expander_set_label_widget:
- * @expander: a #EExpander
- * @label_widget: the new label widget
- *
- * Set the label widget for the expander. This is the widget
- * that will appear embedded alongside the expander arrow.
- **/
-void
-e_expander_set_label_widget (EExpander *expander,
- GtkWidget *label_widget)
-{
- EExpanderPrivate *priv;
- gboolean need_resize = FALSE;
-
- g_return_if_fail (E_IS_EXPANDER (expander));
- g_return_if_fail (label_widget == NULL || GTK_IS_WIDGET (label_widget));
- g_return_if_fail (label_widget == NULL || label_widget->parent == NULL);
-
- priv = E_EXPANDER_GET_PRIVATE (expander);
-
- if (priv->label_widget == label_widget)
- return;
-
- if (priv->label_widget)
- {
- need_resize = GTK_WIDGET_VISIBLE (priv->label_widget);
- gtk_widget_unparent (priv->label_widget);
- }
-
- priv->label_widget = label_widget;
-
- if (label_widget)
- {
- priv->label_widget = label_widget;
- gtk_widget_set_parent (label_widget, GTK_WIDGET (expander));
- need_resize |= GTK_WIDGET_VISIBLE (label_widget);
- }
-
- if (GTK_WIDGET_VISIBLE (expander) && need_resize)
- gtk_widget_queue_resize (GTK_WIDGET (expander));
-
- g_object_notify (G_OBJECT (expander), "label_widget");
-}
-
-/**
- * e_expander_get_label_widget:
- * @expander: a #EExpander
- *
- * Retrieves the label widget for the frame. See
- * e_expander_set_label_widget().
- *
- * Return value: the label widget, or %NULL if there is none.
- **/
-GtkWidget *
-e_expander_get_label_widget (EExpander *expander)
-{
- g_return_val_if_fail (E_IS_EXPANDER (expander), NULL);
-
- return E_EXPANDER_GET_PRIVATE (expander)->label_widget;
-}
diff --git a/widgets/misc/e-expander.h b/widgets/misc/e-expander.h
deleted file mode 100644
index 6ddb68087e..0000000000
--- a/widgets/misc/e-expander.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * 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:
- * Mark McLoughlin <mark@skynet.ie>
- *
- * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
- * Copyright (C) 2003 Sun Microsystems, Inc.
- *
- */
-
-#ifndef _E_EXPANDER_H_
-#define _E_EXPANDER_H_
-
-#include <gtk/gtk.h>
-
-G_BEGIN_DECLS
-
-#define E_TYPE_EXPANDER (e_expander_get_type ())
-#define E_EXPANDER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_EXPANDER, EExpander))
-#define E_EXPANDER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_EXPANDER, EExpanderClass))
-#define E_IS_EXPANDER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_EXPANDER))
-#define E_IS_EXPANDER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), E_TYPE_EXPANDER))
-#define E_EXPANDER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), E_TYPE_EXPANDER, EExpanderClass))
-/* ESTUFF #define E_EXPANDER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), E_TYPE_EXPANDER, EExpanderPrivate)) */
-
-typedef struct _EExpander EExpander;
-typedef struct _EExpanderClass EExpanderClass;
-
-struct _EExpander
-{
- GtkBin bin;
-};
-
-struct _EExpanderClass
-{
- GtkBinClass parent_class;
-
- void (* activate) (EExpander *expander);
-};
-
-GType e_expander_get_type (void);
-
-GtkWidget *e_expander_new (const gchar *label);
-GtkWidget *e_expander_new_with_mnemonic (const gchar *label);
-
-void e_expander_set_expanded (EExpander *expander,
- gboolean expanded);
-gboolean e_expander_get_expanded (EExpander *expander);
-
-/* Spacing between the expander/label and the child */
-void e_expander_set_spacing (EExpander *expander,
- gint spacing);
-gint e_expander_get_spacing (EExpander *expander);
-
-void e_expander_set_label (EExpander *expander,
- const gchar *label);
-G_CONST_RETURN gchar *e_expander_get_label (EExpander *expander);
-
-void e_expander_set_use_underline (EExpander *expander,
- gboolean use_underline);
-gboolean e_expander_get_use_underline (EExpander *expander);
-
-void e_expander_set_label_widget (EExpander *expander,
- GtkWidget *label_widget);
-GtkWidget *e_expander_get_label_widget (EExpander *expander);
-
-G_END_DECLS
-
-#endif /* _E_EXPANDER_H_ */