diff options
author | Matthew Barnes <mbarnes@src.gnome.org> | 2009-04-01 05:48:38 +0800 |
---|---|---|
committer | Matthew Barnes <mbarnes@src.gnome.org> | 2009-04-01 05:48:38 +0800 |
commit | 0485fb58c5beeb04f0b3d833e6b73a2d2ec1acc7 (patch) | |
tree | 90df407868f6e2636e064af23f3a8560b143ddf5 /widgets/misc | |
parent | 04cc4a2cb1bf87417f82d1094ddde611019c0ab8 (diff) | |
download | gsoc2013-evolution-0485fb58c5beeb04f0b3d833e6b73a2d2ec1acc7.tar.gz gsoc2013-evolution-0485fb58c5beeb04f0b3d833e6b73a2d2ec1acc7.tar.zst gsoc2013-evolution-0485fb58c5beeb04f0b3d833e6b73a2d2ec1acc7.zip |
Extend EAttachmentView by subclassing EAttachmentHandler.
So far it only supports extending the attachment pop-up menu, but I
also plan to support extending drag and drop types. Might even end
up replacing EMFormatHook.
Two subclasses created so far:
EAttachmentHandlerImage handles images (built-in)
EAttachmentHandlerMail handles emails (defined in mail module)
svn path=/branches/kill-bonobo/; revision=37487
Diffstat (limited to 'widgets/misc')
-rw-r--r-- | widgets/misc/Makefile.am | 4 | ||||
-rw-r--r-- | widgets/misc/e-attachment-bar.c | 1796 | ||||
-rw-r--r-- | widgets/misc/e-attachment-bar.h | 141 | ||||
-rw-r--r-- | widgets/misc/e-attachment-handler-image.c | 285 | ||||
-rw-r--r-- | widgets/misc/e-attachment-handler-image.h | 65 | ||||
-rw-r--r-- | widgets/misc/e-attachment-handler.c | 157 | ||||
-rw-r--r-- | widgets/misc/e-attachment-handler.h | 67 | ||||
-rw-r--r-- | widgets/misc/e-attachment-icon-view.c | 5 | ||||
-rw-r--r-- | widgets/misc/e-attachment-store.c | 5 | ||||
-rw-r--r-- | widgets/misc/e-attachment-tree-view.c | 5 | ||||
-rw-r--r-- | widgets/misc/e-attachment-view.c | 279 | ||||
-rw-r--r-- | widgets/misc/e-attachment-view.h | 10 | ||||
-rw-r--r-- | widgets/misc/e-attachment.c | 90 | ||||
-rw-r--r-- | widgets/misc/e-attachment.h | 3 |
14 files changed, 796 insertions, 2116 deletions
diff --git a/widgets/misc/Makefile.am b/widgets/misc/Makefile.am index f6fc7ed10a..ad2f445eea 100644 --- a/widgets/misc/Makefile.am +++ b/widgets/misc/Makefile.am @@ -41,6 +41,8 @@ widgetsinclude_HEADERS = \ e-alert-activity.h \ e-attachment.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 \ @@ -103,6 +105,8 @@ libemiscwidgets_la_SOURCES = \ e-alert-activity.c \ e-attachment.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 \ diff --git a/widgets/misc/e-attachment-bar.c b/widgets/misc/e-attachment-bar.c deleted file mode 100644 index aebc6bb423..0000000000 --- a/widgets/misc/e-attachment-bar.c +++ /dev/null @@ -1,1796 +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 "e-mime-part-utils.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-binding.h" -#include "e-util/e-error.h" -#include "e-util/e-gui-utils.h" -#include "e-util/e-icon-factory.h" -#include "e-util/e-mktemp.h" -#include "e-util/e-util.h" -#include "e-util/gconf-bridge.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 - -#define E_ATTACHMENT_BAR_GET_PRIVATE(obj) \ - (G_TYPE_INSTANCE_GET_PRIVATE \ - ((obj), E_TYPE_ATTACHMENT_BAR, EAttachmentBarPrivate)) - -struct _EAttachmentBarPrivate { - gboolean batch_unref; - GPtrArray *attachments; - char *path; - - GtkUIManager *ui_manager; - GtkActionGroup *standard_actions; - GtkActionGroup *editable_actions; - GtkActionGroup *open_actions; - guint merge_id; - - guint editable : 1; -}; - -enum { - PROP_0, - PROP_EDITABLE, - PROP_UI_MANAGER -}; - -enum { - CHANGED, - UPDATE_ACTIONS, - LAST_SIGNAL -}; - -static gpointer parent_class; -static guint signals[LAST_SIGNAL]; - -static const gchar *ui = -"<ui>" -" <popup name='attachment-popup'>" -" <menuitem action='save-as'/>" -" <menuitem action='set-background'/>" -" <menuitem action='remove'/>" -" <menuitem action='properties'/>" -" <placeholder name='custom-actions'/>" -" <separator/>" -" <menuitem action='add'/>" -" <separator/>" -" <placeholder name='open-actions'/>" -" </popup>" -"</ui>"; - -static void -action_properties_cb (GtkAction *action, - EAttachmentBar *attachment_bar) -{ - GnomeIconList *icon_list; - GPtrArray *array; - GList *selection; - gpointer parent; - - array = attachment_bar->priv->attachments; - - icon_list = GNOME_ICON_LIST (attachment_bar); - selection = gnome_icon_list_get_selection (icon_list); - g_return_if_fail (selection != NULL); - - parent = gtk_widget_get_toplevel (GTK_WIDGET (icon_list)); - parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL; - - while (selection != NULL) { - gint index = GPOINTER_TO_INT (selection->data); - EAttachment *attachment; - - selection = g_list_next (selection); - - if (index >= array->len) - continue; - - attachment = array->pdata[index]; - e_attachment_edit (attachment, parent); - } -} - -static void -action_remove_cb (GtkAction *action, - EAttachmentBar *attachment_bar) -{ - GnomeIconList *icon_list; - GPtrArray *array; - GList *selection; - GList *trash = NULL; - - array = attachment_bar->priv->attachments; - - icon_list = GNOME_ICON_LIST (attachment_bar); - selection = gnome_icon_list_get_selection (icon_list); - g_return_if_fail (selection != NULL); - - while (selection != NULL) { - gint index = GPOINTER_TO_INT (selection->data); - - selection = g_list_next (selection); - - if (index >= array->len) - continue; - - /* We can't unref the attachment here because that may - * change the selection and invalidate the list we are - * iterating over. So move it to a trash list instead. */ - trash = g_list_prepend (trash, array->pdata[index]); - array->pdata[index] = NULL; - } - - /* Compress the attachment array. */ - while (g_ptr_array_remove (array, NULL)); - - /* Take out the trash. */ - g_list_foreach (trash, (GFunc) g_object_unref, NULL); - g_list_free (trash); - - e_attachment_bar_refresh (attachment_bar); - - g_signal_emit (attachment_bar, signals[CHANGED], 0); -} - -static void -action_save_as_cb (GtkAction *action, - EAttachmentBar *attachment_bar) -{ -} - -static void -action_set_background_cb (GtkAction *action, - EAttachmentBar *attachment_bar) -{ - GnomeIconList *icon_list; - CamelContentType *content_type; - CamelMimePart *mime_part; - EAttachment *attachment; - GPtrArray *array; - GList *selection; - gchar *basename; - gchar *filename; - gchar *dirname; - GFile *file; - gint index; - GError *error = NULL; - - icon_list = GNOME_ICON_LIST (attachment_bar); - selection = gnome_icon_list_get_selection (icon_list); - g_return_if_fail (selection != NULL); - - array = attachment_bar->priv->attachments; - index = GPOINTER_TO_INT (selection->data); - attachment = E_ATTACHMENT (array->pdata[index]); - mime_part = e_attachment_get_mime_part (attachment); - g_return_if_fail (CAMEL_IS_MIME_PART (mime_part)); - - content_type = camel_mime_part_get_content_type (mime_part); - basename = g_strdup (camel_mime_part_get_filename (mime_part)); - - if (basename == NULL || basename == '\0') { - g_free (basename); - basename = g_strdup_printf ( - _("untitled_image.%s"), - content_type->subtype); - } - - dirname = g_build_filename ( - g_get_home_dir (), ".gnome2", "wallpapers", NULL); - - index = 0; - filename = g_build_filename (dirname, basename, NULL); - - while (g_file_test (filename, G_FILE_TEST_EXISTS)) { - gchar *temp; - gchar *ext; - - ext = strrchr (filename, '.'); - if (ext != NULL) - *ext++ = '\0'; - - if (ext == NULL) - temp = g_strdup_printf ( - "%s (%d)", basename, index++); - else - temp = g_strdup_printf ( - "%s (%d).%s", basename, index++, ext); - - g_free (basename); - g_free (filename); - basename = temp; - - filename = g_build_filename (dirname, basename, NULL); - } - - g_free (basename); - g_free (dirname); - - file = g_file_new_for_path (filename); - - if (e_mime_part_utils_save_to_file (mime_part, file, &error)) { - const gchar *background_filename; - const gchar *background_options; - - background_filename = - e_attachment_bar_get_background_filename ( - attachment_bar); - background_options = - e_attachment_bar_get_background_options ( - attachment_bar); - - if (g_strcmp0 (background_filename, filename) == 0) - e_attachment_bar_set_background_filename ( - attachment_bar, NULL); - - e_attachment_bar_set_background_filename ( - attachment_bar, filename); - - if (g_strcmp0 (background_options, "none") == 0) - e_attachment_bar_set_background_options ( - attachment_bar, "wallpaper"); - } - - g_object_unref (file); - g_free (filename); - - if (error != NULL) { - g_warning ("%s", error->message); - g_error_free (error); - } -} - -static void -attachment_bar_show_popup_menu (EAttachmentBar *attachment_bar, - GdkEventButton *event) -{ - GtkUIManager *ui_manager; - GtkWidget *menu; - - ui_manager = e_attachment_bar_get_ui_manager (attachment_bar); - menu = gtk_ui_manager_get_widget (ui_manager, "/attachment-popup"); - g_return_if_fail (GTK_IS_MENU (menu)); - - e_attachment_bar_update_actions (attachment_bar); - - if (event != NULL) - gtk_menu_popup ( - GTK_MENU (menu), NULL, NULL, NULL, NULL, - event->button, event->time); - else - gtk_menu_popup ( - GTK_MENU (menu), NULL, NULL, NULL, NULL, - 0, gtk_get_current_event_time ()); -} - -/* 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)) { - e_attachment_bar_refresh (bar); - g_signal_emit (bar, signals[CHANGED], 0); - } -} - -/* 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 - CamelMimePart *mime_part; - struct stat file_stat; - char *file_uri = NULL; - gboolean is_tmp = FALSE; - - if (!attachment || !attachment->is_available_local) - return NULL; - - mime_part = e_attachment_get_mime_part (attachment); - - if (attachment->store_uri && g_str_has_prefix (attachment->store_uri, "file://")) - file_uri = attachment->store_uri; - else if (mime_part != NULL) { - /* 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 (mime_part); - 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 (mime_part)); - - 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, - gint *new_width, - gint *new_height) -{ - int width, height, icon_width; - PangoFontMetrics *metrics; - PangoContext *context; - - context = gtk_widget_get_pango_context (GTK_WIDGET (bar)); - metrics = pango_context_get_metrics ( - context, GTK_WIDGET (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; -} - -void -e_attachment_bar_create_attachment_cache (EAttachment *attachment) -{ - CamelContentType *content_type; - CamelMimePart *mime_part; - - g_return_if_fail (E_IS_ATTACHMENT (attachment)); - - mime_part = e_attachment_get_mime_part (attachment); - if (mime_part == NULL) - return; - - content_type = camel_mime_part_get_content_type (mime_part); - - 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 (mime_part)); - 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) { - /* The loader owns the reference. */ - pixbuf = gdk_pixbuf_loader_get_pixbuf (loader); - - /* This returns a new GdkPixbuf. */ - pixbuf = scale_pixbuf (pixbuf); - e_attachment_set_thumbnail (attachment, pixbuf); - g_object_unref (pixbuf); - } else { - e_attachment_set_thumbnail (attachment, NULL); - g_warning ("GdkPixbufLoader Error"); - } - - /* Destroy everything */ - g_object_unref (loader); - camel_object_unref (mstream); - } -} - -static void -update_remote_file (EAttachment *attachment, EAttachmentBar *bar) -{ - GnomeIconList *icon_list; - GnomeIconTextItem *item; - const gchar *filename; - char *msg, *base; - - if (attachment->percentage == -1) { - e_attachment_bar_refresh (bar); - return; - } - - filename = e_attachment_get_filename (attachment); - base = g_path_get_basename (filename); - 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_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); -} - -/** - * 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) -{ - 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) -{ - 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) -{ - 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) -{ - 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++) { - CamelMimePart *mime_part; - - attachment = priv->attachments->pdata[i]; - mime_part = e_attachment_get_mime_part (attachment); - - if (attachment->is_available_local) - parts = g_slist_prepend (parts, mime_part); - } - - return parts; -} - -static char * -temp_save_part (EAttachment *attachment, gboolean readonly) -{ - CamelMimePart *mime_part; - const char *filename; - char *tmpdir, *path, *mfilename = NULL, *utf8_mfilename = NULL; - CamelStream *stream; - CamelDataWrapper *wrapper; - - if (!(tmpdir = e_mkdtemp ("evolution-tmp-XXXXXX"))) - return NULL; - - mime_part = e_attachment_get_mime_part (attachment); - - if (!(filename = camel_mime_part_get_filename (mime_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 (mime_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 -attachment_bar_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - switch (property_id) { - case PROP_EDITABLE: - e_attachment_bar_set_editable ( - E_ATTACHMENT_BAR (object), - g_value_get_boolean (value)); - return; - } - - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); -} - -static void -attachment_bar_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - switch (property_id) { - case PROP_EDITABLE: - g_value_set_boolean ( - value, - e_attachment_bar_get_editable ( - E_ATTACHMENT_BAR (object))); - return; - - case PROP_UI_MANAGER: - g_value_set_object ( - value, - e_attachment_bar_get_ui_manager ( - E_ATTACHMENT_BAR (object))); - return; - } - - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); -} - -static void -attachment_bar_dispose (GObject *object) -{ - EAttachmentBarPrivate *priv; - guint ii; - - priv = E_ATTACHMENT_BAR_GET_PRIVATE (object); - - priv->batch_unref = TRUE; - - for (ii = 0; ii < priv->attachments->len; ii++) { - EAttachment *attachment; - - attachment = priv->attachments->pdata[ii]; - g_object_weak_unref ( - G_OBJECT (attachment), (GWeakNotify) - attachment_destroy, object); - g_object_unref (attachment); - } - g_ptr_array_set_size (priv->attachments, 0); - - if (priv->ui_manager != NULL) { - g_object_unref (priv->ui_manager); - priv->ui_manager = NULL; - } - - if (priv->standard_actions != NULL) { - g_object_unref (priv->standard_actions); - priv->standard_actions = NULL; - } - - if (priv->editable_actions != NULL) { - g_object_unref (priv->editable_actions); - priv->editable_actions = NULL; - } - - if (priv->open_actions != NULL) { - g_object_unref (priv->open_actions); - priv->open_actions = NULL; - } - - /* Chain up to parent's dipose() method. */ - G_OBJECT_CLASS (parent_class)->dispose (object); -} - -static void -attachment_bar_finalize (GObject *object) -{ - EAttachmentBarPrivate *priv; - - priv = E_ATTACHMENT_BAR_GET_PRIVATE (object); - - g_ptr_array_free (priv->attachments, TRUE); - g_free (priv->path); - - /* Chain up to parent's finalize() method. */ - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -static void -attachment_bar_constructed (GObject *object) -{ - EAttachmentBarPrivate *priv; - GtkActionGroup *action_group; - - priv = E_ATTACHMENT_BAR_GET_PRIVATE (object); - action_group = priv->editable_actions; - - e_mutual_binding_new ( - G_OBJECT (object), "editable", - G_OBJECT (action_group), "visible"); -} - -static gboolean -attachment_bar_event (GtkWidget *widget, - GdkEvent *event) -{ - EAttachment *attachment; - gboolean ret = FALSE; - gpointer parent; - CamelURL *url; - char *path; - GSList *p; - - if (event->type != GDK_2BUTTON_PRESS) - return FALSE; - - parent = gtk_widget_get_toplevel (widget); - parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL; - - p = e_attachment_bar_get_selected (E_ATTACHMENT_BAR (widget)); - /* check if has body already, remote files can take longer to fetch */ - if (p && p->next == NULL && e_attachment_get_mime_part (p->data) != NULL) { - attachment = p->data; - - /* Check if the file is stored already */ - if (!attachment->store_uri) { - path = temp_save_part (attachment, 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); - } - - e_show_uri (parent, attachment->store_uri); - - ret = TRUE; - } - - g_slist_foreach (p, (GFunc) g_object_unref, NULL); - g_slist_free (p); - - return ret; -} - -static gboolean -attachment_bar_button_press_event (GtkWidget *widget, - GdkEventButton *event) -{ - GnomeIconList *icon_list; - GList *selected, *tmp; - int length, icon_number; - gboolean take_selected = FALSE; - - GtkTargetEntry drag_types[] = { - { "text/uri-list", 0, 0 }, - }; - - icon_list = GNOME_ICON_LIST (widget); - selected = gnome_icon_list_get_selection (icon_list); - length = g_list_length (selected); - - 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 ( - widget, GDK_BUTTON1_MASK, drag_types, - G_N_ELEMENTS (drag_types), GDK_ACTION_COPY); - else - gtk_drag_source_unset (widget); - goto exit; - } - - /* If not r-click dont progress any more.*/ - if (event->button != 3) - goto exit; - - /* 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); - } - } - - attachment_bar_show_popup_menu (E_ATTACHMENT_BAR (widget), event); - -exit: - /* Chain up to parent's button_press_event() method. */ - return GTK_WIDGET_CLASS (parent_class)-> - button_press_event (widget, event); -} - -static gboolean -attachment_bar_button_release_event (GtkWidget *widget, - GdkEventButton *event) -{ - GnomeIconList *icon_list; - GList *selected; - - GtkTargetEntry drag_types[] = { - { "text/uri-list", 0, 0 }, - }; - - if (event->button != 1) - goto exit; - - icon_list = GNOME_ICON_LIST (widget); - selected = gnome_icon_list_get_selection (icon_list); - - if (selected != NULL) - gtk_drag_source_set ( - widget, GDK_BUTTON1_MASK, drag_types, - G_N_ELEMENTS (drag_types), GDK_ACTION_COPY); - else - gtk_drag_source_unset (widget); - -exit: - /* Chain up to parent's button_release_event() method. */ - return GTK_WIDGET_CLASS (parent_class)-> - button_release_event (widget, event); -} - -static gboolean -attachment_bar_key_press_event (GtkWidget *widget, - GdkEventKey *event) -{ - EAttachmentBar *attachment_bar; - gboolean editable; - - attachment_bar = E_ATTACHMENT_BAR (widget); - editable = e_attachment_bar_get_editable (attachment_bar); - - if (editable && event->keyval == GDK_Delete) { - GtkAction *action; - - action = e_attachment_bar_get_action (attachment_bar, "remove"); - gtk_action_activate (action); - } - - /* Chain up to parent's key_press_event() method. */ - return GTK_WIDGET_CLASS (parent_class)-> - key_press_event (widget, event); -} - -static void -attachment_bar_drag_data_get (GtkWidget *widget, - GdkDragContext *drag, - GtkSelectionData *data, - guint info, - guint time) -{ - EAttachmentBarPrivate *priv; - EAttachment *attachment; - char *path, **uris; - int len, n, i = 0; - CamelURL *url; - GList *items; - - if (info) - return; - - priv = E_ATTACHMENT_BAR_GET_PRIVATE (widget); - items = gnome_icon_list_get_selection (GNOME_ICON_LIST (widget)); - 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, 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); -} - -static gboolean -attachment_bar_popup_menu (GtkWidget *widget) -{ - attachment_bar_show_popup_menu (E_ATTACHMENT_BAR (widget), NULL); - - return TRUE; -} - -static void -attachment_bar_update_actions (EAttachmentBar *attachment_bar) -{ - GnomeIconList *icon_list; - CamelMimePart *mime_part; - GtkUIManager *ui_manager; - GtkActionGroup *action_group; - GtkAction *action; - GList *selection; - guint n_selected; - gboolean is_image; - gpointer parent; - guint merge_id; - - icon_list = GNOME_ICON_LIST (attachment_bar); - selection = gnome_icon_list_get_selection (icon_list); - n_selected = g_list_length (selection); - - parent = gtk_widget_get_toplevel (GTK_WIDGET (attachment_bar)); - parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL; - - is_image = FALSE; - mime_part = NULL; - - if (n_selected == 1) { - GPtrArray *array; - EAttachment *attachment; - gint index; - - array = attachment_bar->priv->attachments; - index = GPOINTER_TO_INT (selection->data); - attachment = E_ATTACHMENT (array->pdata[index]); - mime_part = e_attachment_get_mime_part (attachment); - is_image = e_attachment_is_image (attachment); - } - - action = e_attachment_bar_get_action (attachment_bar, "properties"); - gtk_action_set_visible (action, n_selected == 1); - - action = e_attachment_bar_get_action (attachment_bar, "remove"); - gtk_action_set_visible (action, n_selected > 0); - - action = e_attachment_bar_get_action (attachment_bar, "save-as"); - gtk_action_set_visible (action, n_selected > 0); - - action = e_attachment_bar_get_action (attachment_bar, "set-background"); - gtk_action_set_visible (action, is_image); - - /* Clear out the "open" action group. */ - merge_id = attachment_bar->priv->merge_id; - action_group = attachment_bar->priv->open_actions; - ui_manager = e_attachment_bar_get_ui_manager (attachment_bar); - gtk_ui_manager_remove_ui (ui_manager, merge_id); - e_action_group_remove_all_actions (action_group); - - if (mime_part == NULL) - return; - - e_mime_part_utils_add_open_actions ( - mime_part, ui_manager, action_group, - "/attachment-popup/open-actions", parent, merge_id); -} - -static void -attachment_bar_class_init (EAttachmentBarClass *class) -{ - GObjectClass *object_class; - GtkWidgetClass *widget_class; - - parent_class = g_type_class_peek_parent (class); - g_type_class_add_private (class, sizeof (EAttachmentBarPrivate)); - - object_class = G_OBJECT_CLASS (class); - object_class->set_property = attachment_bar_set_property; - object_class->get_property = attachment_bar_get_property; - object_class->dispose = attachment_bar_dispose; - object_class->finalize = attachment_bar_finalize; - object_class->constructed = attachment_bar_constructed; - - widget_class = GTK_WIDGET_CLASS (class); - widget_class->event = attachment_bar_event; - widget_class->button_press_event = attachment_bar_button_press_event; - widget_class->button_release_event = attachment_bar_button_release_event; - widget_class->key_press_event = attachment_bar_key_press_event; - widget_class->drag_data_get = attachment_bar_drag_data_get; - widget_class->popup_menu = attachment_bar_popup_menu; - - class->update_actions = attachment_bar_update_actions; - - g_object_class_install_property ( - object_class, - PROP_EDITABLE, - g_param_spec_boolean ( - "editable", - "Editable", - NULL, - TRUE, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT)); - - g_object_class_install_property ( - object_class, - PROP_UI_MANAGER, - g_param_spec_object ( - "ui-manager", - "UI Manager", - NULL, - GTK_TYPE_UI_MANAGER, - G_PARAM_READABLE)); - - signals[CHANGED] = g_signal_new ( - "changed", - G_OBJECT_CLASS_TYPE (class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EAttachmentBarClass, changed), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - signals[UPDATE_ACTIONS] = g_signal_new ( - "update-actions", - G_OBJECT_CLASS_TYPE (class), - G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (EAttachmentBarClass, update_actions), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); -} - -static void -attachment_bar_init (EAttachmentBar *bar) -{ - GnomeIconList *icon_list; - gint icon_width, window_height; - GError *error = NULL; - - bar->priv = E_ATTACHMENT_BAR_GET_PRIVATE (bar); - bar->priv->attachments = g_ptr_array_new (); - - GTK_WIDGET_SET_FLAGS (bar, GTK_CAN_FOCUS); - - icon_list = GNOME_ICON_LIST (bar); - - calculate_height_width (bar, &icon_width, &window_height); - gnome_icon_list_construct (icon_list, icon_width, NULL, 0); - - gtk_widget_set_size_request ( - GTK_WIDGET (bar), icon_width * 4, window_height); - - atk_object_set_name ( - gtk_widget_get_accessible (GTK_WIDGET (bar)), - _("Attachment Bar")); - - 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); -} - -GType -e_attachment_bar_get_type (void) -{ - static GType type = 0; - - if (G_UNLIKELY (type == 0)) { - static const GTypeInfo type_info = { - sizeof (EAttachmentBarClass), - (GBaseInitFunc) NULL, - (GBaseFinalizeFunc) NULL, - (GClassInitFunc) attachment_bar_class_init, - (GClassFinalizeFunc) NULL, - NULL, /* class_data */ - sizeof (EAttachmentBar), - 0, /* n_preallocs */ - (GInstanceInitFunc) attachment_bar_init, - NULL /* value_table */ - }; - - type = g_type_register_static ( - GNOME_TYPE_ICON_LIST, "EAttachmentBar", &type_info, 0); - } - - return type; -} - -GtkWidget * -e_attachment_bar_new (void) -{ - return g_object_new (E_TYPE_ATTACHMENT_BAR, NULL); -} - -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; - CamelMimePart *mime_part; - - mime_part = e_attachment_get_mime_part (attachment); - if (mime_part == NULL) - return; - - content_type = camel_mime_part_get_content_type (mime_part); - content = camel_medium_get_content_object (CAMEL_MEDIUM (mime_part)); - - 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 (mime_part, 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 (mime_part, type); - g_free (type); - g_free (buf); - } - - camel_object_unref (bestenc); - } else if (!CAMEL_IS_MIME_MESSAGE (content)) { - camel_mime_part_set_encoding (mime_part, CAMEL_TRANSFER_ENCODING_BASE64); - } - } - - camel_multipart_add_part (multipart, mime_part); -} - -void -e_attachment_bar_to_multipart (EAttachmentBar *bar, - CamelMultipart *multipart, - const gchar *default_charset) -{ - 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 gchar *filename, - const gchar *disposition) -{ - EAttachment *attachment; - CamelException ex; - - g_return_if_fail (E_IS_ATTACHMENT_BAR (bar)); - g_return_if_fail (filename != NULL); - g_return_if_fail (disposition != NULL); - - camel_exception_init (&ex); - - attachment = e_attachment_new (filename, disposition, &ex); - - if (attachment != NULL) - e_attachment_bar_add_attachment (bar, attachment); - else { - GtkWidget *toplevel; - - /* FIXME: Avoid using error from mailer */ - toplevel = gtk_widget_get_toplevel (GTK_WIDGET (bar)); - e_error_run ( - GTK_WINDOW (toplevel), "mail-composer:no-attach", - filename, camel_exception_get_description (&ex), NULL); - camel_exception_clear (&ex); - } -} - -void -e_attachment_bar_add_attachment (EAttachmentBar *bar, - EAttachment *attachment) -{ - g_return_if_fail (E_IS_ATTACHMENT_BAR (bar)); - g_return_if_fail (E_IS_ATTACHMENT (attachment)); - - g_ptr_array_add (bar->priv->attachments, attachment); - - g_object_weak_ref ( - G_OBJECT (attachment), (GWeakNotify) - attachment_destroy, bar); - - g_signal_connect_swapped ( - attachment, "changed", - G_CALLBACK (e_attachment_bar_refresh), bar); - - e_attachment_bar_refresh (bar); - - g_signal_emit (bar, signals[CHANGED], 0); -} - -void -e_attachment_bar_add_attachment_silent (EAttachmentBar *bar, - EAttachment *attachment) -{ - g_return_if_fail (E_IS_ATTACHMENT_BAR (bar)); - g_return_if_fail (E_IS_ATTACHMENT (attachment)); - - g_ptr_array_add (bar->priv->attachments, attachment); - - g_object_weak_ref ( - G_OBJECT (attachment), (GWeakNotify) - attachment_destroy, bar); - - g_signal_connect_swapped ( - attachment, "changed", - G_CALLBACK (e_attachment_bar_refresh), bar); - - g_signal_emit (bar, signals[CHANGED], 0); -} - -void -e_attachment_bar_refresh (EAttachmentBar *bar) -{ - EAttachmentBarPrivate *priv; - GnomeIconList *icon_list; - int bar_width, bar_height; - int i; - - g_return_if_fail (E_IS_ATTACHMENT_BAR (bar)); - - 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; - CamelMimePart *mime_part; - char *size_string, *label; - GdkPixbuf *pixbuf = NULL; - const char *desc; - - attachment = priv->attachments->pdata[i]; - mime_part = e_attachment_get_mime_part (attachment); - - if (!attachment->is_available_local || mime_part == NULL) { - 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 (mime_part); - /* Get the image out of the attachment - and create a thumbnail for it */ - pixbuf = e_attachment_get_thumbnail (attachment); - if (pixbuf != NULL) - 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 (mime_part)); - 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) { - /* The loader owns the reference. */ - pixbuf = gdk_pixbuf_loader_get_pixbuf (loader); - - /* This returns a new GdkPixbuf. */ - pixbuf = scale_pixbuf (pixbuf); - e_attachment_set_thumbnail (attachment, 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))) { - /* This returns a new GdkPixbuf. */ - pixbuf = scale_pixbuf (pixbuf); - e_attachment_set_thumbnail (attachment, pixbuf); - } - - desc = camel_mime_part_get_description (mime_part); - if (desc == NULL || *desc == '\0') - desc = e_attachment_get_filename (attachment); - if (desc == NULL || *desc == '\0') - desc = camel_mime_part_get_filename (mime_part); - - if (!desc) - desc = _("attachment"); - - if (attachment->size && (size_string = g_format_size_for_display (attachment->size))) { - label = g_strdup_printf ("%s (%s)", desc, size_string); - g_free (size_string); - } else - label = g_strdup (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) - e_attachment_set_thumbnail (attachment, 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); - } - } -} - -int -e_attachment_bar_get_download_count (EAttachmentBar *bar) -{ - 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 gchar *url, - const gchar *disposition) -{ - EAttachment *attachment; - CamelException ex; - GtkWidget *parent; - - g_return_if_fail (E_IS_ATTACHMENT_BAR (bar)); - - if (bar->priv->path == NULL) - bar->priv->path = e_mkdtemp ("attach-XXXXXX"); - - parent = gtk_widget_get_toplevel (GTK_WIDGET (bar)); - camel_exception_init (&ex); - - attachment = e_attachment_new_remote_file ( - GTK_WINDOW (parent), url, disposition, bar->priv->path, &ex); - - if (attachment != NULL) { - e_attachment_bar_add_attachment (bar, attachment); - g_signal_connect ( - attachment, "update", - G_CALLBACK (update_remote_file), bar); - } else { - e_error_run ( - GTK_WINDOW (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) -{ - EAttachment *attachment; - - /* XXX Is this function really worth keeping? */ - - g_return_if_fail (E_IS_ATTACHMENT_BAR (bar)); - g_return_if_fail (CAMEL_IS_MIME_PART (part)); - - attachment = e_attachment_new_from_mime_part (part); - e_attachment_bar_add_attachment (bar, attachment); -} - -void -e_attachment_bar_update_actions (EAttachmentBar *attachment_bar) -{ - g_return_if_fail (E_IS_ATTACHMENT_BAR (attachment_bar)); - - g_signal_emit (attachment_bar, signals[UPDATE_ACTIONS], 0); -} - -gboolean -e_attachment_bar_get_editable (EAttachmentBar *attachment_bar) -{ - g_return_val_if_fail (E_IS_ATTACHMENT_BAR (attachment_bar), FALSE); - - return attachment_bar->priv->editable; -} - -void -e_attachment_bar_set_editable (EAttachmentBar *attachment_bar, - gboolean editable) -{ - g_return_if_fail (E_IS_ATTACHMENT_BAR (attachment_bar)); - - attachment_bar->priv->editable = editable; - - g_object_notify (G_OBJECT (attachment_bar), "editable"); -} diff --git a/widgets/misc/e-attachment-bar.h b/widgets/misc/e-attachment-bar.h deleted file mode 100644 index a9b0655276..0000000000 --- a/widgets/misc/e-attachment-bar.h +++ /dev/null @@ -1,141 +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 <gtk/gtk.h> -#include <libgnomeui/gnome-icon-list.h> - -#include <camel/camel-multipart.h> -#include "e-attachment.h" - -#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(cls) \ - (G_TYPE_CHECK_CLASS_CAST \ - ((cls), 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(cls) \ - (G_TYPE_CHECK_CLASS_TYPE \ - ((cls), E_TYPE_ATTACHMENT_BAR)) -#define E_ATTACHMENT_BAR_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS \ - ((obj), E_TYPE_ATTACHMENT_BAR, EAttachmentBarClass)) - -G_BEGIN_DECLS - -typedef struct _EAttachmentBar EAttachmentBar; -typedef struct _EAttachmentBarClass EAttachmentBarClass; -typedef struct _EAttachmentBarPrivate EAttachmentBarPrivate; - -struct _EAttachmentBar { - GnomeIconList parent; - gboolean expand; - EAttachmentBarPrivate *priv; -}; - -struct _EAttachmentBarClass { - GnomeIconListClass parent_class; - - /* Signals */ - void (*changed) (EAttachmentBar *bar); - void (*update_actions) (EAttachmentBar *bar); -}; - -GType e_attachment_bar_get_type (void); -GtkWidget * e_attachment_bar_new (void); -void e_attachment_bar_to_multipart (EAttachmentBar *bar, - CamelMultipart *multipart, - const gchar *default_charset); -guint e_attachment_bar_get_num_attachments - (EAttachmentBar *bar); -void e_attachment_bar_attach (EAttachmentBar *bar, - const gchar *filename, - const gchar *disposition); -void e_attachment_bar_attach_mime_part - (EAttachmentBar *bar, - CamelMimePart *part); -gint e_attachment_bar_get_download_count - (EAttachmentBar *bar); -void e_attachment_bar_attach_remote_file - (EAttachmentBar *bar, - const gchar *url, - const gchar *disposition); -GSList * e_attachment_bar_get_attachment (EAttachmentBar *bar, - gint id); -void e_attachment_bar_add_attachment (EAttachmentBar *bar, - EAttachment *attachment); -GSList * e_attachment_bar_get_parts (EAttachmentBar *bar); -GSList * e_attachment_bar_get_selected (EAttachmentBar *bar); -void e_attachment_bar_set_width (EAttachmentBar *bar, - gint bar_width); -GSList * e_attachment_bar_get_all_attachments - (EAttachmentBar *bar); -void e_attachment_bar_create_attachment_cache - (EAttachment *attachment); -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); -gint e_attachment_bar_file_chooser_dialog_run - (EAttachmentBar *attachment_bar, - GtkWidget *dialog); -void e_attachment_bar_update_actions (EAttachmentBar *attachment_bar); -const gchar * e_attachment_bar_get_background_filename - (EAttachmentBar *attachment_bar); -void e_attachment_bar_set_background_filename - (EAttachmentBar *attachment_bar, - const gchar *background_filename); -const gchar * e_attachment_bar_get_background_options - (EAttachmentBar *attachment_bar); -void e_attachment_bar_set_background_options - (EAttachmentBar *attachment_bar, - const gchar *background_options); -const gchar * e_attachment_bar_get_current_folder - (EAttachmentBar *attachment_bar); -void e_attachment_bar_set_current_folder - (EAttachmentBar *attachment_bar, - const gchar *current_folder); -gboolean e_attachment_bar_get_editable (EAttachmentBar *attachment_bar); -void e_attachment_bar_set_editable (EAttachmentBar *attachment_bar, - gboolean editable); -GtkUIManager * e_attachment_bar_get_ui_manager (EAttachmentBar *attachment_bar); -GtkAction * e_attachment_bar_get_action (EAttachmentBar *attachment_bar, - const gchar *action_name); -GtkActionGroup *e_attachment_bar_get_action_group - (EAttachmentBar *attachment_bar, - const gchar *group_name); - -G_END_DECLS - -#endif /* E_ATTACHMENT_BAR_H */ diff --git a/widgets/misc/e-attachment-handler-image.c b/widgets/misc/e-attachment-handler-image.c new file mode 100644 index 0000000000..02357facc9 --- /dev/null +++ b/widgets/misc/e-attachment-handler-image.c @@ -0,0 +1,285 @@ +/* + * e-attachment-handler-image.c + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include "e-attachment-handler-image.h" + +#include <config.h> +#include <glib/gi18n.h> +#include <gconf/gconf-client.h> + +#define E_ATTACHMENT_HANDLER_IMAGE_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_ATTACHMENT_HANDLER_IMAGE, EAttachmentHandlerImagePrivate)) + +struct _EAttachmentHandlerImagePrivate { + gint placeholder; +}; + +static gpointer parent_class; + +static const gchar *ui = +"<ui>" +" <popup name='context'>" +" <placeholder name='custom-actions'>" +" <menuitem action='image-set-as-background'/>" +" </placeholder>" +" </popup>" +"</ui>"; + +static void +action_image_set_as_background_saved_cb (EAttachment *attachment, + GAsyncResult *result, + EAttachmentHandler *handler) +{ + EAttachmentView *view; + GConfClient *client; + GtkWidget *dialog; + GFile *file; + const gchar *key; + gpointer parent; + gchar *value; + GError *error = NULL; + + client = gconf_client_get_default (); + view = e_attachment_handler_get_view (handler); + + file = e_attachment_save_finish (attachment, result, &error); + + if (error != NULL) + goto error; + + value = g_file_get_path (file); + g_object_unref (file); + + key = "/desktop/gnome/background/picture_filename"; + gconf_client_set_string (client, key, value, &error); + g_free (value); + + if (error != NULL) + goto error; + + /* Ignore errors for this part. */ + key = "/desktop/gnome/background/picture_options"; + value = gconf_client_get_string (client, key, NULL); + if (g_strcmp0 (value, "none") == 0) + gconf_client_set_string (client, key, "wallpaper", NULL); + g_free (value); + + goto exit; + +error: + parent = gtk_widget_get_toplevel (GTK_WIDGET (view)); + parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL; + + dialog = gtk_message_dialog_new_with_markup ( + parent, GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, + "<big><b>%s</b></big>", + _("Could not set as background")); + + 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); + +exit: + g_object_unref (client); + g_object_unref (handler); +} + +static void +action_image_set_as_background_cb (GtkAction *action, + EAttachmentHandler *handler) +{ + EAttachmentView *view; + EAttachment *attachment; + GFile *destination; + GList *selected; + gchar *path; + + view = e_attachment_handler_get_view (handler); + selected = e_attachment_view_get_selected_attachments (view); + g_return_if_fail (g_list_length (selected) == 1); + attachment = E_ATTACHMENT (selected->data); + + /* Save the image under ~/.gnome2/wallpapers/. */ + path = g_build_filename ( + g_get_home_dir (), ".gnome2", "wallpapers", NULL); + destination = g_file_new_for_path (path); + g_mkdir_with_parents (path, 0755); + g_free (path); + + e_attachment_save_async ( + attachment, destination, (GAsyncReadyCallback) + action_image_set_as_background_saved_cb, + g_object_ref (handler)); + + g_object_unref (destination); + + g_list_foreach (selected, (GFunc) g_object_unref, NULL); + g_list_free (selected); +} + +static GtkActionEntry standard_entries[] = { + + { "image-set-as-background", + NULL, + N_("Set as _Background"), + NULL, + NULL, /* XXX Add a tooltip! */ + G_CALLBACK (action_image_set_as_background_cb) } +}; + +static void +attachment_handler_image_update_actions_cb (EAttachmentView *view, + EAttachmentHandler *handler) +{ + EAttachmentHandlerImagePrivate *priv; + EAttachment *attachment; + GFileInfo *file_info; + GtkActionGroup *action_group; + const gchar *content_type; + gchar *mime_type; + GList *selected; + gboolean visible = FALSE; + + priv = E_ATTACHMENT_HANDLER_IMAGE_GET_PRIVATE (handler); + + selected = e_attachment_view_get_selected_attachments (view); + + if (g_list_length (selected) != 1) + goto exit; + + attachment = E_ATTACHMENT (selected->data); + file_info = e_attachment_get_file_info (attachment); + + if (file_info == NULL) + goto exit; + + if (e_attachment_get_loading (attachment)) + goto exit; + + if (e_attachment_get_saving (attachment)) + goto exit; + + content_type = g_file_info_get_content_type (file_info); + + mime_type = g_content_type_get_mime_type (content_type); + visible = (g_ascii_strncasecmp (mime_type, "image/", 6) == 0); + g_free (mime_type); + +exit: + action_group = e_attachment_view_get_action_group (view, "image"); + gtk_action_group_set_visible (action_group, visible); + + g_list_foreach (selected, (GFunc) g_object_unref, NULL); + g_list_free (selected); +} + +static void +attachment_handler_image_constructed (GObject *object) +{ + EAttachmentHandlerImagePrivate *priv; + EAttachmentHandler *handler; + EAttachmentView *view; + GtkActionGroup *action_group; + GtkUIManager *ui_manager; + const gchar *domain = GETTEXT_PACKAGE; + GError *error = NULL; + + handler = E_ATTACHMENT_HANDLER (object); + priv = E_ATTACHMENT_HANDLER_IMAGE_GET_PRIVATE (object); + + /* Chain up to parent's constructed() method. */ + G_OBJECT_CLASS (parent_class)->constructed (object); + + view = e_attachment_handler_get_view (handler); + ui_manager = e_attachment_view_get_ui_manager (view); + + action_group = gtk_action_group_new ("image"); + gtk_action_group_set_translation_domain (action_group, domain); + gtk_action_group_add_actions ( + action_group, standard_entries, + G_N_ELEMENTS (standard_entries), object); + gtk_ui_manager_insert_action_group (ui_manager, action_group, 0); + g_object_unref (action_group); + + gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, &error); + + if (error != NULL) { + g_warning ("%s", error->message); + g_error_free (error); + } + + g_signal_connect ( + view, "update-actions", + G_CALLBACK (attachment_handler_image_update_actions_cb), + object); +} + +static void +attachment_handler_image_class_init (EAttachmentHandlerImageClass *class) +{ + GObjectClass *object_class; + + parent_class = g_type_class_peek_parent (class); + g_type_class_add_private (class, sizeof (EAttachmentHandlerImagePrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->constructed = attachment_handler_image_constructed; +} + +static void +attachment_handler_image_init (EAttachmentHandlerImage *handler) +{ + handler->priv = E_ATTACHMENT_HANDLER_IMAGE_GET_PRIVATE (handler); +} + +GType +e_attachment_handler_image_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) { + static const GTypeInfo type_info = { + sizeof (EAttachmentHandlerImageClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) attachment_handler_image_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (EAttachmentHandlerImage), + 0, /* n_preallocs */ + (GInstanceInitFunc) attachment_handler_image_init, + NULL /* value_table */ + }; + + type = g_type_register_static ( + E_TYPE_ATTACHMENT_HANDLER, + "EAttachmentHandlerImage", + &type_info, 0); + } + + return type; +} diff --git a/widgets/misc/e-attachment-handler-image.h b/widgets/misc/e-attachment-handler-image.h new file mode 100644 index 0000000000..53b076c61f --- /dev/null +++ b/widgets/misc/e-attachment-handler-image.h @@ -0,0 +1,65 @@ +/* + * e-attachment-handler-image.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 + * 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/> + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef E_ATTACHMENT_HANDLER_IMAGE_H +#define E_ATTACHMENT_HANDLER_IMAGE_H + +#include <widgets/misc/e-attachment-handler.h> + +/* Standard GObject macros */ +#define E_TYPE_ATTACHMENT_HANDLER_IMAGE \ + (e_attachment_handler_image_get_type ()) +#define E_ATTACHMENT_HANDLER_IMAGE(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_ATTACHMENT_HANDLER_IMAGE, EAttachmentHandlerImage)) +#define E_ATTACHMENT_HANDLER_IMAGE_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_ATTACHMENT_HANDLER_IMAGE, EAttachmentHandlerImageClass)) +#define E_IS_ATTACHMENT_HANDLER_IMAGE(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_ATTACHMENT_HANDLER_IMAGE)) +#define E_IS_ATTACHMENT_HANDLER_IMAGE_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_ATTACHMENT_HANDLER_IMAGE)) +#define E_ATTACHMENT_HANDLER_IMAGE_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_ATTACHMENT_HANDLER_IMAGE, EAttachmentHandlerImageClass)) + +G_BEGIN_DECLS + +typedef struct _EAttachmentHandlerImage EAttachmentHandlerImage; +typedef struct _EAttachmentHandlerImageClass EAttachmentHandlerImageClass; +typedef struct _EAttachmentHandlerImagePrivate EAttachmentHandlerImagePrivate; + +struct _EAttachmentHandlerImage { + EAttachmentHandler parent; + EAttachmentHandlerImagePrivate *priv; +}; + +struct _EAttachmentHandlerImageClass { + EAttachmentHandlerClass parent_class; +}; + +GType e_attachment_handler_image_get_type (void); + +G_END_DECLS + +#endif /* E_ATTACHMENT_HANDLER_IMAGE_H */ diff --git a/widgets/misc/e-attachment-handler.c b/widgets/misc/e-attachment-handler.c new file mode 100644 index 0000000000..dce139f9c3 --- /dev/null +++ b/widgets/misc/e-attachment-handler.c @@ -0,0 +1,157 @@ +/* + * e-attachment-handler.c + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include "e-attachment-handler.h" + +#define E_ATTACHMENT_HANDLER_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_ATTACHMENT_HANDLER, EAttachmentHandlerPrivate)) + +struct _EAttachmentHandlerPrivate { + gpointer view; /* weak pointer */ +}; + +enum { + PROP_0, + PROP_VIEW +}; + +static gpointer parent_class; + +static void +attachment_handler_set_view (EAttachmentHandler *handler, + EAttachmentView *view) +{ + g_return_if_fail (handler->priv->view == NULL); + + handler->priv->view = view; + + g_object_add_weak_pointer ( + G_OBJECT (view), &handler->priv->view); +} + +static void +attachment_handler_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_VIEW: + attachment_handler_set_view ( + E_ATTACHMENT_HANDLER (object), + g_value_get_object (value)); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +attachment_handler_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_VIEW: + g_value_set_object ( + value, e_attachment_handler_get_view ( + E_ATTACHMENT_HANDLER (object))); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +attachment_handler_constructed (GObject *object) +{ + /* This allows subclasses to chain up safely since GObject + * does not implement this method, and we might want to do + * something here in the future. */ +} + +static void +attachment_handler_class_init (EAttachmentHandlerClass *class) +{ + GObjectClass *object_class; + + parent_class = g_type_class_peek_parent (class); + g_type_class_add_private (class, sizeof (EAttachmentHandlerPrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->set_property = attachment_handler_set_property; + object_class->get_property = attachment_handler_get_property; + object_class->constructed = attachment_handler_constructed; + + g_object_class_install_property ( + object_class, + PROP_VIEW, + g_param_spec_object ( + "view", + "View", + NULL, + E_TYPE_ATTACHMENT_VIEW, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY)); +} + +static void +attachment_handler_init (EAttachmentHandler *handler) +{ + handler->priv = E_ATTACHMENT_HANDLER_GET_PRIVATE (handler); +} + +GType +e_attachment_handler_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) { + static const GTypeInfo type_info = { + sizeof (EAttachmentHandlerClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) attachment_handler_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (EAttachmentHandler), + 0, /* n_preallocs */ + (GInstanceInitFunc) attachment_handler_init, + NULL /* value_table */ + }; + + type = g_type_register_static ( + G_TYPE_OBJECT, "EAttachmentHandler", + &type_info, G_TYPE_FLAG_ABSTRACT); + } + + return type; +} + +EAttachmentView * +e_attachment_handler_get_view (EAttachmentHandler *handler) +{ + g_return_val_if_fail (E_IS_ATTACHMENT_HANDLER (handler), NULL); + + return E_ATTACHMENT_VIEW (handler->priv->view); +} diff --git a/widgets/misc/e-attachment-handler.h b/widgets/misc/e-attachment-handler.h new file mode 100644 index 0000000000..8de5743ba6 --- /dev/null +++ b/widgets/misc/e-attachment-handler.h @@ -0,0 +1,67 @@ +/* + * e-attachment-handler.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 + * 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/> + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef E_ATTACHMENT_HANDLER_H +#define E_ATTACHMENT_HANDLER_H + +#include <widgets/misc/e-attachment-view.h> + +/* Standard GObject macros */ +#define E_TYPE_ATTACHMENT_HANDLER \ + (e_attachment_handler_get_type ()) +#define E_ATTACHMENT_HANDLER(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_ATTACHMENT_HANDLER, EAttachmentHandler)) +#define E_ATTACHMENT_HANDLER_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_ATTACHMENT_HANDLER, EAttachmentHandlerClass)) +#define E_IS_ATTACHMENT_HANDLER(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_ATTACHMENT_HANDLER)) +#define E_IS_ATTACHMENT_HANDLER_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_ATTACHMENT_HANDLER)) +#define E_ATTACHMENT_HANDLER_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_ATTACHMENT_HANDLER, EAttachmentHandlerClass)) + +G_BEGIN_DECLS + +typedef struct _EAttachmentHandler EAttachmentHandler; +typedef struct _EAttachmentHandlerClass EAttachmentHandlerClass; +typedef struct _EAttachmentHandlerPrivate EAttachmentHandlerPrivate; + +struct _EAttachmentHandler { + GObject parent; + EAttachmentHandlerPrivate *priv; +}; + +struct _EAttachmentHandlerClass { + GObjectClass parent_class; +}; + +GType e_attachment_handler_get_type (void); +EAttachmentView * + e_attachment_handler_get_view (EAttachmentHandler *handler); + +G_END_DECLS + +#endif /* E_ATTACHMENT_HANDLER_H */ diff --git a/widgets/misc/e-attachment-icon-view.c b/widgets/misc/e-attachment-icon-view.c index 9588540f05..e8a7db8459 100644 --- a/widgets/misc/e-attachment-icon-view.c +++ b/widgets/misc/e-attachment-icon-view.c @@ -22,7 +22,6 @@ #include "e-attachment-icon-view.h" #include <glib/gi18n.h> -#include <gdk/gdkkeysyms.h> #include "e-attachment.h" #include "e-attachment-store.h" @@ -129,10 +128,8 @@ attachment_icon_view_key_press_event (GtkWidget *widget, { EAttachmentView *view = E_ATTACHMENT_VIEW (widget); - if (event->keyval == GDK_Delete) { - e_attachment_view_remove_selected (view, TRUE); + if (e_attachment_view_key_press_event (view, event)) return TRUE; - } /* Chain up to parent's key_press_event() method. */ return GTK_WIDGET_CLASS (parent_class)-> diff --git a/widgets/misc/e-attachment-store.c b/widgets/misc/e-attachment-store.c index 1eb429b41e..e565d68cae 100644 --- a/widgets/misc/e-attachment-store.c +++ b/widgets/misc/e-attachment-store.c @@ -790,10 +790,13 @@ attachment_store_save_list_finished_cb (EAttachment *attachment, GAsyncResult *result, SaveContext *save_context) { + GFile *file; GSimpleAsyncResult *simple; GError *error = NULL; - e_attachment_save_finish (attachment, result, &error); + file = e_attachment_save_finish (attachment, result, &error); + if (file != NULL) + g_object_unref (file); /* Remove the attachment from the list. */ save_context->attachment_list = g_list_remove ( diff --git a/widgets/misc/e-attachment-tree-view.c b/widgets/misc/e-attachment-tree-view.c index 5a613f4f17..336b3225df 100644 --- a/widgets/misc/e-attachment-tree-view.c +++ b/widgets/misc/e-attachment-tree-view.c @@ -22,7 +22,6 @@ #include "e-attachment-tree-view.h" #include <glib/gi18n.h> -#include <gdk/gdkkeysyms.h> #include "e-attachment.h" #include "e-attachment-store.h" @@ -147,10 +146,8 @@ attachment_tree_view_key_press_event (GtkWidget *widget, { EAttachmentView *view = E_ATTACHMENT_VIEW (widget); - if (event->keyval == GDK_Delete) { - e_attachment_view_remove_selected (view, TRUE); + if (e_attachment_view_key_press_event (view, event)) return TRUE; - } /* Chain up to parent's key_press_event() method. */ return GTK_WIDGET_CLASS (parent_class)-> diff --git a/widgets/misc/e-attachment-view.c b/widgets/misc/e-attachment-view.c index 6d6079df21..b2dc62b934 100644 --- a/widgets/misc/e-attachment-view.c +++ b/widgets/misc/e-attachment-view.c @@ -23,12 +23,18 @@ #include <config.h> #include <glib/gi18n.h> +#include <gdk/gdkkeysyms.h> #include <camel/camel-stream-mem.h> #include "e-util/e-binding.h" -#include "e-util/e-plugin-ui.h" #include "e-util/e-util.h" #include "e-attachment-dialog.h" +#include "e-attachment-handler-image.h" + +enum { + UPDATE_ACTIONS, + LAST_SIGNAL +}; enum { DND_TYPE_MESSAGE_RFC822, @@ -69,9 +75,9 @@ static const gchar *ui = " <popup name='context'>" " <menuitem action='cancel'/>" " <menuitem action='save-as'/>" -" <menuitem action='set-background'/>" " <menuitem action='remove'/>" " <menuitem action='properties'/>" +" <separator/>" " <placeholder name='custom-actions'/>" " <separator/>" " <menuitem action='add'/>" @@ -86,6 +92,8 @@ static const gchar *ui = " </popup>" "</ui>"; +static gulong signals[LAST_SIGNAL]; + static void action_add_cb (GtkAction *action, EAttachmentView *view) @@ -295,13 +303,6 @@ exit: g_list_free (selected); } -static void -action_set_background_cb (GtkAction *action, - EAttachmentView *view) -{ - /* FIXME */ -} - static GtkActionEntry standard_entries[] = { { "cancel", @@ -354,13 +355,6 @@ static GtkActionEntry standard_entries[] = { NULL, NULL, /* XXX Add a tooltip! */ G_CALLBACK (action_save_all_cb) }, - - { "set-background", - NULL, - N_("Set as _Background"), - NULL, - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_set_background_cb) } }; static GtkActionEntry editable_entries[] = { @@ -573,10 +567,114 @@ drop_x_uid_list (EAttachmentView *view, } static void +attachment_view_update_actions (EAttachmentView *view) +{ + EAttachmentViewPrivate *priv; + EAttachment *attachment; + GtkAction *action; + GList *list, *iter; + guint n_selected; + gboolean busy = FALSE; + + g_return_if_fail (E_IS_ATTACHMENT_VIEW (view)); + + priv = e_attachment_view_get_private (view); + list = e_attachment_view_get_selected_attachments (view); + n_selected = g_list_length (list); + + if (n_selected == 1) { + attachment = g_object_ref (list->data); + busy |= e_attachment_get_loading (attachment); + busy |= e_attachment_get_saving (attachment); + } else + attachment = NULL; + + g_list_foreach (list, (GFunc) g_object_unref, NULL); + g_list_free (list); + + action = e_attachment_view_get_action (view, "cancel"); + gtk_action_set_visible (action, busy); + + action = e_attachment_view_get_action (view, "properties"); + gtk_action_set_visible (action, !busy && n_selected == 1); + + action = e_attachment_view_get_action (view, "remove"); + gtk_action_set_visible (action, !busy && n_selected > 0); + + action = e_attachment_view_get_action (view, "save-as"); + gtk_action_set_visible (action, !busy && n_selected > 0); + + /* Clear out the "openwith" action group. */ + gtk_ui_manager_remove_ui (priv->ui_manager, priv->merge_id); + e_action_group_remove_all_actions (priv->openwith_actions); + + if (attachment == NULL || busy) + return; + + list = e_attachment_list_apps (attachment); + + for (iter = list; iter != NULL; iter = iter->next) { + GAppInfo *app_info = iter->data; + GtkAction *action; + const gchar *app_executable; + const gchar *app_name; + gchar *action_tooltip; + gchar *action_label; + gchar *action_name; + + if (!g_app_info_should_show (app_info)) + continue; + + app_executable = g_app_info_get_executable (app_info); + app_name = g_app_info_get_name (app_info); + + action_name = g_strdup_printf ("open-in-%s", app_executable); + action_label = g_strdup_printf (_("Open in %s..."), app_name); + + action_tooltip = g_strdup_printf ( + _("Open this attachment in %s"), app_name); + + action = gtk_action_new ( + action_name, action_label, action_tooltip, NULL); + + g_object_set_data_full ( + G_OBJECT (action), + "app-info", g_object_ref (app_info), + (GDestroyNotify) g_object_unref); + + g_object_set_data_full ( + G_OBJECT (action), + "attachment", g_object_ref (attachment), + (GDestroyNotify) g_object_unref); + + g_signal_connect ( + action, "activate", + G_CALLBACK (action_open_in_cb), view); + + gtk_action_group_add_action (priv->openwith_actions, action); + + gtk_ui_manager_add_ui ( + priv->ui_manager, priv->merge_id, + "/context/open-actions", action_name, + action_name, GTK_UI_MANAGER_AUTO, FALSE); + + g_free (action_name); + g_free (action_label); + g_free (action_tooltip); + } + + g_object_unref (attachment); + g_list_foreach (list, (GFunc) g_object_unref, NULL); + g_list_free (list); +} + +static void attachment_view_class_init (EAttachmentViewIface *iface) { gint ii; + iface->update_actions = attachment_view_update_actions; + g_object_interface_install_property ( iface, g_param_spec_boolean ( @@ -587,6 +685,15 @@ attachment_view_class_init (EAttachmentViewIface *iface) G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + signals[UPDATE_ACTIONS] = g_signal_new ( + "update-actions", + G_TYPE_FROM_INTERFACE (iface), + G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (EAttachmentViewIface, update_actions), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + for (ii = 0; ii < G_N_ELEMENTS (drag_info); ii++) { const gchar *target = drag_info[ii].target; drag_info[ii].atom = gdk_atom_intern (target, FALSE); @@ -616,6 +723,9 @@ e_attachment_view_get_type (void) G_TYPE_INTERFACE, "EAttachmentView", &type_info, 0); g_type_interface_add_prerequisite (type, GTK_TYPE_WIDGET); + + /* Register known handler types. */ + e_attachment_handler_image_get_type (); } return type; @@ -628,6 +738,8 @@ e_attachment_view_init (EAttachmentView *view) GtkUIManager *ui_manager; GtkActionGroup *action_group; const gchar *domain = GETTEXT_PACKAGE; + GType *children; + guint ii; GError *error = NULL; priv = e_attachment_view_get_private (view); @@ -671,7 +783,14 @@ e_attachment_view_init (EAttachmentView *view) G_OBJECT (view), "editable", G_OBJECT (priv->editable_actions), "visible"); - e_plugin_ui_register_manager (ui_manager, "attachment-view", view); + /* Instantiate attachment handlers. */ + children = g_type_children (E_TYPE_ATTACHMENT_HANDLER, NULL); + for (ii = 0; children[ii] != G_TYPE_INVALID; ii++) { + EAttachmentHandler *handler; + handler = g_object_new (children[ii], "view", view, NULL); + priv->handlers = g_list_prepend (priv->handlers, handler); + } + g_free (children); } void @@ -681,6 +800,10 @@ e_attachment_view_dispose (EAttachmentView *view) priv = e_attachment_view_get_private (view); + g_list_foreach (priv->handlers, (GFunc) g_object_unref, NULL); + g_list_free (priv->handlers); + priv->handlers = NULL; + if (priv->ui_manager != NULL) { g_object_unref (priv->ui_manager); priv->ui_manager = NULL; @@ -952,6 +1075,25 @@ e_attachment_view_button_release_event (EAttachmentView *view, return FALSE; } +gboolean +e_attachment_view_key_press_event (EAttachmentView *view, + GdkEventKey *event) +{ + gboolean editable; + + g_return_val_if_fail (E_IS_ATTACHMENT_VIEW (view), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + editable = e_attachment_view_get_editable (view); + + if (event->keyval == GDK_Delete && editable) { + e_attachment_view_remove_selected (view, TRUE); + return TRUE; + } + + return FALSE; +} + GtkTreePath * e_attachment_view_get_path_at_pos (EAttachmentView *view, gint x, @@ -1445,108 +1587,7 @@ e_attachment_view_show_popup_menu (EAttachmentView *view, void e_attachment_view_update_actions (EAttachmentView *view) { - EAttachmentViewPrivate *priv; - EAttachment *attachment; - GtkAction *action; - GList *list, *iter; - guint n_selected; - gboolean is_image; - gboolean busy = FALSE; - g_return_if_fail (E_IS_ATTACHMENT_VIEW (view)); - priv = e_attachment_view_get_private (view); - list = e_attachment_view_get_selected_attachments (view); - n_selected = g_list_length (list); - - if (n_selected == 1) { - attachment = g_object_ref (list->data); - is_image = e_attachment_is_image (attachment); - busy |= e_attachment_get_loading (attachment); - busy |= e_attachment_get_saving (attachment); - } else { - attachment = NULL; - is_image = FALSE; - } - - g_list_foreach (list, (GFunc) g_object_unref, NULL); - g_list_free (list); - - action = e_attachment_view_get_action (view, "cancel"); - gtk_action_set_visible (action, busy); - - action = e_attachment_view_get_action (view, "properties"); - gtk_action_set_visible (action, !busy && n_selected == 1); - - action = e_attachment_view_get_action (view, "remove"); - gtk_action_set_visible (action, !busy && n_selected > 0); - - action = e_attachment_view_get_action (view, "save-as"); - gtk_action_set_visible (action, !busy && n_selected > 0); - - action = e_attachment_view_get_action (view, "set-background"); - gtk_action_set_visible (action, !busy && is_image); - - /* Clear out the "openwith" action group. */ - gtk_ui_manager_remove_ui (priv->ui_manager, priv->merge_id); - e_action_group_remove_all_actions (priv->openwith_actions); - - if (attachment == NULL || busy) - return; - - list = e_attachment_list_apps (attachment); - - for (iter = list; iter != NULL; iter = iter->next) { - GAppInfo *app_info = iter->data; - GtkAction *action; - const gchar *app_executable; - const gchar *app_name; - gchar *action_tooltip; - gchar *action_label; - gchar *action_name; - - if (!g_app_info_should_show (app_info)) - continue; - - app_executable = g_app_info_get_executable (app_info); - app_name = g_app_info_get_name (app_info); - - action_name = g_strdup_printf ("open-in-%s", app_executable); - action_label = g_strdup_printf (_("Open in %s..."), app_name); - - action_tooltip = g_strdup_printf ( - _("Open this attachment in %s"), app_name); - - action = gtk_action_new ( - action_name, action_label, action_tooltip, NULL); - - g_object_set_data_full ( - G_OBJECT (action), - "app-info", g_object_ref (app_info), - (GDestroyNotify) g_object_unref); - - g_object_set_data_full ( - G_OBJECT (action), - "attachment", g_object_ref (attachment), - (GDestroyNotify) g_object_unref); - - g_signal_connect ( - action, "activate", - G_CALLBACK (action_open_in_cb), view); - - gtk_action_group_add_action (priv->openwith_actions, action); - - gtk_ui_manager_add_ui ( - priv->ui_manager, priv->merge_id, - "/context/open-actions", action_name, - action_name, GTK_UI_MANAGER_AUTO, FALSE); - - g_free (action_name); - g_free (action_label); - g_free (action_tooltip); - } - - g_object_unref (attachment); - g_list_foreach (list, (GFunc) g_object_unref, NULL); - g_list_free (list); + g_signal_emit (view, signals[UPDATE_ACTIONS], 0); } diff --git a/widgets/misc/e-attachment-view.h b/widgets/misc/e-attachment-view.h index d33ad951ac..16a7ac1967 100644 --- a/widgets/misc/e-attachment-view.h +++ b/widgets/misc/e-attachment-view.h @@ -85,10 +85,16 @@ struct _EAttachmentViewIface { GdkDragAction actions); void (*drag_source_unset) (EAttachmentView *view); void (*drag_dest_unset) (EAttachmentView *view); + + /* Signals */ + void (*update_actions) (EAttachmentView *view); }; struct _EAttachmentViewPrivate { + /* Attachment Handlers */ + GList *handlers; + /* Popup Menu Management */ GtkUIManager *ui_manager; GtkActionGroup *standard_actions; @@ -127,12 +133,16 @@ void e_attachment_view_remove_selected (EAttachmentView *view, gboolean select_next); +/* Event Support */ gboolean e_attachment_view_button_press_event (EAttachmentView *view, GdkEventButton *event); gboolean e_attachment_view_button_release_event (EAttachmentView *view, GdkEventButton *event); +gboolean e_attachment_view_key_press_event + (EAttachmentView *view, + GdkEventKey *event); /* Selection Management */ GtkTreePath * e_attachment_view_get_path_at_pos diff --git a/widgets/misc/e-attachment.c b/widgets/misc/e-attachment.c index 52a3d928f6..fb84261fa2 100644 --- a/widgets/misc/e-attachment.c +++ b/widgets/misc/e-attachment.c @@ -52,7 +52,7 @@ #define EMBLEM_SIGN_GOOD "stock_signature-ok" #define EMBLEM_SIGN_UNKNOWN "stock_signature" -/* Attributes needed by EAttachmentStore, et al. */ +/* Attributes needed for EAttachmentStore columns. */ #define ATTACHMENT_QUERY "standard::*,preview::*,thumbnail::*" struct _EAttachmentPrivate { @@ -1185,31 +1185,6 @@ e_attachment_get_thumbnail_path (EAttachment *attachment) } gboolean -e_attachment_is_image (EAttachment *attachment) -{ - GFileInfo *file_info; - const gchar *content_type; - gchar *mime_type; - gboolean is_image; - - 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_image = (g_ascii_strncasecmp (mime_type, "image/", 6) == 0); - g_free (mime_type); - - return is_image; -} - -gboolean e_attachment_is_rfc822 (EAttachment *attachment) { GFileInfo *file_info; @@ -1805,7 +1780,6 @@ struct _OpenContext { GSimpleAsyncResult *simple; GAppInfo *app_info; - GFile *file; }; static OpenContext * @@ -1836,9 +1810,6 @@ attachment_open_context_free (OpenContext *open_context) if (open_context->app_info != NULL) g_object_unref (open_context->app_info); - if (open_context->file != NULL) - g_object_unref (open_context->file); - g_slice_free (OpenContext, open_context); } @@ -1865,7 +1836,8 @@ attachment_open_check_for_error (OpenContext *open_context, } static void -attachment_open_file (OpenContext *open_context) +attachment_open_file (GFile *file, + OpenContext *open_context) { GdkAppLaunchContext *context; GSimpleAsyncResult *simple; @@ -1900,7 +1872,7 @@ attachment_open_file (OpenContext *open_context) goto exit; context = gdk_app_launch_context_new (); - file_list = g_list_prepend (NULL, open_context->file); + file_list = g_list_prepend (NULL, file); success = g_app_info_launch ( open_context->app_info, file_list, @@ -1926,19 +1898,22 @@ attachment_open_save_finished_cb (EAttachment *attachment, GAsyncResult *result, OpenContext *open_context) { + GFile *file; GError *error = NULL; - e_attachment_save_finish (attachment, result, &error); + file = e_attachment_save_finish (attachment, result, &error); if (attachment_open_check_for_error (open_context, error)) return; - attachment_open_file (open_context); + attachment_open_file (file, open_context); + g_object_unref (file); } static void attachment_open_save_temporary (OpenContext *open_context) { + GFile *file; gchar *path; gint fd; GError *error = NULL; @@ -1948,14 +1923,16 @@ attachment_open_save_temporary (OpenContext *open_context) if (attachment_open_check_for_error (open_context, error)) return; - close (fd); + file = g_file_new_for_path (path); - open_context->file = g_file_new_for_path (path); + close (fd); + g_free (path); e_attachment_save_async ( - open_context->attachment, open_context->file, - (GAsyncReadyCallback) attachment_open_save_finished_cb, - open_context); + open_context->attachment, file, (GAsyncReadyCallback) + attachment_open_save_finished_cb, open_context); + + g_object_unref (file); } void @@ -1985,8 +1962,7 @@ e_attachment_open_async (EAttachment *attachment, * the application directly. Otherwise we have to save the MIME * part to a temporary file and launch the application from that. */ if (file != NULL) { - open_context->file = g_object_ref (file); - attachment_open_file (open_context); + attachment_open_file (file, open_context); } else if (mime_part != NULL) attachment_open_save_temporary (open_context); @@ -2071,6 +2047,7 @@ struct _SaveContext { GSimpleAsyncResult *simple; GFile *directory; + GFile *destination; GInputStream *input_stream; GOutputStream *output_stream; goffset total_num_bytes; @@ -2115,6 +2092,9 @@ attachment_save_context_free (SaveContext *save_context) if (save_context->directory != NULL) g_object_unref (save_context->directory); + if (save_context->destination != NULL) + g_object_unref (save_context->destination); + if (save_context->input_stream != NULL) g_object_unref (save_context->input_stream); @@ -2259,12 +2239,18 @@ attachment_save_read_cb (GInputStream *input_stream, if (bytes_read == 0) { GSimpleAsyncResult *simple; + GFile *destination; /* Steal the result. */ simple = save_context->simple; save_context->simple = NULL; - g_simple_async_result_set_op_res_gboolean (simple, TRUE); + /* 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); @@ -2366,6 +2352,7 @@ attachment_save_create_cb (GFile *destination, if (attachment_save_check_for_error (save_context, error)) return; + save_context->destination = g_object_ref (destination); attachment_save_got_output_stream (save_context); } @@ -2384,6 +2371,7 @@ attachment_save_replace_cb (GFile *destination, if (attachment_save_check_for_error (save_context, error)) return; + save_context->destination = g_object_ref (destination); attachment_save_got_output_stream (save_context); } @@ -2490,26 +2478,28 @@ e_attachment_save_async (EAttachment *attachment, attachment_save_query_info_cb, save_context); } -gboolean +GFile * e_attachment_save_finish (EAttachment *attachment, GAsyncResult *result, GError **error) { GSimpleAsyncResult *simple; - gboolean success; + GFile *destination; g_return_val_if_fail ( g_simple_async_result_is_valid (result, G_OBJECT (attachment), e_attachment_save_async), FALSE); simple = G_SIMPLE_ASYNC_RESULT (result); - success = g_simple_async_result_get_op_res_gboolean (simple); + 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 success; + return destination; } void @@ -2517,8 +2507,9 @@ e_attachment_save_handle_error (EAttachment *attachment, GAsyncResult *result, GtkWindow *parent) { - GtkWidget *dialog; + GFile *file; GFileInfo *file_info; + GtkWidget *dialog; const gchar *display_name; const gchar *primary_text; GError *error = NULL; @@ -2527,8 +2518,9 @@ e_attachment_save_handle_error (EAttachment *attachment, g_return_if_fail (G_IS_ASYNC_RESULT (result)); g_return_if_fail (GTK_IS_WINDOW (parent)); - if (e_attachment_save_finish (attachment, result, &error)) - return; + file = e_attachment_save_finish (attachment, result, &error); + if (file != NULL) + g_object_unref (file); /* Ignore cancellations. */ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) diff --git a/widgets/misc/e-attachment.h b/widgets/misc/e-attachment.h index 8a13da2909..1184b32012 100644 --- a/widgets/misc/e-attachment.h +++ b/widgets/misc/e-attachment.h @@ -98,7 +98,6 @@ 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_image (EAttachment *attachment); gboolean e_attachment_is_rfc822 (EAttachment *attachment); GList * e_attachment_list_apps (EAttachment *attachment); @@ -120,7 +119,7 @@ void e_attachment_save_async (EAttachment *attachment, GFile *destination, GAsyncReadyCallback callback, gpointer user_data); -gboolean e_attachment_save_finish (EAttachment *attachment, +GFile * e_attachment_save_finish (EAttachment *attachment, GAsyncResult *result, GError **error); |