diff options
author | Matthew Barnes <mbarnes@src.gnome.org> | 2009-04-02 06:58:10 +0800 |
---|---|---|
committer | Matthew Barnes <mbarnes@src.gnome.org> | 2009-04-02 06:58:10 +0800 |
commit | 3a6dd7931ed7787b49a574ebe69eba5f46289fff (patch) | |
tree | f8bdde77fe6bf3fe9d8f4e68fbdb46df6a7abf56 | |
parent | 0485fb58c5beeb04f0b3d833e6b73a2d2ec1acc7 (diff) | |
download | gsoc2013-evolution-3a6dd7931ed7787b49a574ebe69eba5f46289fff.tar gsoc2013-evolution-3a6dd7931ed7787b49a574ebe69eba5f46289fff.tar.gz gsoc2013-evolution-3a6dd7931ed7787b49a574ebe69eba5f46289fff.tar.bz2 gsoc2013-evolution-3a6dd7931ed7787b49a574ebe69eba5f46289fff.tar.lz gsoc2013-evolution-3a6dd7931ed7787b49a574ebe69eba5f46289fff.tar.xz gsoc2013-evolution-3a6dd7931ed7787b49a574ebe69eba5f46289fff.tar.zst gsoc2013-evolution-3a6dd7931ed7787b49a574ebe69eba5f46289fff.zip |
Finish attachment drag and drop.
Expunge em-popup.c of dead code. Not much left.
Kill the save-attachments (experimental) plugin.
The attachment bar can already save all at once.
svn path=/branches/kill-bonobo/; revision=37488
23 files changed, 693 insertions, 2053 deletions
diff --git a/composer/e-msg-composer.c b/composer/e-msg-composer.c index f6e85b78c8..ad61b1b461 100644 --- a/composer/e-msg-composer.c +++ b/composer/e-msg-composer.c @@ -133,39 +133,6 @@ enum { LAST_SIGNAL }; -enum { - DND_TYPE_MESSAGE_RFC822, - DND_TYPE_X_UID_LIST, - DND_TYPE_TEXT_URI_LIST, - DND_TYPE_NETSCAPE_URL, - DND_TYPE_TEXT_VCARD, - DND_TYPE_TEXT_CALENDAR -}; - -static GtkTargetEntry drop_types[] = { - { "message/rfc822", 0, DND_TYPE_MESSAGE_RFC822 }, - { "x-uid-list", 0, DND_TYPE_X_UID_LIST }, - { "text/uri-list", 0, DND_TYPE_TEXT_URI_LIST }, - { "_NETSCAPE_URL", 0, DND_TYPE_NETSCAPE_URL }, - { "text/x-vcard", 0, DND_TYPE_TEXT_VCARD }, - { "text/calendar", 0, DND_TYPE_TEXT_CALENDAR } -}; - -static struct { - gchar *target; - GdkAtom atom; - guint32 actions; -} drag_info[] = { - { "message/rfc822", NULL, GDK_ACTION_COPY }, - { "x-uid-list", NULL, GDK_ACTION_ASK | - GDK_ACTION_MOVE | - GDK_ACTION_COPY }, - { "text/uri-list", NULL, GDK_ACTION_COPY }, - { "_NETSCAPE_URL", NULL, GDK_ACTION_COPY }, - { "text/x-vcard", NULL, GDK_ACTION_COPY }, - { "text/calendar", NULL, GDK_ACTION_COPY } -}; - static gpointer parent_class; static guint signals[LAST_SIGNAL]; @@ -1844,8 +1811,13 @@ msg_composer_drag_data_received (GtkWidget *widget, composer = E_MSG_COMPOSER (gtk_widget_get_toplevel (widget)); view = e_msg_composer_get_attachment_view (composer); - e_attachment_view_drag_data_received ( - view, context, x, y, selection, info, time); + /* Forward the data to the attachment view. Note that calling + * e_attachment_view_drag_data_received() will not work because + * that function only handles the case where all the other drag + * handlers have failed. */ + e_attachment_paned_drag_data_received ( + E_ATTACHMENT_PANED (view), + context, x, y, selection, info, time); } static void @@ -1900,7 +1872,6 @@ msg_composer_paste_clipboard (GtkhtmlEditor *editor) GtkWidget *widget; gchar *filename; gchar *uri; - gint fd; GError *error = NULL; composer = E_MSG_COMPOSER (editor); @@ -1924,14 +1895,13 @@ msg_composer_paste_clipboard (GtkhtmlEditor *editor) goto chainup; /* Reserve a temporary file. */ - fd = e_file_open_tmp (&filename, &error); - if (error != NULL) { - g_warning ("%s", error->message); + filename = e_mktemp (NULL); + if (filename == NULL) { + g_warning ("%s", g_strerror (errno)); g_object_unref (pixbuf); g_error_free (error); return; } - close (fd); /* Save the pixbuf as a temporary file in image/png format. */ if (!gdk_pixbuf_save (pixbuf, filename, "png", &error, NULL)) { @@ -2197,11 +2167,6 @@ msg_composer_class_init (EMsgComposerClass *class) GtkObjectClass *gtk_object_class; GtkWidgetClass *widget_class; GtkhtmlEditorClass *editor_class; - gint ii; - - for (ii = 0; ii < G_N_ELEMENTS (drag_info); ii++) - drag_info[ii].atom = - gdk_atom_intern (drag_info[ii].target, FALSE); parent_class = g_type_class_peek_parent (class); g_type_class_add_private (class, sizeof (EMsgComposerPrivate)); @@ -2265,10 +2230,14 @@ msg_composer_init (EMsgComposer *composer) EAttachmentView *view; EAttachmentStore *store; EComposerHeaderTable *table; + GdkDragAction drag_actions; + GtkTargetList *target_list; + GtkTargetEntry *targets; GtkUIManager *manager; GtkhtmlEditor *editor; GtkHTML *html; const gchar *id; + gint n_targets; composer->priv = E_MSG_COMPOSER_GET_PRIVATE (composer); @@ -2277,6 +2246,7 @@ msg_composer_init (EMsgComposer *composer) editor = GTKHTML_EDITOR (composer); html = gtkhtml_editor_get_html (editor); manager = gtkhtml_editor_get_ui_manager (editor); + view = e_msg_composer_get_attachment_view (composer); all_composers = g_slist_prepend (all_composers, composer); table = E_COMPOSER_HEADER_TABLE (composer->priv->header_table); @@ -2285,16 +2255,20 @@ msg_composer_init (EMsgComposer *composer) /* Drag-and-Drop Support */ -#if 0 /* KILL-BONOBO */ + target_list = e_attachment_view_get_target_list (view); + drag_actions = e_attachment_view_get_drag_actions (view); + + targets = gtk_target_table_new_from_list (target_list, &n_targets); + gtk_drag_dest_set ( GTK_WIDGET (composer), GTK_DEST_DEFAULT_ALL, - drop_types, G_N_ELEMENTS (drop_types), - GDK_ACTION_COPY | GDK_ACTION_ASK | GDK_ACTION_MOVE); + targets, n_targets, drag_actions); g_signal_connect ( html, "drag-data-received", G_CALLBACK (msg_composer_drag_data_received), NULL); -#endif + + gtk_target_table_free (targets, n_targets); /* Configure Headers */ @@ -2336,7 +2310,6 @@ msg_composer_init (EMsgComposer *composer) /* Attachments */ - view = e_msg_composer_get_attachment_view (composer); store = e_attachment_view_get_store (view); g_signal_connect_swapped ( diff --git a/configure.in b/configure.in index 05024a1422..0b0c11b50f 100644 --- a/configure.in +++ b/configure.in @@ -1785,12 +1785,12 @@ plugins_standard_always="bbdb subject-thread save-calendar copy-tool mail-to-tas plugins_standard="$plugins_standard_always" all_plugins_standard="$plugins_standard" -plugins_experimental_always="folder-unsubscribe mail-to-meeting save-attachments external-editor hula-account-setup" +plugins_experimental_always="folder-unsubscribe mail-to-meeting external-editor hula-account-setup" plugins_experimental="$plugins_experimental_always $IPOD_SYNC $TNEF_ATTACHMENTS $PYTHON_PLUGIN" all_plugins_experimental="$plugins_experimental_always ipod-sync tnef-attachments" dnl Temporary KILL-BONOBO hack -enable_plugins="attachment-reminder addressbook-file audio-inline bbdb bogo-junk-plugin caldav calendar-file calendar-http copy-tool default-source external-editor google-account-setup hula-account-setup imap-features mail-notification mail-to-meeting mark-all-read plugin-manager profiler sa-junk-plugin save-attachments save-calendar subject-thread tnef-attachments vcard-inline webdav-account-setup" +enable_plugins="attachment-reminder addressbook-file audio-inline bbdb bogo-junk-plugin caldav calendar-file calendar-http copy-tool default-source external-editor google-account-setup hula-account-setup imap-features mail-notification mail-to-meeting mark-all-read plugin-manager profiler sa-junk-plugin save-calendar subject-thread tnef-attachments vcard-inline webdav-account-setup" dnl PLUGINS NOT BUILDING YET dnl ------------------------ diff --git a/e-util/e-util.c b/e-util/e-util.c index 02c76c3d32..071f5e58b8 100644 --- a/e-util/e-util.c +++ b/e-util/e-util.c @@ -186,33 +186,6 @@ exit: } /** - * e_file_open_tmp: - * @name_used: location to store the actual named used, or %NULL - * @error: return location for a #GError, or %NULL - * - * Convenience function wraps g_file_open_tmp() but chooses a suitable - * filename template using both the package name and the user name. - * - * Returns: A file handle (as from open()) to the file opened for reading - * and writing. The file is opened in binary mode on platforms - * where there is a difference. The file handle should be closed - * with close(). In case of errors, -1 is returned and @error - * will be set. - **/ -gint -e_file_open_tmp (gchar **name_used, - GError **error) -{ - static gchar *template = NULL; - - if (G_UNLIKELY (template == NULL)) - template = g_strdup_printf ( - PACKAGE "-%s-XXXXXX", g_get_user_name ()); - - return g_file_open_tmp (template, name_used, error); -} - -/** * e_lookup_action: * @ui_manager: a #GtkUIManager * @action_name: the name of an action diff --git a/e-util/e-util.h b/e-util/e-util.h index 168b497da7..84ec411516 100644 --- a/e-util/e-util.h +++ b/e-util/e-util.h @@ -47,8 +47,6 @@ void e_show_uri (GtkWindow *parent, const gchar *uri); void e_display_help (GtkWindow *parent, const gchar *link_id); -gint e_file_open_tmp (gchar **name_used, - GError **error); GtkAction * e_lookup_action (GtkUIManager *ui_manager, const gchar *action_name); GtkActionGroup *e_lookup_action_group (GtkUIManager *ui_manager, diff --git a/mail/e-attachment-handler-mail.c b/mail/e-attachment-handler-mail.c index 32cd884fe2..b7be3b6b38 100644 --- a/mail/e-attachment-handler-mail.c +++ b/mail/e-attachment-handler-mail.c @@ -23,6 +23,7 @@ #include <config.h> #include <glib/gi18n.h> +#include <camel/camel-stream-mem.h> #include "mail/em-composer-utils.h" @@ -47,17 +48,21 @@ static const gchar *ui = " </popup>" "</ui>"; +/* Note: Do not use the info field. */ +static GtkTargetEntry target_table[] = { + { "message/rfc822", 0, 0 }, + { "x-uid-list", 0, 0 } +}; + static void -action_mail_forward_cb (GtkAction *action, - EAttachmentHandler *handler) +attachment_handler_mail_forward (GtkAction *action, + EAttachmentView *view) { - EAttachmentView *view; EAttachment *attachment; CamelMimePart *mime_part; CamelDataWrapper *wrapper; GList *selected; - view = e_attachment_handler_get_view (handler); selected = e_attachment_view_get_selected_attachments (view); g_return_if_fail (g_list_length (selected) == 1); @@ -72,16 +77,14 @@ action_mail_forward_cb (GtkAction *action, } static void -action_mail_reply_all_cb (GtkAction *action, - EAttachmentHandler *handler) +attachment_handler_mail_reply_all (GtkAction *action, + EAttachmentView *view) { - EAttachmentView *view; EAttachment *attachment; CamelMimePart *mime_part; CamelDataWrapper *wrapper; GList *selected; - view = e_attachment_handler_get_view (handler); selected = e_attachment_view_get_selected_attachments (view); g_return_if_fail (g_list_length (selected) == 1); @@ -98,16 +101,14 @@ action_mail_reply_all_cb (GtkAction *action, } static void -action_mail_reply_sender_cb (GtkAction *action, - EAttachmentHandler *handler) +attachment_handler_mail_reply_sender (GtkAction *action, + EAttachmentView *view) { - EAttachmentView *view; EAttachment *attachment; CamelMimePart *mime_part; CamelDataWrapper *wrapper; GList *selected; - view = e_attachment_handler_get_view (handler); selected = e_attachment_view_get_selected_attachments (view); g_return_if_fail (g_list_length (selected) == 1); @@ -130,26 +131,109 @@ static GtkActionEntry standard_entries[] = { N_("_Forward"), NULL, NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_mail_forward_cb) }, + G_CALLBACK (attachment_handler_mail_forward) }, { "mail-reply-all", "mail-reply-all", N_("Reply to _All"), NULL, NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_mail_reply_all_cb) }, + G_CALLBACK (attachment_handler_mail_reply_all) }, { "mail-reply-sender", "mail-reply-sender", N_("_Reply to Sender"), NULL, NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_mail_reply_sender_cb) } + G_CALLBACK (attachment_handler_mail_reply_sender) } }; static void -attachment_handler_mail_update_actions_cb (EAttachmentView *view, - EAttachmentHandler *handler) +attachment_handler_mail_message_rfc822 (EAttachmentView *view, + GdkDragContext *drag_context, + gint x, + gint y, + GtkSelectionData *selection_data, + guint info, + guint time) +{ + static GdkAtom atom = GDK_NONE; + EAttachmentStore *store; + EAttachment *attachment; + CamelMimeMessage *message; + CamelDataWrapper *wrapper; + CamelStream *stream; + const gchar *data; + gboolean success = FALSE; + gpointer parent; + gint length; + + if (G_UNLIKELY (atom == GDK_NONE)) + atom = gdk_atom_intern_static_string ("message/rfc822"); + + if (gtk_selection_data_get_target (selection_data) != atom) + return; + + g_signal_stop_emission_by_name (view, "drag-data-received"); + + data = (const gchar *) gtk_selection_data_get_data (selection_data); + length = gtk_selection_data_get_length (selection_data); + + stream = camel_stream_mem_new (); + camel_stream_write (stream, data, length); + camel_stream_reset (stream); + + message = camel_mime_message_new (); + wrapper = CAMEL_DATA_WRAPPER (message); + + if (camel_data_wrapper_construct_from_stream (wrapper, stream) == -1) + goto exit; + + store = e_attachment_view_get_store (view); + + parent = gtk_widget_get_toplevel (GTK_WIDGET (view)); + parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL; + + attachment = e_attachment_new_for_message (message); + e_attachment_store_add_attachment (store, attachment); + e_attachment_load_async ( + attachment, (GAsyncReadyCallback) + e_attachment_load_handle_error, parent); + g_object_unref (attachment); + + success = TRUE; + +exit: + camel_object_unref (message); + camel_object_unref (stream); + + gtk_drag_finish (drag_context, success, FALSE, time); +} + +static void +attachment_handler_mail_x_uid_list (EAttachmentView *view, + GdkDragContext *drag_context, + gint x, + gint y, + GtkSelectionData *selection_data, + guint info, + guint time) +{ + static GdkAtom atom = GDK_NONE; + + if (G_UNLIKELY (atom == GDK_NONE)) + atom = gdk_atom_intern_static_string ("x-uid-list"); + + if (gtk_selection_data_get_target (selection_data) != atom) + return; + + return; /* REMOVE ME */ + + g_signal_stop_emission_by_name (view, "drag-data-received"); +} + +static void +attachment_handler_mail_update_actions (EAttachmentView *view) { EAttachment *attachment; CamelMimePart *mime_part; @@ -184,7 +268,6 @@ exit: static void attachment_handler_mail_constructed (GObject *object) { - EAttachmentHandlerMailPrivate *priv; EAttachmentHandler *handler; EAttachmentView *view; GtkActionGroup *action_group; @@ -193,7 +276,6 @@ attachment_handler_mail_constructed (GObject *object) GError *error = NULL; handler = E_ATTACHMENT_HANDLER (object); - priv = E_ATTACHMENT_HANDLER_MAIL_GET_PRIVATE (object); /* Chain up to parent's constructed() method. */ G_OBJECT_CLASS (parent_class)->constructed (object); @@ -205,7 +287,7 @@ attachment_handler_mail_constructed (GObject *object) gtk_action_group_set_translation_domain (action_group, domain); gtk_action_group_add_actions ( action_group, standard_entries, - G_N_ELEMENTS (standard_entries), object); + G_N_ELEMENTS (standard_entries), view); gtk_ui_manager_insert_action_group (ui_manager, action_group, 0); g_object_unref (action_group); @@ -218,20 +300,51 @@ attachment_handler_mail_constructed (GObject *object) g_signal_connect ( view, "update-actions", - G_CALLBACK (attachment_handler_mail_update_actions_cb), - object); + G_CALLBACK (attachment_handler_mail_update_actions), + NULL); + + g_signal_connect ( + view, "drag-data-received", + G_CALLBACK (attachment_handler_mail_message_rfc822), + NULL); + + g_signal_connect ( + view, "drag-data-received", + G_CALLBACK (attachment_handler_mail_x_uid_list), + NULL); +} + +static GdkDragAction +attachment_handler_mail_get_drag_actions (EAttachmentHandler *handler) +{ + return GDK_ACTION_COPY; +} + +static const GtkTargetEntry * +attachment_handler_mail_get_target_table (EAttachmentHandler *handler, + guint *n_targets) +{ + if (n_targets != NULL) + *n_targets = G_N_ELEMENTS (target_table); + + return target_table; } static void attachment_handler_mail_class_init (EAttachmentHandlerMailClass *class) { GObjectClass *object_class; + EAttachmentHandlerClass *handler_class; parent_class = g_type_class_peek_parent (class); g_type_class_add_private (class, sizeof (EAttachmentHandlerMailPrivate)); object_class = G_OBJECT_CLASS (class); object_class->constructed = attachment_handler_mail_constructed; + + handler_class = E_ATTACHMENT_HANDLER_CLASS (class); + handler_class->get_drag_actions = attachment_handler_mail_get_drag_actions; + handler_class->get_target_table = attachment_handler_mail_get_target_table; } static void @@ -261,8 +374,7 @@ e_attachment_handler_mail_get_type (void) type = g_type_register_static ( E_TYPE_ATTACHMENT_HANDLER, - "EAttachmentHandlerMail", - &type_info, 0); + "EAttachmentHandlerMail", &type_info, 0); } return type; diff --git a/mail/em-popup.c b/mail/em-popup.c index c9dde270a0..e57b1de7f8 100644 --- a/mail/em-popup.c +++ b/mail/em-popup.c @@ -55,8 +55,6 @@ #include <e-util/e-util.h> #include "e-attachment.h" -static void emp_standard_menu_factory(EPopup *emp, void *data); - static GObjectClass *emp_parent; static void @@ -116,10 +114,6 @@ emp_class_init(GObjectClass *klass) { klass->finalize = emp_finalise; ((EPopupClass *)klass)->target_free = emp_target_free; - -#if 0 /* KILL-BONOBO */ - e_popup_class_add_factory((EPopupClass *)klass, NULL, emp_standard_menu_factory, NULL); -#endif } GType @@ -363,568 +357,6 @@ done: return t; } -#if 0 /* KILL-BONOBO */ -/** - * em_popup_target_new_attachments: - * @emp: - * @attachments: A list of EMsgComposerAttachment objects, reffed for - * the list. Will be unreff'd once finished with. - * - * Owns the list @attachments and their items after they're passed in. - * - * Return value: - **/ -EMPopupTargetAttachments * -em_popup_target_new_attachments(EMPopup *emp, GSList *attachments) -{ - EMPopupTargetAttachments *t = e_popup_target_new(&emp->popup, EM_POPUP_TARGET_ATTACHMENTS, sizeof(*t)); - guint32 mask = ~0; - int len = g_slist_length(attachments); - - t->attachments = attachments; - if (len > 0) - mask &= ~ EM_POPUP_ATTACHMENTS_MANY; - if (len == 1 && ((EAttachment *)attachments->data)->is_available_local) { - EAttachment *attachment; - CamelMimePart *mime_part; - CamelContentType *mime_type; - CamelDataWrapper *data_wrapper; - - attachment = attachments->data; - mime_part = e_attachment_get_mime_part (attachment); - mime_type = CAMEL_DATA_WRAPPER (mime_part)->mime_type; - data_wrapper = camel_medium_get_content_object ( - CAMEL_MEDIUM (mime_part)); - - if (camel_content_type_is (mime_type, "image", "*")) - mask &= ~ EM_POPUP_ATTACHMENTS_IMAGE; - if (CAMEL_IS_MIME_MESSAGE (data_wrapper)) - mask &= ~EM_POPUP_ATTACHMENTS_MESSAGE; - - mask &= ~ EM_POPUP_ATTACHMENTS_ONE; - } - if (len > 1) - mask &= ~ EM_POPUP_ATTACHMENTS_MULTIPLE; - t->target.mask = mask; - - return t; -} -#endif - -/* ********************************************************************** */ - -#if 0 /* KILL-BONOBO */ -static void -emp_part_popup_saveas(EPopup *ep, EPopupItem *item, void *data) -{ - EPopupTarget *t = ep->target; - CamelMimePart *part = NULL; - GtkWidget *widget; - gpointer parent; - - /* If it is of type EM_POPUP_TARGET_ATTACHMENTS, we can assume the length is one. */ - if (t->type == EM_POPUP_TARGET_ATTACHMENTS) { - EAttachment *attachment; - - attachment = E_ATTACHMENT (((EMPopupTargetAttachments *) t)->attachments->data); - part = e_attachment_get_mime_part (attachment); - } else - part = ((EMPopupTargetPart *) t)->part; - - widget = ep->target->widget; - parent = gtk_widget_get_toplevel (widget); - parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL; - - em_utils_save_part (parent, _("Save As..."), part); -} -#endif - -#if 0 /* KILL-BONOBO */ -static void -emp_part_popup_set_background(EPopup *ep, EPopupItem *item, void *data) -{ - EPopupTarget *t = ep->target; - GConfClient *gconf; - char *str, *filename, *path, *extension; - unsigned int i=1; - CamelMimePart *part = NULL; - - if (t->type == EM_POPUP_TARGET_ATTACHMENTS) { - EAttachment *attachment; - - attachment = E_ATTACHMENT (((EMPopupTargetAttachments *) t)->attachments->data); - part = e_attachment_get_mime_part (attachment); - } else - part = ((EMPopupTargetPart *) t)->part; - - if (!part) - return; - - filename = g_strdup(camel_mime_part_get_filename(part)); - - /* if filename is blank, create a default filename based on MIME type */ - if (!filename || !filename[0]) { - CamelContentType *ct; - - ct = camel_mime_part_get_content_type(part); - g_free (filename); - filename = g_strdup_printf (_("untitled_image.%s"), ct->subtype); - } - - e_filename_make_safe(filename); - - path = g_build_filename(g_get_home_dir(), ".gnome2", "wallpapers", filename, NULL); - - extension = strrchr(filename, '.'); - if (extension) - *extension++ = 0; - - /* if file exists, stick a (number) on the end */ - while (g_file_test(path, G_FILE_TEST_EXISTS)) { - char *name; - name = g_strdup_printf(extension?"%s (%d).%s":"%s (%d)", filename, i++, extension); - g_free(path); - path = g_build_filename(g_get_home_dir(), ".gnome2", "wallpapers", name, NULL); - g_free(name); - } - - g_free(filename); - - if (em_utils_save_part_to_file(ep->target->widget, path, part)) { - gconf = gconf_client_get_default(); - - /* if the filename hasn't changed, blank the filename before - * setting it so that gconf detects a change and updates it */ - if ((str = gconf_client_get_string(gconf, "/desktop/gnome/background/picture_filename", NULL)) != NULL - && strcmp (str, path) == 0) { - gconf_client_set_string(gconf, "/desktop/gnome/background/picture_filename", "", NULL); - } - - g_free (str); - gconf_client_set_string(gconf, "/desktop/gnome/background/picture_filename", path, NULL); - - /* if GNOME currently doesn't display a picture, set to "wallpaper" - * display mode, otherwise leave it alone */ - if ((str = gconf_client_get_string(gconf, "/desktop/gnome/background/picture_options", NULL)) == NULL - || strcmp(str, "none") == 0) { - gconf_client_set_string(gconf, "/desktop/gnome/background/picture_options", "wallpaper", NULL); - } - - gconf_client_suggest_sync(gconf, NULL); - - g_free(str); - g_object_unref(gconf); - } - - g_free(path); -} -#endif - -static void -emp_part_popup_reply_sender(EPopup *ep, EPopupItem *item, void *data) -{ - EPopupTarget *t = ep->target; - CamelMimeMessage *message; - CamelMimePart *part; - - if (t->type == EM_POPUP_TARGET_ATTACHMENTS) { - EAttachment *attachment; - - attachment = E_ATTACHMENT (((EMPopupTargetAttachments *) t)->attachments->data); - part = e_attachment_get_mime_part (attachment); - } else - part = ((EMPopupTargetPart *) t)->part; - - message = (CamelMimeMessage *)camel_medium_get_content_object((CamelMedium *)part); - em_utils_reply_to_message(NULL, NULL, message, REPLY_MODE_SENDER, NULL); -} - -static void -emp_part_popup_reply_list (EPopup *ep, EPopupItem *item, void *data) -{ - EPopupTarget *t = ep->target; - CamelMimeMessage *message; - CamelMimePart *part; - - if (t->type == EM_POPUP_TARGET_ATTACHMENTS) { - EAttachment *attachment; - - attachment = E_ATTACHMENT (((EMPopupTargetAttachments *) t)->attachments->data); - part = e_attachment_get_mime_part (attachment); - } else - part = ((EMPopupTargetPart *) t)->part; - - message = (CamelMimeMessage *)camel_medium_get_content_object((CamelMedium *)part); - em_utils_reply_to_message(NULL, NULL, message, REPLY_MODE_LIST, NULL); -} - -static void -emp_part_popup_reply_all (EPopup *ep, EPopupItem *item, void *data) -{ - EPopupTarget *t = ep->target; - CamelMimeMessage *message; - CamelMimePart *part; - - if (t->type == EM_POPUP_TARGET_ATTACHMENTS) { - EAttachment *attachment; - - attachment = E_ATTACHMENT (((EMPopupTargetAttachments *) t)->attachments->data); - part = e_attachment_get_mime_part (attachment); - } else - part = ((EMPopupTargetPart *) t)->part; - - message = (CamelMimeMessage *)camel_medium_get_content_object((CamelMedium *)part); - em_utils_reply_to_message(NULL, NULL, message, REPLY_MODE_ALL, NULL); -} - -static void -emp_part_popup_forward (EPopup *ep, EPopupItem *item, void *data) -{ - EPopupTarget *t = ep->target; - CamelMimeMessage *message; - CamelMimePart *part; - - if (t->type == EM_POPUP_TARGET_ATTACHMENTS) { - EAttachment *attachment; - - attachment = E_ATTACHMENT (((EMPopupTargetAttachments *) t)->attachments->data); - part = e_attachment_get_mime_part (attachment); - } else - part = ((EMPopupTargetPart *) t)->part; - - /* TODO: have a emfv specific override so we can get the parent folder uri */ - message = (CamelMimeMessage *)camel_medium_get_content_object((CamelMedium *) part); - em_utils_forward_message(message, NULL); -} - -#if 0 /* KILL-BONOBO */ -static EMPopupItem emp_standard_object_popups[] = { - { E_POPUP_ITEM, "00.part.00", N_("_Save As..."), emp_part_popup_saveas, NULL, "document-save-as", 0 }, - { E_POPUP_ITEM, "00.part.10", N_("Set as _Background"), emp_part_popup_set_background, NULL, NULL, EM_POPUP_PART_IMAGE }, - { E_POPUP_BAR, "10.part", NULL, NULL, NULL, NULL, EM_POPUP_PART_MESSAGE }, - { E_POPUP_ITEM, "10.part.00", N_("_Reply to sender"), emp_part_popup_reply_sender, NULL, "mail-reply-sender" , EM_POPUP_PART_MESSAGE }, - { E_POPUP_ITEM, "10.part.01", N_("Reply to _List"), emp_part_popup_reply_list, NULL, NULL, EM_POPUP_PART_MESSAGE}, - { E_POPUP_ITEM, "10.part.03", N_("Reply to _All"), emp_part_popup_reply_all, NULL, "mail-reply-all", EM_POPUP_PART_MESSAGE}, - { E_POPUP_BAR, "20.part", NULL, NULL, NULL, NULL, EM_POPUP_PART_MESSAGE }, - { E_POPUP_ITEM, "20.part.00", N_("_Forward"), emp_part_popup_forward, NULL, "mail-forward", EM_POPUP_PART_MESSAGE }, -}; - -static EMPopupItem emp_attachment_object_popups[] = { - { E_POPUP_ITEM, "00.attach.00", N_("_Save As..."), emp_part_popup_saveas, NULL, "document-save-as", 0 }, - { E_POPUP_ITEM, "00.attach.10", N_("Set as _Background"), emp_part_popup_set_background, NULL, NULL, EM_POPUP_ATTACHMENTS_IMAGE }, - { E_POPUP_BAR, "05.attach", NULL, NULL, NULL, NULL, EM_POPUP_ATTACHMENTS_MESSAGE }, - { E_POPUP_ITEM, "05.attach.00", N_("_Reply to sender"), emp_part_popup_reply_sender, NULL, "mail-reply-sender" , EM_POPUP_ATTACHMENTS_MESSAGE }, - { E_POPUP_ITEM, "05.attach.01", N_("Reply to _List"), emp_part_popup_reply_list, NULL, NULL, EM_POPUP_ATTACHMENTS_MESSAGE}, - { E_POPUP_ITEM, "05.attach.03", N_("Reply to _All"), emp_part_popup_reply_all, NULL, "mail-reply-all", EM_POPUP_ATTACHMENTS_MESSAGE}, - { E_POPUP_BAR, "05.attach.10", NULL, NULL, NULL, NULL, EM_POPUP_ATTACHMENTS_MESSAGE }, - { E_POPUP_ITEM, "05.attach.15", N_("_Forward"), emp_part_popup_forward, NULL, "mail-forward", EM_POPUP_ATTACHMENTS_MESSAGE }, -}; - -static const EPopupItem emp_standard_part_apps_bar = { E_POPUP_BAR, "99.object" }; -#endif - -/* ********************************************************************** */ - -static void -emp_uri_popup_link_open(EPopup *ep, EPopupItem *item, void *data) -{ - EMPopupTargetURI *t = (EMPopupTargetURI *)ep->target; - gchar *unescaped_uri = em_utils_url_unescape_amp (t->uri); - - /* FIXME Pass a parent window. */ - e_show_uri (NULL, unescaped_uri); - g_free (unescaped_uri); -} - -static void -emp_uri_popup_address_send(EPopup *ep, EPopupItem *item, void *data) -{ - EMPopupTargetURI *t = (EMPopupTargetURI *)ep->target; - - /* TODO: have an emfv specific override to get the from uri */ - em_utils_compose_new_message_with_mailto(t->uri, NULL); -} - -static void -emp_uri_popup_address_add(EPopup *ep, EPopupItem *item, void *data) -{ - EMPopupTargetURI *t = (EMPopupTargetURI *)ep->target; - CamelURL *url; - - url = camel_url_new(t->uri, NULL); - if (url == NULL) { - g_warning("cannot parse url '%s'", t->uri); - return; - } - - if (url->path && url->path[0]) - em_utils_add_address(ep->target->widget, url->path); - - camel_url_free(url); -} - -static EPopupItem emp_standard_uri_popups[] = { - { E_POPUP_ITEM, "00.uri.00", N_("_Open Link in Browser"), emp_uri_popup_link_open, NULL, NULL, EM_POPUP_URI_HTTP }, - { E_POPUP_ITEM, "00.uri.10", N_("_Send New Message To..."), emp_uri_popup_address_send, NULL, "mail-message-new", EM_POPUP_URI_MAILTO }, - { E_POPUP_ITEM, "00.uri.20", N_("_Add to Address Book"), emp_uri_popup_address_add, NULL, "contact-new", EM_POPUP_URI_MAILTO }, -}; - -/* ********************************************************************** */ - -#define LEN(x) (sizeof(x)/sizeof(x[0])) - -static void -emp_apps_open_in(EPopup *ep, EPopupItem *item, void *data) -{ - char *path; - EPopupTarget *target = ep->target; - CamelMimePart *part; - - if (target->type == EM_POPUP_TARGET_ATTACHMENTS) { - EAttachment *attachment; - - attachment = E_ATTACHMENT (((EMPopupTargetAttachments *) target)->attachments->data); - part = e_attachment_get_mime_part (attachment); - } else - part = ((EMPopupTargetPart *) target)->part; - - path = em_utils_temp_save_part(target->widget, part, TRUE); - if (path) { - GAppInfo *app = item->user_data; - GList *uris = NULL; - GError *error = NULL; - - if (g_app_info_supports_files (app)) { - GFile *file = g_file_new_for_path (path); - - uris = g_list_append (uris, file); - g_app_info_launch (app, uris, NULL, &error); - g_object_unref (file); - } else { - char *uri; - - uri = e_util_filename_to_uri (path); - uris = g_list_append (uris, uri); - - g_app_info_launch_uris (app, uris, NULL, &error); - g_free (uri); - } - - if (error) { - g_warning ("%s", error->message); - g_error_free (error); - } - - g_list_free (uris); - g_free (path); - } -} - -static void -emp_apps_popup_free(EPopup *ep, GSList *free_list, void *data) -{ - while (free_list) { - GSList *n = free_list->next; - EPopupItem *item = free_list->data; - - if (item->user_data && item->activate == emp_apps_open_in) - g_object_unref (item->user_data); - - g_free(item->path); - g_free(item->label); - g_free(item); - g_slist_free_1(free_list); - - free_list = n; - } -} - -static void -emp_standard_items_free(EPopup *ep, GSList *items, void *data) -{ - g_slist_free(items); -} - -static void -emp_add_vcard (EPopup *ep, EPopupItem *item, void *data) -{ - EPopupTarget *target = ep->target; - CamelMimePart *part; - CamelDataWrapper *content; - CamelStreamMem *mem; - - if (target->type == EM_POPUP_TARGET_ATTACHMENTS) { - EAttachment *attachment; - - attachment = E_ATTACHMENT (((EMPopupTargetAttachments *) target)->attachments->data); - part = e_attachment_get_mime_part (attachment); - } else - part = ((EMPopupTargetPart *) target)->part; - - if (!part) - return; - - content = camel_medium_get_content_object (CAMEL_MEDIUM (part)); - mem = CAMEL_STREAM_MEM (camel_stream_mem_new ()); - - if (camel_data_wrapper_decode_to_stream (content, CAMEL_STREAM (mem)) == -1 || - !mem->buffer->data) - g_warning ("Read part's content failed!"); - else { - GString *vcard = g_string_new_len ((const gchar *) mem->buffer->data, mem->buffer->len); - - em_utils_add_vcard (target->widget, vcard->str); - - g_string_free (vcard, TRUE); - } - - camel_object_unref (mem); -} - -#if 0 /* KILL-BONOBO */ -static void -emp_standard_menu_factory(EPopup *emp, void *data) -{ - int i, len; - EPopupItem *items; - GSList *menus = NULL; - GList *apps = NULL; - char *mime_type = NULL; - const char *filename = NULL; - - switch (emp->target->type) { -#if 0 - case EM_POPUP_TARGET_SELECT: - return; - items = emp_standard_select_popups; - len = LEN(emp_standard_select_popups); - break; -#endif - case EM_POPUP_TARGET_URI: { - /*EMPopupTargetURI *t = (EMPopupTargetURI *)target;*/ - - items = emp_standard_uri_popups; - len = LEN(emp_standard_uri_popups); - break; } - case EM_POPUP_TARGET_PART: { - EMPopupTargetPart *t = (EMPopupTargetPart *)emp->target; - mime_type = camel_data_wrapper_get_mime_type((CamelDataWrapper *)t->part); - filename = camel_mime_part_get_filename(t->part); - - items = emp_standard_object_popups; - len = LEN(emp_standard_object_popups); - break; } - case EM_POPUP_TARGET_ATTACHMENTS: { - EMPopupTargetAttachments *t = (EMPopupTargetAttachments *)emp->target; - GSList *list = t->attachments; - EAttachment *attachment; - CamelMimePart *mime_part; - - if (g_slist_length(list) != 1 || !((EAttachment *)list->data)->is_available_local) { - items = NULL; - len = 0; - break; - } - - /* Only one attachment selected */ - attachment = list->data; - mime_part = e_attachment_get_mime_part (attachment); - mime_type = camel_data_wrapper_get_mime_type (CAMEL_DATA_WRAPPER (mime_part)); - filename = camel_mime_part_get_filename (mime_part); - - items = emp_attachment_object_popups; - len = LEN(emp_attachment_object_popups); - break; } - default: - items = NULL; - len = 0; - } - - if (mime_type) { - gchar *cp; - - /* GIO expects lowercase MIME types. */ - for (cp = mime_type; *cp != '\0'; cp++) - *cp = g_ascii_tolower (*cp); - - cp = g_content_type_from_mime_type (mime_type); - apps = g_app_info_get_all_for_type (cp ? cp : mime_type); - g_free (cp); - - if (apps == NULL && strcmp (mime_type, "application/octet-stream") == 0) { - if (filename != NULL) { - gchar *name_type; - - name_type = e_util_guess_mime_type (filename, FALSE); - cp = g_content_type_from_mime_type (name_type); - apps = g_app_info_get_all_for_type (cp ? cp : name_type); - g_free (cp); - g_free (name_type); - } - } - - if (apps) { - GString *label = g_string_new(""); - GSList *open_menus = NULL; - GList *l; - - menus = g_slist_prepend(menus, (void *)&emp_standard_part_apps_bar); - - for (l = apps, i = 0; l; l = l->next, i++) { - GAppInfo *app = l->data; - EPopupItem *item; - - if (!g_app_info_should_show (app)) { - g_object_unref (app); - l->data = NULL; - continue; - } - - item = g_malloc0(sizeof(*item)); - item->type = E_POPUP_ITEM; - item->path = g_strdup_printf("99.object.%02d", i); - item->label = g_strdup_printf(_("Open in %s..."), g_app_info_get_name (app)); - item->activate = emp_apps_open_in; - item->user_data = app; - - open_menus = g_slist_prepend(open_menus, item); - } - - if (open_menus) - e_popup_add_items(emp, open_menus, NULL, emp_apps_popup_free, NULL); - - g_string_free(label, TRUE); - g_list_free(apps); - } - - if (g_ascii_strcasecmp (mime_type, "text/x-vcard") == 0|| - g_ascii_strcasecmp (mime_type, "text/vcard") == 0) { - EPopupItem *item; - - item = g_malloc0 (sizeof (*item)); - item->type = E_POPUP_ITEM; - item->path = "00.00.vcf.00"; /* make it first item */ - item->label = _("_Add to Address Book"); - item->activate = emp_add_vcard; - item->user_data = NULL; - item->image = "contact-new"; - - e_popup_add_items (emp, g_slist_append (NULL, item), NULL, NULL, NULL); - } - - g_free (mime_type); - } - - for (i=0;i<len;i++) { - if ((items[i].visible & emp->target->mask) == 0) - menus = g_slist_prepend(menus, &items[i]); - } - - if (menus) - e_popup_add_items(emp, menus, NULL, emp_standard_items_free, NULL); -} -#endif - /* ********************************************************************** */ /* Popup menu plugin handler */ diff --git a/plugins/save-attachments/ChangeLog b/plugins/save-attachments/ChangeLog deleted file mode 100644 index 9980fdf13d..0000000000 --- a/plugins/save-attachments/ChangeLog +++ /dev/null @@ -1,102 +0,0 @@ -2009-01-28 Tor Lillqvist <tml@novell.com> - - * Makefile.am: Use -no-undefined and link with more libs on - Windows. - -2008-09-19 Sankar P <psankar@novell.com> - -License Changes - - * save-attachments.c: - -2007-12-20 Matthew Barnes <mbarnes@redhat.com> - - ** Fixes part of bug #362638 - - * save-attachments.c: - Use the new MailMsg API for messages. - -2007-04-02 Sankar P <psankar@novell.com> - - * Committed on behalf of Gilles Dartiguelongue <dartigug@esiee.fr> - - * org-gnome-save-attachments.eplug.xml: - Cleanup. - Fixes part of #301149 - -2007-03-29 Matthew Barnes <mbarnes@redhat.com> - - * save-attachments.c: - Evolution requires GLib 2.10 now; remove dead backward-compatibility - code for GLib < 2.8 (#418971). - -2007-01-27 Nickolay V. Shmyrev <nshmyrev@yandex.ru> - - * save-attachments.c: (save_got_message): - mark strings as translatable. See bug #399381 for details. - -2006-07-07 Hiroyuki Ikezoe <poincare@ikezoe.net> - - ** Fixes bug #341369 - * save-attachments.c: fixing a memory leak. - -2006-02-28 Shi Pu <shi.pu@sun.com> - - ** Fixes #323853 - - * save-attachments.c: (save_response), (entry_changed), - (save_got_message): - replace GnomeFileEntry by GtkFileChooserButton. - -2005-12-17 Tor Lillqvist <tml@novell.com> - - * save-attachments.c (entry_changed): Use GLib API to manipulate - pathname. - -2005-05-16 Not Zed <NotZed@Ximian.com> - - * save-attachments.c: moved e-error to e-util - -2005-05-13 Rodney Dawes <dobey@novell.com> - - * org-gnome-save-attachments.xml: Update for new menu layout - -2005-05-12 Not Zed <NotZed@Ximian.com> - - * Makefile.am: setup built_sources/cleanfiles. - -2005-05-06 Not Zed <NotZed@Ximian.com> - - * Makefile.am: - * org-gnome-save-attachments.eplug.xml: s/.in/.xml/ & i18n. - -2005-02-24 Björn Torkelsson <torkel@acc.umu.se> - - * org-gnome-save-attachments.eplug.in: Removed plugin from the - name. - Fixed description and added author - -2005-02-07 Not Zed <NotZed@Ximian.com> - - * save-attachments.c (save_part): fix the access() call test. - -2005-01-04 Philip Van Hoof <pvanhoof@gnome.org> - - * save-attachments.c: Use standard error messages - -2004-12-27 Philip Van Hoof <pvanhoof@gnome.org> - - * save-attachments.c: Warning when overwriting file - -2004-11-01 JP Rosevear <jpr@novell.com> - - * Makefile.am: dist xml menu file - -2004-11-01 JP Rosevear <jpr@novell.com> - - * Makefile.am: dist .eplug.in file - -2004-10-20 Not Zed <NotZed@Ximian.com> - - * Imported save-attachments example plugin. - diff --git a/plugins/save-attachments/Makefile.am b/plugins/save-attachments/Makefile.am deleted file mode 100644 index 05c724a4e4..0000000000 --- a/plugins/save-attachments/Makefile.am +++ /dev/null @@ -1,31 +0,0 @@ -if OS_WIN32 -NO_UNDEFINED_REQUIRED_LIBS = \ - $(top_builddir)/mail/libevolution-mail.la \ - $(EVOLUTION_MAIL_LIBS) \ - $(GNOME_PLATFORM_LIBS) \ - $(top_builddir)/e-util/libeutil.la -endif - -INCLUDES = \ - -I$(top_srcdir) \ - $(EVOLUTION_MAIL_CFLAGS) - -@EVO_PLUGIN_RULE@ - -plugin_DATA = org-gnome-save-attachments.eplug org-gnome-save-attachments.xml -plugin_LTLIBRARIES = liborg-gnome-save-attachments.la - -liborg_gnome_save_attachments_la_SOURCES = save-attachments.c -liborg_gnome_save_attachments_la_LDFLAGS = -module \ - -avoid-version $(NO_UNDEFINED) - -liborg_gnome_save_attachments_la_LIBADD = \ - $(NO_UNDEFINED_REQUIRED_LIBS) - - -EXTRA_DIST = \ - org-gnome-save-attachments.eplug.xml \ - org-gnome-save-attachments.xml - -BUILT_SOURCES = org-gnome-save-attachments.eplug -CLEANFILES = $(BUILT_SOURCES) diff --git a/plugins/save-attachments/org-gnome-save-attachments.eplug.xml b/plugins/save-attachments/org-gnome-save-attachments.eplug.xml deleted file mode 100644 index d51b341db4..0000000000 --- a/plugins/save-attachments/org-gnome-save-attachments.eplug.xml +++ /dev/null @@ -1,26 +0,0 @@ -<?xml version="1.0"?> -<e-plugin-list> - <!-- the path to the shared library --> - <e-plugin - id="org.gnome.plugin.attachments.save" - type="shlib" - location="@PLUGINDIR@/liborg-gnome-save-attachments@SOEXT@" - _name="Save attachments"> - - <author name="Not Zed" email="NotZed@Ximian.com"/> - <_description>A plugin for saving all attachments or parts of a message at once.</_description> - - <hook class="org.gnome.evolution.mail.bonobomenu:1.0"> - <menu id="org.gnome.evolution.mail.browser" target="select"> - <!-- the path to the bonobo menu description --> - <ui file="@PLUGINDIR@/org-gnome-save-attachments.xml"/> - <item - type="item" - verb="EPSASaveAttachments" - path="/commands/EPSASaveAttachments" - enable="one" - activate="org_gnome_save_attachments_save"/> - </menu> - </hook> - </e-plugin> -</e-plugin-list> diff --git a/plugins/save-attachments/org-gnome-save-attachments.xml b/plugins/save-attachments/org-gnome-save-attachments.xml deleted file mode 100644 index 75f4aef7fb..0000000000 --- a/plugins/save-attachments/org-gnome-save-attachments.xml +++ /dev/null @@ -1,20 +0,0 @@ -<Root> - <commands> - <cmd name="EPSASaveAttachments" _label="Save Attachments..." - _tip="Save all attachments" - pixtype="stock" pixname="Save"/> - </commands> - - <menu> -<!-- - <placeholder name="MessagePlaceholder"> - <submenu name="Message"> - <placeholder name="MailMessageActions"> - <separator f="" name="emaillist5"/> - <menuitem name="EPSASaveAttachments" verb=""/> - </placeholder> - </submenu> - </placeholder> ---> - </menu> -</Root> diff --git a/plugins/save-attachments/save-attachments.c b/plugins/save-attachments/save-attachments.c deleted file mode 100644 index c48711c55a..0000000000 --- a/plugins/save-attachments/save-attachments.c +++ /dev/null @@ -1,392 +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: - * Michael Zucchi <notzed@ximian.com> - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -/* This is prototype code only, this may, or may not, use undocumented - * unstable or private internal function calls. */ - -#include <sys/types.h> -#include <sys/stat.h> -#include <unistd.h> -#include <string.h> -#include <stdio.h> - -#include <gtk/gtk.h> -#include <glib/gi18n.h> -#include <glib/gstdio.h> - -#include <camel/camel-folder.h> -#include <camel/camel-exception.h> -#include <camel/camel-mime-message.h> -#include <camel/camel-multipart.h> -#include <camel/camel-utf8.h> - -#include "e-util/e-error.h" - -#include "mail/em-menu.h" -#include "mail/em-utils.h" - -/* these are sort of mail-internal */ -#include "mail/mail-mt.h" -#include "mail/mail-ops.h" - -void org_gnome_save_attachments_save(EPlugin *ep, EMMenuTargetSelect *target); - -struct _save_data { - CamelFolder *folder; - char *uid; - CamelMimeMessage *msg; - - char *path; - char *base; - - GtkWidget *entry; - GtkWidget *tree; - GtkTreeStore *model; -}; - -static void -free_data(struct _save_data *data) -{ - if (data->msg) - camel_object_unref(data->msg); - g_free(data->base); - g_free(data->path); - g_free(data->uid); - camel_object_unref(data->folder); - if (data->model) - g_object_unref(data->model); - g_free(data); -} - -static char * -clean_name(const char *s) -{ - GString *out = g_string_new(""); - int c; - char *r; - - while ( (c = camel_utf8_getc((const unsigned char **)&s)) ) { - if (!g_unichar_isprint(c) || ( c < 0x7f && strchr(" /'\"`&();|<>$%{}!", c ))) - c = '_'; - g_string_append_u(out, c); - } - - r = g_strdup(out->str); - g_string_free(out, TRUE); - - return r; -} - -static void -fill_model_rec(CamelMimeMessage *msg, CamelMimePart *part, GtkTreeStore *model, GtkTreeIter *parent, GString *name) -{ - CamelDataWrapper *containee; - int parts, i; - char *type; - GtkTreeIter iter; - int len = name->len; - CamelContentType *mime; - - containee = camel_medium_get_content_object((CamelMedium *)part); - if (containee == NULL) - return; - - mime = ((CamelDataWrapper *)containee)->mime_type; - type = camel_content_type_simple(mime); - - if (CAMEL_IS_MULTIPART(containee)) { - gtk_tree_store_append(model, &iter, parent); - g_string_append_printf(name, ".multipart"); - gtk_tree_store_set(model, &iter, 0, FALSE, 1, type, 2, name->str, 3, name->str, 4, part, -1); - - parts = camel_multipart_get_number((CamelMultipart *)containee); - for (i = 0; i < parts; i++) { - CamelMimePart *mpart = camel_multipart_get_part((CamelMultipart *)containee, i); - - g_string_truncate(name, len); - g_string_append_printf(name, ".%d", i); - fill_model_rec(msg, mpart, model, &iter, name); - } - } else if (CAMEL_IS_MIME_MESSAGE(containee)) { - gtk_tree_store_append(model, &iter, parent); - g_string_append_printf(name, ".msg"); - gtk_tree_store_set(model, &iter, 0, FALSE, 1, type, 2, name->str, 3, name->str, 4, part, -1); - fill_model_rec(msg, (CamelMimePart *)containee, model, &iter, name); - } else { - char *filename = NULL; - const char *ext = NULL, *tmp; - int save = FALSE; - - gtk_tree_store_append(model, &iter, parent); - tmp = camel_mime_part_get_filename(part); - if (tmp) { - filename = clean_name(tmp); - ext = strrchr(filename, '.'); - } - tmp = camel_mime_part_get_disposition(part); - if (tmp && !strcmp(tmp, "attachment")) - save = TRUE; - - if (camel_content_type_is(mime, "text", "*")) { - if (ext == NULL) { - if ((ext = mime->subtype) == NULL || !strcmp(ext, "plain")) - ext = "text"; - } - } else if (camel_content_type_is(mime, "image", "*")) { - if (ext == NULL) { - if ((ext = mime->subtype) == NULL) - ext = "image"; - } - save = TRUE; - } - - g_string_append_printf(name, ".%s", ext); - gtk_tree_store_set(model, &iter, 0, save, 1, type, 2, filename?filename:name->str, 3, filename?NULL:name->str, 4, part, -1); - g_free(filename); - } - g_free(type); - - g_string_truncate(name, len); -} - -static void -fill_model(CamelMimeMessage *msg, GtkTreeStore *model) -{ - GString *name = g_string_new(""); - GtkTreeIter iter; - - gtk_tree_store_append(model, &iter, NULL); - gtk_tree_store_set(model, &iter, 0, FALSE, 1, "message/rfc822", 2, ".msg", 3, ".msg", 4, msg, -1); - fill_model_rec(msg, (CamelMimePart *)msg, model, &iter, name); - g_string_free(name, TRUE); -} - -static gboolean -save_part(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, void *d) -{ - struct _save_data *data = d; - char *filename, *ext, *save; - CamelMimePart *part; - gboolean doit; - - /* TODO: check for existing file */ - - gtk_tree_model_get(model, iter, 0, &doit, -1); - if (!doit) - return FALSE; - - gtk_tree_model_get(model, iter, 2, &filename, 3, &ext, 4, &part, -1); - if (ext == NULL) - save = g_build_filename(data->path, filename, NULL); - else - save = g_strdup_printf("%s%s", data->base, ext); - - /* FIXME: if part == data->msg then we need to save this - * differently, not using the envelope MimePart */ - - /* - * The underlying em_utils_save_part_to_file ain't using gnome-vfs. Therefor - * the POSIX access-call should suffice for checking the file existence. - */ - - if (g_access(save, F_OK) == 0) - doit = e_error_run(NULL, E_ERROR_ASK_FILE_EXISTS_OVERWRITE, save, NULL) == GTK_RESPONSE_OK; - - if (doit) - em_utils_save_part_to_file(NULL, save, part); - - g_free(ext); - g_free(filename); - - return FALSE; -} - -static void -save_response(GtkWidget *d, int id, struct _save_data *data) -{ - if (id == GTK_RESPONSE_OK) { - char *tmp; - - data->base = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (data->entry)); - data->path = g_strdup(data->base); - tmp = strrchr(data->path, '/'); - if (tmp) - *tmp = 0; - gtk_tree_model_foreach((GtkTreeModel *)data->model, save_part, data); - } - - gtk_widget_destroy(d); - free_data(data); -} - -static gboolean -entry_changed_update(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, void *d) -{ - const char *name = d; - char *filename, *ext; - - gtk_tree_model_get(model, iter, 3, &ext, -1); - if (ext) { - filename = g_strdup_printf("%s%s", name, ext); - gtk_tree_store_set((GtkTreeStore *)model, iter, 2, filename, -1); - g_free(filename); - g_free(ext); - } - - return FALSE; -} - -static void -entry_changed(GtkWidget *entry, struct _save_data *data) -{ - char *path; - char *basename = NULL; - const char *file; - - path = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (data->entry)); - if (path == NULL - || G_IS_DIR_SEPARATOR (path[strlen(path)-1]) - || (basename = g_path_get_basename(path)) == NULL - || (basename[0] == '.' && basename[1] == '\0') - || (g_file_test(path, G_FILE_TEST_IS_DIR))) - file = "attachment"; - else - file = basename; - - gtk_tree_model_foreach((GtkTreeModel *)data->model, entry_changed_update, (void *)file); - g_free(path); - g_free(basename); -} - -static void -toggle_changed(GtkWidget *entry, const char *spath, struct _save_data *data) -{ - GtkTreePath *path; - GtkTreeIter iter; - - path = gtk_tree_path_new_from_string(spath); - if (gtk_tree_model_get_iter((GtkTreeModel *)data->model, &iter, path)) { - gboolean on; - - gtk_tree_model_get((GtkTreeModel *)data->model, &iter, 0, &on, -1); - gtk_tree_store_set(data->model, &iter, 0, !on, -1); - } - - gtk_tree_path_free (path); -} - -static void -save_got_message(CamelFolder *folder, const char *uid, CamelMimeMessage *msg, void *d) -{ - struct _save_data *data = d; - GtkDialog *dialog; - GtkWidget *w, *tree; - GtkTreeStore *model; - GtkCellRenderer *renderer; - - /* not found, the mailer will show an error box for this */ - if (msg == NULL) { - free_data(data); - return; - } - - data->msg = msg; - camel_object_ref(msg); - - dialog = (GtkDialog *)gtk_dialog_new_with_buttons(_("Save attachments"), - NULL, /* target->parent? */ - 0, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - GTK_STOCK_SAVE, GTK_RESPONSE_OK, - NULL); - w = gtk_file_chooser_button_new (_("Select save base name"), GTK_FILE_CHOOSER_ACTION_OPEN); - data->entry = w; - g_object_set(w, "filechooser_action", GTK_FILE_CHOOSER_ACTION_SAVE, NULL); - gtk_widget_show(w); - gtk_box_pack_start((GtkBox *)dialog->vbox, w, FALSE, TRUE, 6); - - g_signal_connect(GTK_FILE_CHOOSER_BUTTON (w), "selection-changed", G_CALLBACK(entry_changed), data); - - model = gtk_tree_store_new(5, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER); - data->model = model; - fill_model(msg, model); - - tree = gtk_tree_view_new_with_model((GtkTreeModel *)model); - data->tree = tree; - gtk_widget_show(tree); - gtk_tree_view_expand_all((GtkTreeView *)tree); - - renderer = gtk_cell_renderer_text_new(); - gtk_tree_view_insert_column_with_attributes((GtkTreeView *)tree, -1, - _("MIME Type"), renderer, "text", 1, NULL); - gtk_tree_view_set_expander_column((GtkTreeView *)tree, gtk_tree_view_get_column((GtkTreeView *)tree, 0)); - - renderer = gtk_cell_renderer_toggle_new(); - g_object_set(renderer, "activatable", TRUE, NULL); - g_signal_connect(renderer, "toggled", G_CALLBACK(toggle_changed), data); - - gtk_tree_view_insert_column_with_attributes((GtkTreeView *)tree, -1, - _("Save"), renderer, "active", 0, NULL); - renderer = gtk_cell_renderer_text_new(); - gtk_tree_view_insert_column_with_attributes((GtkTreeView *)tree, -1, - _("Name"), renderer, "text", 2, NULL); - - w = g_object_new(gtk_frame_get_type(), - "shadow_type", GTK_SHADOW_NONE, - "label_widget", g_object_new(gtk_label_get_type(), - "label", "<span weight=\"bold\">Attachments</span>", - "use_markup", TRUE, - "xalign", 0.0, NULL), - "child", g_object_new(gtk_alignment_get_type(), - "left_padding", 12, - "top_padding", 6, - "child", g_object_new(gtk_scrolled_window_get_type(), - "hscrollbar_policy", GTK_POLICY_AUTOMATIC, - "vscrollbar_policy", GTK_POLICY_AUTOMATIC, - "shadow_type", GTK_SHADOW_IN, - "child", tree, - NULL), - NULL), - NULL); - gtk_widget_show_all(w); - - gtk_box_pack_start((GtkBox *)dialog->vbox, w, TRUE, TRUE, 0); - g_signal_connect(dialog, "response", G_CALLBACK(save_response), data); - gtk_window_set_default_size((GtkWindow *)dialog, 500, 500); - gtk_widget_show((GtkWidget *)dialog); -} - -void -org_gnome_save_attachments_save(EPlugin *ep, EMMenuTargetSelect *target) -{ - struct _save_data *data; - - if (target->uids->len != 1) - return; - - data = g_malloc0(sizeof(*data)); - data->folder = target->folder; - camel_object_ref(data->folder); - data->uid = g_strdup(target->uids->pdata[0]); - - mail_get_message(data->folder, data->uid, save_got_message, data, mail_msg_unordered_push); -} diff --git a/widgets/misc/Makefile.am b/widgets/misc/Makefile.am index ad2f445eea..8ba66287f8 100644 --- a/widgets/misc/Makefile.am +++ b/widgets/misc/Makefile.am @@ -70,7 +70,6 @@ widgetsinclude_HEADERS = \ e-image-chooser.h \ e-map.h \ e-menu-tool-button.h \ - e-mime-part-utils.h \ e-online-button.h \ e-popup-action.h \ e-popup-menu.h \ @@ -134,7 +133,6 @@ libemiscwidgets_la_SOURCES = \ e-image-chooser.c \ e-map.c \ e-menu-tool-button.c \ - e-mime-part-utils.c \ e-online-button.c \ e-popup-action.c \ e-popup-menu.c \ diff --git a/widgets/misc/e-attachment-handler.c b/widgets/misc/e-attachment-handler.c index dce139f9c3..03af1eec9b 100644 --- a/widgets/misc/e-attachment-handler.c +++ b/widgets/misc/e-attachment-handler.c @@ -155,3 +155,37 @@ e_attachment_handler_get_view (EAttachmentHandler *handler) return E_ATTACHMENT_VIEW (handler->priv->view); } + +GdkDragAction +e_attachment_handler_get_drag_actions (EAttachmentHandler *handler) +{ + EAttachmentHandlerClass *class; + + g_return_val_if_fail (E_IS_ATTACHMENT_HANDLER (handler), 0); + + class = E_ATTACHMENT_HANDLER_GET_CLASS (handler); + + if (class->get_drag_actions != NULL) + return class->get_drag_actions (handler); + + return 0; +} + +const GtkTargetEntry * +e_attachment_handler_get_target_table (EAttachmentHandler *handler, + guint *n_targets) +{ + EAttachmentHandlerClass *class; + + g_return_val_if_fail (E_IS_ATTACHMENT_HANDLER (handler), NULL); + + class = E_ATTACHMENT_HANDLER_GET_CLASS (handler); + + if (class->get_target_table != NULL) + return class->get_target_table (handler, n_targets); + + if (n_targets != NULL) + *n_targets = 0; + + return NULL; +} diff --git a/widgets/misc/e-attachment-handler.h b/widgets/misc/e-attachment-handler.h index 8de5743ba6..05df3e8bbe 100644 --- a/widgets/misc/e-attachment-handler.h +++ b/widgets/misc/e-attachment-handler.h @@ -56,11 +56,22 @@ struct _EAttachmentHandler { struct _EAttachmentHandlerClass { GObjectClass parent_class; + + GdkDragAction (*get_drag_actions) (EAttachmentHandler *handler); + const GtkTargetEntry * + (*get_target_table) (EAttachmentHandler *handler, + guint *n_targets); }; GType e_attachment_handler_get_type (void); EAttachmentView * e_attachment_handler_get_view (EAttachmentHandler *handler); +GdkDragAction e_attachment_handler_get_drag_actions + (EAttachmentHandler *handler); +const GtkTargetEntry * + e_attachment_handler_get_target_table + (EAttachmentHandler *handler, + guint *n_targets); G_END_DECLS diff --git a/widgets/misc/e-attachment-paned.c b/widgets/misc/e-attachment-paned.c index 42890236e9..f9f7bb1cca 100644 --- a/widgets/misc/e-attachment-paned.c +++ b/widgets/misc/e-attachment-paned.c @@ -729,3 +729,20 @@ e_attachment_paned_set_expanded (EAttachmentPaned *paned, g_object_notify (G_OBJECT (paned), "expanded"); } + +void +e_attachment_paned_drag_data_received (EAttachmentPaned *paned, + GdkDragContext *context, + gint x, + gint y, + GtkSelectionData *selection, + guint info, + guint time) +{ + g_return_if_fail (E_IS_ATTACHMENT_PANED (paned)); + + /* XXX Dirty hack for forwarding drop events. */ + g_signal_emit_by_name ( + paned->priv->icon_view, "drag-data-received", + context, x, y, selection, info, time); +} diff --git a/widgets/misc/e-attachment-paned.h b/widgets/misc/e-attachment-paned.h index c15d642771..076ab6033e 100644 --- a/widgets/misc/e-attachment-paned.h +++ b/widgets/misc/e-attachment-paned.h @@ -70,6 +70,14 @@ void e_attachment_paned_set_active_view gboolean e_attachment_paned_get_expanded (EAttachmentPaned *paned); void e_attachment_paned_set_expanded (EAttachmentPaned *paned, gboolean expanded); +void e_attachment_paned_drag_data_received + (EAttachmentPaned *paned, + GdkDragContext *context, + gint x, + gint y, + GtkSelectionData *selection, + guint info, + guint time); G_END_DECLS diff --git a/widgets/misc/e-attachment-store.c b/widgets/misc/e-attachment-store.c index e565d68cae..589f670f34 100644 --- a/widgets/misc/e-attachment-store.c +++ b/widgets/misc/e-attachment-store.c @@ -21,10 +21,12 @@ #include "e-attachment-store.h" +#include <errno.h> +#include <config.h> #include <glib/gi18n.h> #include "e-util/e-util.h" -#include "e-util/gconf-bridge.h" +#include "e-util/e-mktemp.h" #define E_ATTACHMENT_STORE_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE \ @@ -32,8 +34,6 @@ struct _EAttachmentStorePrivate { GHashTable *attachment_index; - gchar *background_filename; - gchar *background_options; gchar *current_folder; guint ignore_row_changed : 1; @@ -41,8 +41,6 @@ struct _EAttachmentStorePrivate { enum { PROP_0, - PROP_BACKGROUND_FILENAME, - PROP_BACKGROUND_OPTIONS, PROP_CURRENT_FOLDER, PROP_NUM_ATTACHMENTS, PROP_NUM_LOADING, @@ -51,44 +49,6 @@ enum { static gpointer parent_class; -static const gchar * -attachment_store_get_background_filename (EAttachmentStore *store) -{ - return store->priv->background_filename; -} - -static void -attachment_store_set_background_filename (EAttachmentStore *store, - const gchar *background_filename) -{ - if (background_filename == NULL) - background_filename = ""; - - g_free (store->priv->background_filename); - store->priv->background_filename = g_strdup (background_filename); - - g_object_notify (G_OBJECT (store), "background-filename"); -} - -static const gchar * -attachment_store_get_background_options (EAttachmentStore *store) -{ - return store->priv->background_options; -} - -static void -attachment_store_set_background_options (EAttachmentStore *store, - const gchar *background_options) -{ - if (background_options == NULL) - background_options = ""; - - g_free (store->priv->background_options); - store->priv->background_options = g_strdup (background_options); - - g_object_notify (G_OBJECT (store), "background-options"); -} - static void attachment_store_set_property (GObject *object, guint property_id, @@ -96,18 +56,6 @@ attachment_store_set_property (GObject *object, GParamSpec *pspec) { switch (property_id) { - case PROP_BACKGROUND_FILENAME: - attachment_store_set_background_filename ( - E_ATTACHMENT_STORE (object), - g_value_get_string (value)); - return; - - case PROP_BACKGROUND_OPTIONS: - attachment_store_set_background_options ( - E_ATTACHMENT_STORE (object), - g_value_get_string (value)); - return; - case PROP_CURRENT_FOLDER: e_attachment_store_set_current_folder ( E_ATTACHMENT_STORE (object), @@ -125,20 +73,6 @@ attachment_store_get_property (GObject *object, GParamSpec *pspec) { switch (property_id) { - case PROP_BACKGROUND_FILENAME: - g_value_set_string ( - value, - attachment_store_get_background_filename ( - E_ATTACHMENT_STORE (object))); - return; - - case PROP_BACKGROUND_OPTIONS: - g_value_set_string ( - value, - attachment_store_get_background_options ( - E_ATTACHMENT_STORE (object))); - return; - case PROP_CURRENT_FOLDER: g_value_set_string ( value, @@ -193,8 +127,6 @@ attachment_store_finalize (GObject *object) g_hash_table_destroy (priv->attachment_index); - g_free (priv->background_filename); - g_free (priv->background_options); g_free (priv->current_folder); /* Chain up to parent's finalize() method. */ @@ -202,26 +134,6 @@ attachment_store_finalize (GObject *object) } static void -attachment_store_constructed (GObject *object) -{ - EAttachmentStorePrivate *priv; - GConfBridge *bridge; - const gchar *prop; - const gchar *key; - - priv = E_ATTACHMENT_STORE_GET_PRIVATE (object); - bridge = gconf_bridge_get (); - - prop = "background-filename"; - key = "/desktop/gnome/background/picture_filename"; - gconf_bridge_bind_property (bridge, key, object, prop); - - prop = "background-options"; - key = "/desktop/gnome/background/picture_options"; - gconf_bridge_bind_property (bridge, key, object, prop); -} - -static void attachment_store_class_init (EAttachmentStoreClass *class) { GObjectClass *object_class; @@ -234,29 +146,6 @@ attachment_store_class_init (EAttachmentStoreClass *class) object_class->get_property = attachment_store_get_property; object_class->dispose = attachment_store_dispose; object_class->finalize = attachment_store_finalize; - object_class->constructed = attachment_store_constructed; - - g_object_class_install_property ( - object_class, - PROP_BACKGROUND_FILENAME, - g_param_spec_string ( - "background-filename", - "Background Filename", - NULL, - NULL, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT)); - - g_object_class_install_property ( - object_class, - PROP_BACKGROUND_OPTIONS, - g_param_spec_string ( - "background-options", - "Background Options", - NULL, - NULL, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT)); g_object_class_install_property ( object_class, @@ -737,101 +626,124 @@ e_attachment_store_run_save_dialog (EAttachmentStore *store, return destination; } -/******************* e_attachment_store_save_list_async() ********************/ +/******************** e_attachment_store_get_uris_async() ********************/ -typedef struct _SaveContext SaveContext; +typedef struct _UriContext UriContext; -struct _SaveContext { +struct _UriContext { GSimpleAsyncResult *simple; GList *attachment_list; GError *error; + gchar **uris; + gint index; }; -static SaveContext * -attachment_store_save_context_new (EAttachmentStore *store, - GList *attachment_list, - GAsyncReadyCallback callback, - gpointer user_data) +static UriContext * +attachment_store_uri_context_new (EAttachmentStore *store, + GList *attachment_list, + GAsyncReadyCallback callback, + gpointer user_data) { - SaveContext *save_context; + UriContext *uri_context; GSimpleAsyncResult *simple; + guint length; + gchar **uris; simple = g_simple_async_result_new ( G_OBJECT (store), callback, user_data, - e_attachment_store_save_list_async); + e_attachment_store_get_uris_async); + + /* Add one for NULL terminator. */ + length = g_list_length (attachment_list) + 1; + uris = g_malloc0 (sizeof (gchar *) * length); - save_context = g_slice_new0 (SaveContext); - save_context->simple = simple; - save_context->attachment_list = g_list_copy (attachment_list); + uri_context = g_slice_new0 (UriContext); + uri_context->simple = simple; + uri_context->attachment_list = g_list_copy (attachment_list); + uri_context->uris = uris; g_list_foreach ( - save_context->attachment_list, + uri_context->attachment_list, (GFunc) g_object_ref, NULL); - return save_context; + return uri_context; } static void -attachment_store_save_context_free (SaveContext *save_context) +attachment_store_uri_context_free (UriContext *uri_context) { /* Do not free the GSimpleAsyncResult. */ /* The attachment list should be empty now. */ - g_warn_if_fail (save_context->attachment_list != NULL); + g_warn_if_fail (uri_context->attachment_list == NULL); /* So should the error. */ - g_warn_if_fail (save_context->error != NULL); + g_warn_if_fail (uri_context->error == NULL); - g_slice_free (SaveContext, save_context); + g_strfreev (uri_context->uris); + + g_slice_free (UriContext, uri_context); } static void -attachment_store_save_list_finished_cb (EAttachment *attachment, - GAsyncResult *result, - SaveContext *save_context) +attachment_store_get_uris_save_cb (EAttachment *attachment, + GAsyncResult *result, + UriContext *uri_context) { - GFile *file; GSimpleAsyncResult *simple; + GFile *file; + gchar **uris; + gchar *uri; GError *error = NULL; 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 ( - save_context->attachment_list, attachment); + uri_context->attachment_list = g_list_remove ( + uri_context->attachment_list, attachment); g_object_unref (attachment); - /* If this is the first error, cancel the other jobs. */ - if (error != NULL && save_context->error == NULL) { - g_propagate_error (&save_context->error, error); - g_list_foreach ( - save_context->attachment_list, - (GFunc) e_attachment_cancel, NULL); + if (file != NULL) { + uri = g_file_get_uri (file); + uri_context->uris[uri_context->index++] = uri; + g_object_unref (file); - /* Otherwise, we can only report back one error. So if this is - * something other than cancellation, dump it to the terminal. */ - } else if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - g_warning ("%s", error->message); + } else if (error != NULL) { + /* If this is the first error, cancel the other jobs. */ + if (uri_context->error == NULL) { + g_propagate_error (&uri_context->error, error); + g_list_foreach ( + uri_context->attachment_list, + (GFunc) e_attachment_cancel, NULL); + + /* Otherwise, we can only report back one error. So if + * this is something other than cancellation, dump it to + * the terminal. */ + } else if (!g_error_matches ( + error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + g_warning ("%s", error->message); - if (error != NULL) g_error_free (error); + } /* If there's still jobs running, let them finish. */ - if (save_context->attachment_list != NULL) + if (uri_context->attachment_list != NULL) return; /* Steal the result. */ - simple = save_context->simple; - save_context->simple = NULL; + simple = uri_context->simple; + uri_context->simple = NULL; - /* Steal the error, too. */ - error = save_context->error; - save_context->error = NULL; + /* And the URI list. */ + uris = uri_context->uris; + uri_context->uris = NULL; + + /* And the error. */ + error = uri_context->error; + uri_context->error = NULL; if (error == NULL) - g_simple_async_result_set_op_res_gboolean (simple, TRUE); + g_simple_async_result_set_op_res_gpointer (simple, uris, NULL); else { g_simple_async_result_set_from_error (simple, error); g_error_free (error); @@ -839,63 +751,109 @@ attachment_store_save_list_finished_cb (EAttachment *attachment, g_simple_async_result_complete (simple); - attachment_store_save_context_free (save_context); + attachment_store_uri_context_free (uri_context); } void -e_attachment_store_save_list_async (EAttachmentStore *store, - GList *attachment_list, - GFile *destination, - GAsyncReadyCallback callback, - gpointer user_data) +e_attachment_store_get_uris_async (EAttachmentStore *store, + GList *attachment_list, + GAsyncReadyCallback callback, + gpointer user_data) { - SaveContext *save_context; + GFile *temp_directory; + UriContext *uri_context; + GList *iter, *trash = NULL; + gchar *template; + gchar *path; g_return_if_fail (E_IS_ATTACHMENT_STORE (store)); - g_return_if_fail (G_IS_FILE (destination)); g_return_if_fail (callback != NULL); - /* Passing an empty list is silly, but we'll handle it. */ - if (attachment_list == NULL) { + uri_context = attachment_store_uri_context_new ( + store, attachment_list, callback, user_data); + + /* Grab the copied attachment list. */ + attachment_list = uri_context->attachment_list; + + /* First scan the list for attachments with a GFile. */ + for (iter = attachment_list; iter != NULL; iter = iter->next) { + EAttachment *attachment = iter->data; + GFile *file; + gchar *uri; + + file = e_attachment_get_file (attachment); + if (file == NULL) + continue; + + uri = g_file_get_uri (file); + uri_context->uris[uri_context->index++] = uri; + + /* Mark the list node for deletion. */ + trash = g_list_prepend (trash, iter); + g_object_unref (attachment); + } + + /* Expunge the list. */ + for (iter = trash; iter != NULL; iter = iter->next) { + GList *link = iter->data; + attachment_list = g_list_delete_link (attachment_list, link); + } + g_list_free (trash); + + uri_context->attachment_list = attachment_list; + + /* Any remaining attachments in the list should have MIME parts + * only, so we need to save them all to a temporary directory. + * We use a directory so the files can retain their basenames. */ + template = g_strdup_printf (PACKAGE "-%s-XXXXXX", g_get_user_name ()); + path = e_mkdtemp (template); + g_free (template); + + if (path == NULL) { GSimpleAsyncResult *simple; - simple = g_simple_async_result_new ( - G_OBJECT (store), callback, user_data, - e_attachment_store_save_list_async); - g_simple_async_result_set_op_res_gboolean (simple, TRUE); + /* Steal the result. */ + simple = uri_context->simple; + uri_context->simple = NULL; + + g_simple_async_result_set_error ( + simple, G_FILE_ERROR, + g_file_error_from_errno (errno), + "%s", g_strerror (errno)); + g_simple_async_result_complete_in_idle (simple); + attachment_store_uri_context_free (uri_context); return; } - save_context = attachment_store_save_context_new ( - store, attachment_list, callback, user_data); + temp_directory = g_file_new_for_path (path); - while (attachment_list != NULL) { + for (iter = attachment_list; iter != NULL; iter = iter->next) e_attachment_save_async ( - E_ATTACHMENT (attachment_list->data), - destination, (GAsyncReadyCallback) - attachment_store_save_list_finished_cb, - save_context); - attachment_list = g_list_next (attachment_list); - } + E_ATTACHMENT (iter->data), + temp_directory, (GAsyncReadyCallback) + attachment_store_get_uris_save_cb, + uri_context); + + g_object_unref (temp_directory); } -gboolean -e_attachment_store_save_list_finish (EAttachmentStore *store, - GAsyncResult *result, - GError **error) +gchar ** +e_attachment_store_get_uris_finish (EAttachmentStore *store, + GAsyncResult *result, + GError **error) { GSimpleAsyncResult *simple; - gboolean success; + gchar **uris; g_return_val_if_fail ( g_simple_async_result_is_valid (result, G_OBJECT (store), - e_attachment_store_save_list_async), FALSE); + e_attachment_store_get_uris_async), FALSE); simple = G_SIMPLE_ASYNC_RESULT (result); - success = g_simple_async_result_get_op_res_gboolean (simple); + uris = g_simple_async_result_get_op_res_gpointer (simple); g_simple_async_result_propagate_error (simple, error); g_object_unref (simple); - return success; + return uris; } diff --git a/widgets/misc/e-attachment-store.h b/widgets/misc/e-attachment-store.h index c672cb3c34..a6dd702b97 100644 --- a/widgets/misc/e-attachment-store.h +++ b/widgets/misc/e-attachment-store.h @@ -107,13 +107,12 @@ GFile * e_attachment_store_run_save_dialog GtkWindow *parent); /* Asynchronous Operations */ -void e_attachment_store_save_list_async +void e_attachment_store_get_uris_async (EAttachmentStore *store, GList *attachment_list, - GFile *destination, GAsyncReadyCallback callback, gpointer user_data); -gboolean e_attachment_store_save_list_finish +gchar ** e_attachment_store_get_uris_finish (EAttachmentStore *store, GAsyncResult *result, GError **error); diff --git a/widgets/misc/e-attachment-view.c b/widgets/misc/e-attachment-view.c index b2dc62b934..d6dff653cc 100644 --- a/widgets/misc/e-attachment-view.c +++ b/widgets/misc/e-attachment-view.c @@ -36,38 +36,11 @@ enum { LAST_SIGNAL }; -enum { - DND_TYPE_MESSAGE_RFC822, - DND_TYPE_X_UID_LIST, - DND_TYPE_TEXT_URI_LIST, - DND_TYPE_NETSCAPE_URL, - DND_TYPE_TEXT_VCARD, - DND_TYPE_TEXT_CALENDAR -}; - -static GtkTargetEntry drop_types[] = { - { "message/rfc822", 0, DND_TYPE_MESSAGE_RFC822 }, - { "x-uid-list", 0, DND_TYPE_X_UID_LIST }, - { "text/uri-list", 0, DND_TYPE_TEXT_URI_LIST }, - { "_NETSCAPE_URL", 0, DND_TYPE_NETSCAPE_URL }, - { "text/x-vcard", 0, DND_TYPE_TEXT_VCARD }, - { "text/calendar", 0, DND_TYPE_TEXT_CALENDAR } -}; - -/* The atoms need initialized at runtime. */ -static struct { - const gchar *target; - GdkAtom atom; - GdkDragAction actions; -} drag_info[] = { - { "message/rfc822", NULL, GDK_ACTION_COPY }, - { "x-uid-list", NULL, GDK_ACTION_COPY | - GDK_ACTION_MOVE | - GDK_ACTION_ASK }, - { "text/uri-list", NULL, GDK_ACTION_COPY }, - { "_NETSCAPE_URL", NULL, GDK_ACTION_COPY }, - { "text/x-vcard", NULL, GDK_ACTION_COPY }, - { "text/calendar", NULL, GDK_ACTION_COPY } +/* Note: Do not use the info field. */ +static GtkTargetEntry target_table[] = { + { "_NETSCAPE_URL", 0, 0 }, + { "text/x-vcard", 0, 0 }, + { "text/calendar", 0, 0 } }; static const gchar *ui = @@ -84,12 +57,6 @@ static const gchar *ui = " <separator/>" " <placeholder name='open-actions'/>" " </popup>" -" <popup name='dnd'>" -" <menuitem action='drag-copy'/>" -" <menuitem action='drag-move'/>" -" <separator/>" -" <menuitem action='drag-cancel'/>" -" </popup>" "</ui>"; static gulong signals[LAST_SIGNAL]; @@ -126,30 +93,6 @@ action_cancel_cb (GtkAction *action, } static void -action_drag_cancel_cb (GtkAction *action, - EAttachmentView *view) -{ - EAttachmentViewPrivate *priv; - - priv = e_attachment_view_get_private (view); - gtk_drag_finish (priv->drag_context, FALSE, FALSE, priv->time); -} - -static void -action_drag_copy_cb (GtkAction *action, - EAttachmentView *view) -{ - e_attachment_view_drag_action (view, GDK_ACTION_COPY); -} - -static void -action_drag_move_cb (GtkAction *action, - EAttachmentView *view) -{ - e_attachment_view_drag_action (view, GDK_ACTION_MOVE); -} - -static void action_open_in_cb (GtkAction *action, EAttachmentView *view) { @@ -312,27 +255,6 @@ static GtkActionEntry standard_entries[] = { NULL, /* XXX Add a tooltip! */ G_CALLBACK (action_cancel_cb) }, - { "drag-cancel", - NULL, - N_("Cancel _Drag"), - NULL, - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_drag_cancel_cb) }, - - { "drag-copy", - NULL, - N_("_Copy"), - NULL, - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_drag_copy_cb) }, - - { "drag-move", - NULL, - N_("_Move"), - NULL, - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_drag_move_cb) }, - { "save-all", GTK_STOCK_SAVE_AS, N_("S_ave All"), @@ -382,159 +304,153 @@ static GtkActionEntry editable_entries[] = { }; static void -drop_message_rfc822 (EAttachmentView *view, - GtkSelectionData *selection_data, - EAttachmentStore *store, - GdkDragAction action) +attachment_view_netscape_url (EAttachmentView *view, + GdkDragContext *drag_context, + gint x, + gint y, + GtkSelectionData *selection_data, + guint info, + guint time) { - EAttachmentViewPrivate *priv; + static GdkAtom atom = GDK_NONE; + EAttachmentStore *store; EAttachment *attachment; - CamelMimeMessage *message; - CamelDataWrapper *wrapper; - CamelStream *stream; const gchar *data; - gboolean success = FALSE; - gboolean delete = FALSE; gpointer parent; + gchar *copied_data; + gchar **strv; gint length; - priv = e_attachment_view_get_private (view); + if (G_UNLIKELY (atom == GDK_NONE)) + atom = gdk_atom_intern_static_string ("_NETSCAPE_URL"); + + if (gtk_selection_data_get_target (selection_data) != atom) + return; + + g_signal_stop_emission_by_name (view, "drag-data-received"); + + /* _NETSCAPE_URL is represented as "URI\nTITLE" */ data = (const gchar *) gtk_selection_data_get_data (selection_data); length = gtk_selection_data_get_length (selection_data); - stream = camel_stream_mem_new (); - camel_stream_write (stream, data, length); - camel_stream_reset (stream); - - message = camel_mime_message_new (); - wrapper = CAMEL_DATA_WRAPPER (message); + copied_data = g_strndup (data, length); + strv = g_strsplit (copied_data, "\n", 2); + g_free (copied_data); - if (camel_data_wrapper_construct_from_stream (wrapper, stream) == -1) - goto exit; + store = e_attachment_view_get_store (view); parent = gtk_widget_get_toplevel (GTK_WIDGET (view)); parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL; - attachment = e_attachment_new_for_message (message); + attachment = e_attachment_new_for_uri (strv[0]); e_attachment_store_add_attachment (store, attachment); e_attachment_load_async ( attachment, (GAsyncReadyCallback) e_attachment_load_handle_error, parent); g_object_unref (attachment); - success = TRUE; - delete = (action == GDK_ACTION_MOVE); - -exit: - camel_object_unref (message); - camel_object_unref (stream); + g_strfreev (strv); - gtk_drag_finish (priv->drag_context, success, delete, priv->time); + gtk_drag_finish (drag_context, TRUE, FALSE, time); } static void -drop_netscape_url (EAttachmentView *view, - GtkSelectionData *selection_data, - EAttachmentStore *store, - GdkDragAction action) +attachment_view_text_calendar (EAttachmentView *view, + GdkDragContext *drag_context, + gint x, + gint y, + GtkSelectionData *selection_data, + guint info, + guint time) { - EAttachmentViewPrivate *priv; + static GdkAtom atom = GDK_NONE; + EAttachmentStore *store; EAttachment *attachment; + CamelMimePart *mime_part; + GdkAtom data_type; const gchar *data; gpointer parent; - gchar *copied_data; - gchar **strv; + gchar *content_type; gint length; - /* _NETSCAPE_URL is represented as "URI\nTITLE" */ + if (G_UNLIKELY (atom = GDK_NONE)) + atom = gdk_atom_intern_static_string ("text/calendar"); - priv = e_attachment_view_get_private (view); + if (gtk_selection_data_get_target (selection_data) != atom) + return; + + g_signal_stop_emission_by_name (view, "drag-data-received"); data = (const gchar *) gtk_selection_data_get_data (selection_data); length = gtk_selection_data_get_length (selection_data); + data_type = gtk_selection_data_get_data_type (selection_data); - copied_data = g_strndup (data, length); - strv = g_strsplit (copied_data, "\n", 2); - g_free (copied_data); + mime_part = camel_mime_part_new (); + + content_type = gdk_atom_name (data_type); + camel_mime_part_set_content (mime_part, data, length, content_type); + camel_mime_part_set_disposition (mime_part, "inline"); + g_free (content_type); + + store = e_attachment_view_get_store (view); parent = gtk_widget_get_toplevel (GTK_WIDGET (view)); parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL; - attachment = e_attachment_new_for_uri (strv[0]); + attachment = e_attachment_new (); + e_attachment_set_mime_part (attachment, mime_part); e_attachment_store_add_attachment (store, attachment); e_attachment_load_async ( attachment, (GAsyncReadyCallback) e_attachment_load_handle_error, parent); g_object_unref (attachment); - g_strfreev (strv); - - gtk_drag_finish (priv->drag_context, TRUE, FALSE, priv->time); -} - -static void -drop_text_uri_list (EAttachmentView *view, - GtkSelectionData *selection_data, - EAttachmentStore *store, - GdkDragAction action) -{ - EAttachmentViewPrivate *priv; - gpointer parent; - gchar **uris; - gint ii; - - priv = e_attachment_view_get_private (view); - - uris = gtk_selection_data_get_uris (selection_data); - - parent = gtk_widget_get_toplevel (GTK_WIDGET (view)); - parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL; - - for (ii = 0; uris[ii] != NULL; ii++) { - EAttachment *attachment; - - attachment = e_attachment_new_for_uri (uris[ii]); - e_attachment_store_add_attachment (store, attachment); - e_attachment_load_async ( - attachment, (GAsyncReadyCallback) - e_attachment_load_handle_error, parent); - g_object_unref (attachment); - } - - g_strfreev (uris); + camel_object_unref (mime_part); - gtk_drag_finish (priv->drag_context, TRUE, FALSE, priv->time); + gtk_drag_finish (drag_context, TRUE, FALSE, time); } static void -drop_text_generic (EAttachmentView *view, - GtkSelectionData *selection_data, - EAttachmentStore *store, - GdkDragAction action) +attachment_view_text_x_vcard (EAttachmentView *view, + GdkDragContext *drag_context, + gint x, + gint y, + GtkSelectionData *selection_data, + guint info, + guint time) { - EAttachmentViewPrivate *priv; + static GdkAtom atom = GDK_NONE; + EAttachmentStore *store; EAttachment *attachment; CamelMimePart *mime_part; - GdkAtom atom; + GdkAtom data_type; const gchar *data; gpointer parent; gchar *content_type; gint length; - priv = e_attachment_view_get_private (view); + if (G_UNLIKELY (atom = GDK_NONE)) + atom = gdk_atom_intern_static_string ("text/x-vcard"); + + if (gtk_selection_data_get_target (selection_data) != atom) + return; + + g_signal_stop_emission_by_name (view, "drag-data-received"); data = (const gchar *) gtk_selection_data_get_data (selection_data); length = gtk_selection_data_get_length (selection_data); - atom = gtk_selection_data_get_data_type (selection_data); + data_type = gtk_selection_data_get_data_type (selection_data); mime_part = camel_mime_part_new (); - content_type = gdk_atom_name (atom); + content_type = gdk_atom_name (data_type); camel_mime_part_set_content (mime_part, data, length, content_type); camel_mime_part_set_disposition (mime_part, "inline"); g_free (content_type); + store = e_attachment_view_get_store (view); + parent = gtk_widget_get_toplevel (GTK_WIDGET (view)); parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL; @@ -548,22 +464,49 @@ drop_text_generic (EAttachmentView *view, camel_object_unref (mime_part); - gtk_drag_finish (priv->drag_context, TRUE, FALSE, priv->time); + gtk_drag_finish (drag_context, TRUE, FALSE, time); } static void -drop_x_uid_list (EAttachmentView *view, - GtkSelectionData *selection_data, - EAttachmentStore *store, - GdkDragAction action) +attachment_view_uris (EAttachmentView *view, + GdkDragContext *drag_context, + gint x, + gint y, + GtkSelectionData *selection_data, + guint info, + guint time) { - EAttachmentViewPrivate *priv; + EAttachmentStore *store; + gpointer parent; + gchar **uris; + gint ii; - /* FIXME Ugh, this looks painful. Requires mailer stuff. */ + uris = gtk_selection_data_get_uris (selection_data); - priv = e_attachment_view_get_private (view); + if (uris == NULL) + return; + + g_signal_stop_emission_by_name (view, "drag-data-received"); + + store = e_attachment_view_get_store (view); + + parent = gtk_widget_get_toplevel (GTK_WIDGET (view)); + parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL; + + for (ii = 0; uris[ii] != NULL; ii++) { + EAttachment *attachment; + + attachment = e_attachment_new_for_uri (uris[ii]); + e_attachment_store_add_attachment (store, attachment); + e_attachment_load_async ( + attachment, (GAsyncReadyCallback) + e_attachment_load_handle_error, parent); + g_object_unref (attachment); + } - gtk_drag_finish (priv->drag_context, FALSE, FALSE, priv->time); + g_strfreev (uris); + + gtk_drag_finish (drag_context, TRUE, FALSE, time); } static void @@ -669,10 +612,48 @@ attachment_view_update_actions (EAttachmentView *view) } static void -attachment_view_class_init (EAttachmentViewIface *iface) +attachment_view_init_handlers (EAttachmentView *view) { - gint ii; + EAttachmentViewPrivate *priv; + GtkTargetList *target_list; + GType *children; + guint ii; + + priv = e_attachment_view_get_private (view); + + target_list = gtk_target_list_new ( + target_table, G_N_ELEMENTS (target_table)); + + gtk_target_list_add_uri_targets (target_list, 0); + + priv->handlers = g_ptr_array_new (); + priv->target_list = target_list; + priv->drag_actions = GDK_ACTION_COPY; + + children = g_type_children (E_TYPE_ATTACHMENT_HANDLER, NULL); + + for (ii = 0; children[ii] != G_TYPE_INVALID; ii++) { + EAttachmentHandler *handler; + const GtkTargetEntry *targets; + guint n_targets; + + handler = g_object_new (children[ii], "view", view, NULL); + targets = e_attachment_handler_get_target_table ( + handler, &n_targets); + gtk_target_list_add_table (target_list, targets, n_targets); + priv->drag_actions |= + e_attachment_handler_get_drag_actions (handler); + + g_ptr_array_add (priv->handlers, handler); + } + + g_free (children); +} + +static void +attachment_view_class_init (EAttachmentViewIface *iface) +{ iface->update_actions = attachment_view_update_actions; g_object_interface_install_property ( @@ -693,11 +674,6 @@ attachment_view_class_init (EAttachmentViewIface *iface) 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); - } } GType @@ -738,15 +714,10 @@ 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); - e_attachment_view_drag_source_set (view); - e_attachment_view_drag_dest_set (view); - ui_manager = gtk_ui_manager_new (); priv->merge_id = gtk_ui_manager_new_merge_id (ui_manager); priv->ui_manager = ui_manager; @@ -783,14 +754,28 @@ e_attachment_view_init (EAttachmentView *view) G_OBJECT (view), "editable", G_OBJECT (priv->editable_actions), "visible"); - /* 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); + attachment_view_init_handlers (view); + + e_attachment_view_drag_source_set (view); + e_attachment_view_drag_dest_set (view); + + /* Connect built-in drag and drop handlers. */ + + g_signal_connect ( + view, "drag-data-received", + G_CALLBACK (attachment_view_netscape_url), NULL); + + g_signal_connect ( + view, "drag-data-received", + G_CALLBACK (attachment_view_text_calendar), NULL); + + g_signal_connect ( + view, "drag-data-received", + G_CALLBACK (attachment_view_text_x_vcard), NULL); + + g_signal_connect ( + view, "drag-data-received", + G_CALLBACK (attachment_view_uris), NULL); } void @@ -800,9 +785,13 @@ 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; + g_ptr_array_foreach (priv->handlers, (GFunc) g_object_unref, NULL); + g_ptr_array_set_size (priv->handlers, 0); + + if (priv->target_list != NULL) { + gtk_target_list_unref (priv->target_list); + priv->target_list = NULL; + } if (priv->ui_manager != NULL) { g_object_unref (priv->ui_manager); @@ -823,11 +812,6 @@ e_attachment_view_dispose (EAttachmentView *view) g_object_unref (priv->openwith_actions); priv->openwith_actions = NULL; } - - if (priv->drag_context != NULL) { - g_object_unref (priv->drag_context); - priv->drag_context = NULL; - } } void @@ -837,8 +821,7 @@ e_attachment_view_finalize (EAttachmentView *view) priv = e_attachment_view_get_private (view); - if (priv->selection_data != NULL) - gtk_selection_data_free (priv->selection_data); + g_ptr_array_free (priv->handlers, TRUE); } EAttachmentViewPrivate * @@ -893,6 +876,30 @@ e_attachment_view_set_editable (EAttachmentView *view, g_object_notify (G_OBJECT (view), "editable"); } +GtkTargetList * +e_attachment_view_get_target_list (EAttachmentView *view) +{ + EAttachmentViewPrivate *priv; + + g_return_val_if_fail (E_IS_ATTACHMENT_VIEW (view), NULL); + + priv = e_attachment_view_get_private (view); + + return priv->target_list; +} + +GdkDragAction +e_attachment_view_get_drag_actions (EAttachmentView *view) +{ + EAttachmentViewPrivate *priv; + + g_return_val_if_fail (E_IS_ATTACHMENT_VIEW (view), 0); + + priv = e_attachment_view_get_private (view); + + return priv->drag_actions; +} + GList * e_attachment_view_get_selected_attachments (EAttachmentView *view) { @@ -1257,6 +1264,24 @@ e_attachment_view_drag_end (EAttachmentView *view, g_return_if_fail (GDK_IS_DRAG_CONTEXT (context)); } +static void +attachment_view_got_uris_cb (EAttachmentStore *store, + GAsyncResult *result, + gpointer user_data) +{ + struct { + gchar **uris; + gboolean done; + } *status = user_data; + + /* XXX Since this is a best-effort function, + * should we care about errors? */ + status->uris = e_attachment_store_get_uris_finish ( + store, result, NULL); + + status->done = TRUE; +} + void e_attachment_view_drag_data_get (EAttachmentView *view, GdkDragContext *context, @@ -1264,56 +1289,65 @@ e_attachment_view_drag_data_get (EAttachmentView *view, guint info, guint time) { - GList *selected, *iter; - gchar **uris; - gint ii = 0; + EAttachmentStore *store; + GList *selected; + + struct { + gchar **uris; + gboolean done; + } status; g_return_if_fail (E_IS_ATTACHMENT_VIEW (view)); g_return_if_fail (GDK_IS_DRAG_CONTEXT (context)); g_return_if_fail (selection != NULL); + status.uris = NULL; + status.done = FALSE; + + store = e_attachment_view_get_store (view); + selected = e_attachment_view_get_selected_attachments (view); if (selected == NULL) return; - uris = g_malloc0 (sizeof (gchar *) * (g_list_length (selected) + 1)); + e_attachment_store_get_uris_async ( + store, selected, (GAsyncReadyCallback) + attachment_view_got_uris_cb, &status); - for (iter = selected; iter != NULL; iter = iter->next) { - EAttachment *attachment = iter->data; - GFile *file; - - /* FIXME Need to handle attachments with no GFile. */ - file = e_attachment_get_file (attachment); - if (file == NULL) - continue; + g_list_foreach (selected, (GFunc) g_object_unref, NULL); + g_list_free (selected); - uris[ii++] = g_file_get_uri (file); - } + /* We can't return until we have results, so crank + * the main loop until the callback gets triggered. */ + while (!status.done) + if (gtk_main_iteration ()) + break; - gtk_selection_data_set_uris (selection, uris); + if (status.uris != NULL) + gtk_selection_data_set_uris (selection, status.uris); - g_strfreev (uris); + g_strfreev (status.uris); } void e_attachment_view_drag_dest_set (EAttachmentView *view) { + EAttachmentViewPrivate *priv; GtkTargetEntry *targets; - GtkTargetList *list; gint n_targets; g_return_if_fail (E_IS_ATTACHMENT_VIEW (view)); - list = gtk_target_list_new (NULL, 0); - /* FIXME Add targets here... */ - targets = gtk_target_table_new_from_list (list, &n_targets); + priv = e_attachment_view_get_private (view); + + targets = gtk_target_table_new_from_list ( + priv->target_list, &n_targets); gtk_drag_dest_set ( GTK_WIDGET (view), GTK_DEST_DEFAULT_ALL, - targets, n_targets, GDK_ACTION_COPY); + targets, n_targets, priv->drag_actions); gtk_target_table_free (targets, n_targets); - gtk_target_list_unref (list); } void @@ -1324,61 +1358,6 @@ e_attachment_view_drag_dest_unset (EAttachmentView *view) gtk_drag_dest_unset (GTK_WIDGET (view)); } -void -e_attachment_view_drag_action (EAttachmentView *view, - GdkDragAction action) -{ - EAttachmentViewPrivate *priv; - GtkSelectionData *selection_data; - EAttachmentStore *store; - GdkAtom atom; - gchar *name; - - g_return_if_fail (E_IS_ATTACHMENT_VIEW (view)); - - priv = e_attachment_view_get_private (view); - - selection_data = priv->selection_data; - store = e_attachment_view_get_store (view); - atom = gtk_selection_data_get_data_type (selection_data); - - switch (priv->info) { - case DND_TYPE_MESSAGE_RFC822: - drop_message_rfc822 ( - view, selection_data, store, action); - return; - - case DND_TYPE_NETSCAPE_URL: - drop_netscape_url ( - view, selection_data, store, action); - return; - - case DND_TYPE_TEXT_URI_LIST: - drop_text_uri_list ( - view, selection_data, store, action); - return; - - case DND_TYPE_TEXT_VCARD: - case DND_TYPE_TEXT_CALENDAR: - drop_text_generic ( - view, selection_data, store, action); - return; - - case DND_TYPE_X_UID_LIST: - drop_x_uid_list ( - view, selection_data, store, action); - return; - - default: - name = gdk_atom_name (atom); - g_warning ("Unknown drag type: %s", name); - g_free (name); - break; - } - - gtk_drag_finish (priv->drag_context, FALSE, FALSE, priv->time); -} - gboolean e_attachment_view_drag_motion (EAttachmentView *view, GdkDragContext *context, @@ -1386,27 +1365,20 @@ e_attachment_view_drag_motion (EAttachmentView *view, gint y, guint time) { - GList *iter; - GdkDragAction actions = 0; + EAttachmentViewPrivate *priv; + GdkDragAction actions; GdkDragAction chosen_action; g_return_val_if_fail (E_IS_ATTACHMENT_VIEW (view), FALSE); g_return_val_if_fail (GDK_IS_DRAG_CONTEXT (context), FALSE); + priv = e_attachment_view_get_private (view); + /* Disallow drops if we're not editable. */ if (!e_attachment_view_get_editable (view)) return FALSE; - for (iter = context->targets; iter != NULL; iter = iter->next) { - GdkAtom atom = iter->data; - gint ii; - - for (ii = 0; ii < G_N_ELEMENTS (drag_info); ii++) - if (atom == drag_info[ii].atom) - actions |= drag_info[ii].actions; - } - - actions &= context->actions; + actions = priv->drag_actions & context->actions; chosen_action = context->suggested_action; if (chosen_action == GDK_ACTION_ASK) { @@ -1441,53 +1413,31 @@ e_attachment_view_drag_drop (EAttachmentView *view, void e_attachment_view_drag_data_received (EAttachmentView *view, - GdkDragContext *context, + GdkDragContext *drag_context, gint x, gint y, - GtkSelectionData *selection, + GtkSelectionData *selection_data, guint info, guint time) { - EAttachmentViewPrivate *priv; - GtkUIManager *ui_manager; - GdkDragAction action; + GdkAtom atom; + gchar *name; g_return_if_fail (E_IS_ATTACHMENT_VIEW (view)); - g_return_if_fail (GDK_IS_DRAG_CONTEXT (context)); - g_return_if_fail (selection != NULL); - - priv = e_attachment_view_get_private (view); - ui_manager = e_attachment_view_get_ui_manager (view); + g_return_if_fail (GDK_IS_DRAG_CONTEXT (drag_context)); - action = context->action; + /* Drop handlers are supposed to stop further emission of the + * "drag-data-received" signal if they can handle the data. If + * we get this far it means none of the handlers were successful, + * so report the drop as failed. */ - if (gtk_selection_data_get_data (selection) == NULL) - return; - - if (gtk_selection_data_get_length (selection) == -1) - return; - - if (priv->drag_context != NULL) - g_object_unref (priv->drag_context); - - if (priv->selection_data != NULL) - gtk_selection_data_free (priv->selection_data); + atom = gtk_selection_data_get_target (selection_data); - priv->drag_context = g_object_ref (context); - priv->selection_data = gtk_selection_data_copy (selection); - priv->info = info; - priv->time = time; + name = gdk_atom_name (atom); + g_warning ("Unknown selection target: %s", name); + g_free (name); - if (action == GDK_ACTION_ASK) { - GtkWidget *menu; - - menu = gtk_ui_manager_get_widget (ui_manager, "/dnd"); - g_return_if_fail (GTK_IS_MENU (menu)); - - gtk_menu_popup ( - GTK_MENU (menu), NULL, NULL, NULL, NULL, 0, time); - } else - e_attachment_view_drag_action (view, action); + gtk_drag_finish (drag_context, FALSE, FALSE, time); } GtkAction * diff --git a/widgets/misc/e-attachment-view.h b/widgets/misc/e-attachment-view.h index 16a7ac1967..8b625d0d8a 100644 --- a/widgets/misc/e-attachment-view.h +++ b/widgets/misc/e-attachment-view.h @@ -93,7 +93,11 @@ struct _EAttachmentViewIface { struct _EAttachmentViewPrivate { /* Attachment Handlers */ - GList *handlers; + GPtrArray *handlers; + + /* Drag Destination */ + GtkTargetList *target_list; + GdkDragAction drag_actions; /* Popup Menu Management */ GtkUIManager *ui_manager; @@ -102,12 +106,6 @@ struct _EAttachmentViewPrivate { GtkActionGroup *openwith_actions; guint merge_id; - /* Drag and Drop State */ - GdkDragContext *drag_context; - GtkSelectionData *selection_data; - guint info; - guint time; - guint editable : 1; }; @@ -124,6 +122,10 @@ EAttachmentStore * gboolean e_attachment_view_get_editable (EAttachmentView *view); void e_attachment_view_set_editable (EAttachmentView *view, gboolean editable); +GtkTargetList * e_attachment_view_get_target_list + (EAttachmentView *view); +GdkDragAction e_attachment_view_get_drag_actions + (EAttachmentView *view); GList * e_attachment_view_get_selected_attachments (EAttachmentView *view); void e_attachment_view_open_path (EAttachmentView *view, @@ -182,8 +184,6 @@ void e_attachment_view_drag_data_get (EAttachmentView *view, void e_attachment_view_drag_dest_set (EAttachmentView *view); void e_attachment_view_drag_dest_unset (EAttachmentView *view); -void e_attachment_view_drag_action (EAttachmentView *view, - GdkDragAction action); gboolean e_attachment_view_drag_motion (EAttachmentView *view, GdkDragContext *context, gint x, diff --git a/widgets/misc/e-attachment.c b/widgets/misc/e-attachment.c index fb84261fa2..bd9795c908 100644 --- a/widgets/misc/e-attachment.c +++ b/widgets/misc/e-attachment.c @@ -22,6 +22,7 @@ #include "e-attachment.h" #include <errno.h> +#include <config.h> #include <glib/gi18n.h> #include <camel/camel-iconv.h> #include <camel/camel-data-wrapper.h> @@ -32,6 +33,7 @@ #include <camel/camel-stream-vfs.h> #include "e-util/e-util.h" +#include "e-util/e-mktemp.h" #include "e-attachment-store.h" #define E_ATTACHMENT_GET_PRIVATE(obj) \ @@ -1914,18 +1916,30 @@ static void attachment_open_save_temporary (OpenContext *open_context) { GFile *file; + gchar *template; gchar *path; - gint fd; GError *error = NULL; - fd = e_file_open_tmp (&path, &error); + errno = 0; + /* XXX This could trigger a blocking temp directory cleanup. */ + template = g_strdup_printf (PACKAGE "-%s-XXXXXX", g_get_user_name ()); + path = e_mktemp (template); + g_free (template); + + /* XXX Let's hope errno got set properly. */ + if (path == NULL) + g_set_error ( + &error, G_FILE_ERROR, + g_file_error_from_errno (errno), + "%s", g_strerror (errno)); + + /* We already know if there's an error, but this does the cleanup. */ if (attachment_open_check_for_error (open_context, error)) return; file = g_file_new_for_path (path); - close (fd); g_free (path); e_attachment_save_async ( @@ -2519,8 +2533,11 @@ e_attachment_save_handle_error (EAttachment *attachment, g_return_if_fail (GTK_IS_WINDOW (parent)); file = e_attachment_save_finish (attachment, result, &error); - if (file != NULL) + + if (file != NULL) { g_object_unref (file); + return; + } /* Ignore cancellations. */ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) diff --git a/widgets/misc/e-mime-part-utils.c b/widgets/misc/e-mime-part-utils.c deleted file mode 100644 index 3238ca93f5..0000000000 --- a/widgets/misc/e-mime-part-utils.c +++ /dev/null @@ -1,223 +0,0 @@ -/* - * e-mime-part-utils.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-mime-part-utils.h" - -#include <errno.h> -#include <gio/gio.h> -#include <glib/gi18n.h> -#include <camel/camel-stream-vfs.h> - -#include "e-util/e-util.h" - -static void -mime_part_utils_open_in_cb (GtkAction *action, - CamelMimePart *mime_part) -{ - GtkWindow *parent; - GFile *file; - gchar *path; - gchar *uri; - gint fd; - GError *error = NULL; - - parent = g_object_get_data (G_OBJECT (action), "parent-window"); - - fd = e_file_open_tmp (&path, &error); - if (error != NULL) - goto fail; - - close (fd); - - file = g_file_new_for_path (path); - e_mime_part_utils_save_to_file (mime_part, file, &error); - g_free (path); - - if (error != NULL) { - g_object_unref (file); - goto fail; - } - - uri = g_file_get_uri (file); - e_show_uri (parent, uri); - g_free (uri); - - g_object_unref (file); - - return; - -fail: - g_warning ("%s", error->message); - g_error_free (error); -} - -GList * -e_mime_part_utils_get_apps (CamelMimePart *mime_part) -{ - GList *app_info_list; - const gchar *filename; - gchar *content_type; - gchar *mime_type; - gchar *cp; - - g_return_val_if_fail (CAMEL_IS_MIME_PART (mime_part), NULL); - - filename = camel_mime_part_get_filename (mime_part); - mime_type = camel_content_type_simple ( - camel_mime_part_get_content_type (mime_part)); - g_return_val_if_fail (mime_type != NULL, NULL); - - /* GIO expects lowercase MIME types. */ - for (cp = mime_type; *cp != '\0'; cp++) - *cp = g_ascii_tolower (*cp); - - content_type = g_content_type_from_mime_type (mime_type); - if (content_type != NULL) - app_info_list = g_app_info_get_all_for_type (content_type); - else - app_info_list = g_app_info_get_all_for_type (mime_type); - g_free (content_type); - - if (app_info_list != NULL || filename == NULL) - goto exit; - - if (strcmp (mime_type, "application/octet-stream") != 0) - goto exit; - - content_type = g_content_type_guess (filename, NULL, 0, NULL); - app_info_list = g_app_info_get_all_for_type (content_type); - g_free (content_type); - -exit: - g_free (mime_type); - - return app_info_list; -} - -gboolean -e_mime_part_utils_save_to_file (CamelMimePart *mime_part, - GFile *file, - GError **error) -{ - GFileOutputStream *output_stream; - CamelDataWrapper *content; - CamelStream *stream; - - g_return_val_if_fail (CAMEL_IS_MIME_PART (mime_part), FALSE); - g_return_val_if_fail (G_IS_FILE (file), FALSE); - - output_stream = g_file_replace ( - file, NULL, FALSE, G_FILE_CREATE_NONE, NULL, error); - if (output_stream == NULL) - return FALSE; - - /* The CamelStream takes ownership of the GFileOutputStream. */ - content = camel_medium_get_content_object (CAMEL_MEDIUM (mime_part)); - stream = camel_stream_vfs_new_with_stream (G_OBJECT (output_stream)); - - /* XXX Camel's streams are synchronous only, so we have to write - * the whole thing in one shot and hope it doesn't block the - * main loop for too long. */ - if (camel_data_wrapper_decode_to_stream (content, stream) < 0) - goto file_error; - - if (camel_stream_flush (stream) < 0) - goto file_error; - - camel_object_unref (stream); - - return TRUE; - -file_error: - g_set_error ( - error, G_FILE_ERROR, - g_file_error_from_errno (errno), - "%s", g_strerror (errno)); - - camel_object_unref (stream); - - return FALSE; -} - -void -e_mime_part_utils_add_open_actions (CamelMimePart *mime_part, - GtkUIManager *ui_manager, - GtkActionGroup *action_group, - const gchar *widget_path, - GtkWindow *parent, - guint merge_id) -{ - GList *app_info_list; - GList *iter; - - g_return_if_fail (CAMEL_IS_MIME_PART (mime_part)); - g_return_if_fail (GTK_IS_UI_MANAGER (ui_manager)); - g_return_if_fail (GTK_IS_ACTION_GROUP (action_group)); - g_return_if_fail (parent == NULL || GTK_IS_WINDOW (parent)); - g_return_if_fail (widget_path != NULL); - - app_info_list = e_mime_part_utils_get_apps (mime_part); - - for (iter = app_info_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 ( - G_OBJECT (action), "parent-window", parent); - - g_signal_connect ( - action, "activate", - G_CALLBACK (mime_part_utils_open_in_cb), mime_part); - - gtk_action_group_add_action (action_group, action); - - gtk_ui_manager_add_ui ( - ui_manager, merge_id, widget_path, action_name, - action_name, GTK_UI_MANAGER_AUTO, FALSE); - - g_free (action_name); - g_free (action_label); - g_free (action_tooltip); - } - - g_list_foreach (app_info_list, (GFunc) g_object_unref, NULL); - g_list_free (app_info_list); -} diff --git a/widgets/misc/e-mime-part-utils.h b/widgets/misc/e-mime-part-utils.h deleted file mode 100644 index e923e07c8d..0000000000 --- a/widgets/misc/e-mime-part-utils.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * e-mime-part-utils.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_MIME_PART_UTILS_H -#define E_MIME_PART_UTILS_H - -#include <gtk/gtk.h> -#include <camel/camel-mime-part.h> -#include <shell/e-shell-window.h> - -G_BEGIN_DECLS - -GList * e_mime_part_utils_get_apps (CamelMimePart *mime_part); -gboolean e_mime_part_utils_save_to_file (CamelMimePart *mime_part, - GFile *file, - GError **error); - -void e_mime_part_utils_add_open_actions - (CamelMimePart *mime_part, - GtkUIManager *ui_manager, - GtkActionGroup *action_group, - const gchar *widget_path, - GtkWindow *parent, - guint merge_id); - -G_END_DECLS - -#endif /* E_MIME_PART_UTILS_H */ |