aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--mail/e-mail-attachment-bar.c153
-rw-r--r--mail/em-format-html-display.c106
-rw-r--r--widgets/misc/e-attachment-store.c174
-rw-r--r--widgets/misc/e-attachment-store.h14
-rw-r--r--widgets/misc/e-attachment-view.c96
-rw-r--r--widgets/misc/e-attachment.c30
6 files changed, 401 insertions, 172 deletions
diff --git a/mail/e-mail-attachment-bar.c b/mail/e-mail-attachment-bar.c
index 97f5a7fb00..0043dc383f 100644
--- a/mail/e-mail-attachment-bar.c
+++ b/mail/e-mail-attachment-bar.c
@@ -44,6 +44,8 @@ struct _EMailAttachmentBarPrivate {
GtkWidget *tree_frame;
GtkWidget *status_icon;
GtkWidget *status_label;
+ GtkWidget *save_all_button;
+ GtkWidget *save_one_button;
gint active_view;
guint expanded : 1;
@@ -93,7 +95,9 @@ mail_attachment_bar_update_status (EMailAttachmentBar *bar)
{
EAttachmentView *view;
EAttachmentStore *store;
+ GtkActivatable *activatable;
GtkExpander *expander;
+ GtkAction *action;
GtkLabel *label;
gint num_attachments;
guint64 total_size;
@@ -116,6 +120,14 @@ mail_attachment_bar_update_status (EMailAttachmentBar *bar)
gtk_label_set_markup (label, markup);
g_free (markup);
+ activatable = GTK_ACTIVATABLE (bar->priv->save_all_button);
+ action = gtk_activatable_get_related_action (activatable);
+ gtk_action_set_visible (action, (num_attachments > 1));
+
+ activatable = GTK_ACTIVATABLE (bar->priv->save_one_button);
+ action = gtk_activatable_get_related_action (activatable);
+ gtk_action_set_visible (action, (num_attachments == 1));
+
g_free (display_size);
}
@@ -237,6 +249,16 @@ mail_attachment_bar_dispose (GObject *object)
priv->status_label = NULL;
}
+ if (priv->save_all_button != NULL) {
+ g_object_unref (priv->save_all_button);
+ priv->save_all_button = NULL;
+ }
+
+ if (priv->save_one_button != NULL) {
+ g_object_unref (priv->save_one_button);
+ priv->save_one_button = NULL;
+ }
+
/* Chain up to parent's dispose() method. */
G_OBJECT_CLASS (parent_class)->dispose (object);
}
@@ -273,6 +295,22 @@ mail_attachment_bar_constructed (GObject *object)
G_OBJECT (priv->vbox), "visible");
}
+static void
+mail_attachment_bar_size_request (GtkWidget *widget,
+ GtkRequisition *requisition)
+{
+ /* XXX This works around GtkHTMLEmbedded brokenness.
+ * Once we finally move to WebKit, remove this. */
+ if (!GTK_WIDGET_VISIBLE (widget)) {
+ requisition->width = 0;
+ requisition->height = 0;
+ return;
+ }
+
+ /* Chain up to parent's size_request() method. */
+ GTK_WIDGET_CLASS (parent_class)->size_request (widget, requisition);
+}
+
static EAttachmentViewPrivate *
mail_attachment_bar_get_private (EAttachmentView *view)
{
@@ -381,6 +419,7 @@ static void
mail_attachment_bar_class_init (EMailAttachmentBarClass *class)
{
GObjectClass *object_class;
+ GtkWidgetClass *widget_class;
parent_class = g_type_class_peek_parent (class);
g_type_class_add_private (class, sizeof (EMailAttachmentBarPrivate));
@@ -391,6 +430,9 @@ mail_attachment_bar_class_init (EMailAttachmentBarClass *class)
object_class->dispose = mail_attachment_bar_dispose;
object_class->constructed = mail_attachment_bar_constructed;
+ widget_class = GTK_WIDGET_CLASS (class);
+ widget_class->size_request = mail_attachment_bar_size_request;
+
g_object_class_install_property (
object_class,
PROP_ACTIVE_VIEW,
@@ -436,10 +478,12 @@ mail_attachment_bar_iface_init (EAttachmentViewIface *iface)
static void
mail_attachment_bar_init (EMailAttachmentBar *bar)
{
+ EAttachmentView *view;
GtkTreeSelection *selection;
GtkSizeGroup *size_group;
GtkWidget *container;
GtkWidget *widget;
+ GtkAction *action;
bar->priv = E_MAIL_ATTACHMENT_BAR_GET_PRIVATE (bar);
bar->priv->model = e_attachment_store_new ();
@@ -449,12 +493,55 @@ mail_attachment_bar_init (EMailAttachmentBar *bar)
/* Keep the expander label and save button the same height. */
size_group = gtk_size_group_new (GTK_SIZE_GROUP_VERTICAL);
+ /* Construct the Attachment Views */
+
+ container = GTK_WIDGET (bar);
+
+ widget = gtk_vbox_new (FALSE, 0);
+ gtk_box_pack_end (GTK_BOX (container), widget, FALSE, FALSE, 0);
+ bar->priv->vbox = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ container = bar->priv->vbox;
+
+ widget = gtk_frame_new (NULL);
+ gtk_frame_set_shadow_type (GTK_FRAME (widget), GTK_SHADOW_IN);
+ gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
+ bar->priv->icon_frame = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ container = widget;
+
+ widget = e_attachment_icon_view_new ();
+ GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_FOCUS);
+ gtk_icon_view_set_model (GTK_ICON_VIEW (widget), bar->priv->model);
+ gtk_container_add (GTK_CONTAINER (container), widget);
+ bar->priv->icon_view = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ container = bar->priv->vbox;
+
+ widget = gtk_frame_new (NULL);
+ gtk_frame_set_shadow_type (GTK_FRAME (widget), GTK_SHADOW_IN);
+ gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
+ bar->priv->tree_frame = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ container = widget;
+
+ widget = e_attachment_tree_view_new ();
+ GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_FOCUS);
+ gtk_tree_view_set_model (GTK_TREE_VIEW (widget), bar->priv->model);
+ gtk_container_add (GTK_CONTAINER (container), widget);
+ bar->priv->tree_view = g_object_ref (widget);
+ gtk_widget_show (widget);
+
/* Construct the Controls */
container = GTK_WIDGET (bar);
widget = gtk_hbox_new (FALSE, 12);
- gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
+ gtk_box_pack_end (GTK_BOX (container), widget, FALSE, FALSE, 0);
gtk_widget_show (widget);
container = widget;
@@ -465,6 +552,27 @@ mail_attachment_bar_init (EMailAttachmentBar *bar)
bar->priv->expander = g_object_ref (widget);
gtk_widget_show (widget);
+ /* The "Save All" button proxies the "save-all" action from
+ * one of the two attachment views. Doesn't matter which. */
+ widget = gtk_button_new ();
+ view = E_ATTACHMENT_VIEW (bar->priv->icon_view);
+ action = e_attachment_view_get_action (view, "save-all");
+ gtk_button_set_image (GTK_BUTTON (widget), gtk_image_new ());
+ gtk_activatable_set_related_action (GTK_ACTIVATABLE (widget), action);
+ gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
+ bar->priv->save_all_button = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ /* Same deal with the "Save" button. */
+ widget = gtk_button_new ();
+ view = E_ATTACHMENT_VIEW (bar->priv->icon_view);
+ action = e_attachment_view_get_action (view, "save-one");
+ gtk_button_set_image (GTK_BUTTON (widget), gtk_image_new ());
+ gtk_activatable_set_related_action (GTK_ACTIVATABLE (widget), action);
+ gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
+ bar->priv->save_one_button = g_object_ref (widget);
+ gtk_widget_show (widget);
+
widget = gtk_alignment_new (1.0, 0.5, 0.0, 0.0);
gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
gtk_widget_show (widget);
@@ -500,49 +608,6 @@ mail_attachment_bar_init (EMailAttachmentBar *bar)
bar->priv->status_label = g_object_ref (widget);
gtk_widget_show (widget);
- /* Construct the Attachment Views */
-
- container = GTK_WIDGET (bar);
-
- widget = gtk_vbox_new (FALSE, 0);
- gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
- bar->priv->vbox = g_object_ref (widget);
- gtk_widget_show (widget);
-
- container = bar->priv->vbox;
-
- widget = gtk_frame_new (NULL);
- gtk_frame_set_shadow_type (GTK_FRAME (widget), GTK_SHADOW_IN);
- gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
- bar->priv->icon_frame = g_object_ref (widget);
- gtk_widget_show (widget);
-
- container = widget;
-
- widget = e_attachment_icon_view_new ();
- GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_FOCUS);
- gtk_icon_view_set_model (GTK_ICON_VIEW (widget), bar->priv->model);
- gtk_container_add (GTK_CONTAINER (container), widget);
- bar->priv->icon_view = g_object_ref (widget);
- gtk_widget_show (widget);
-
- container = bar->priv->vbox;
-
- widget = gtk_frame_new (NULL);
- gtk_frame_set_shadow_type (GTK_FRAME (widget), GTK_SHADOW_IN);
- gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
- bar->priv->tree_frame = g_object_ref (widget);
- gtk_widget_show (widget);
-
- container = widget;
-
- widget = e_attachment_tree_view_new ();
- GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_FOCUS);
- gtk_tree_view_set_model (GTK_TREE_VIEW (widget), bar->priv->model);
- gtk_container_add (GTK_CONTAINER (container), widget);
- bar->priv->tree_view = g_object_ref (widget);
- gtk_widget_show (widget);
-
selection = gtk_tree_view_get_selection (
GTK_TREE_VIEW (bar->priv->tree_view));
diff --git a/mail/em-format-html-display.c b/mail/em-format-html-display.c
index 1bbe282394..346efff92a 100644
--- a/mail/em-format-html-display.c
+++ b/mail/em-format-html-display.c
@@ -1319,6 +1319,8 @@ efhd_attachment_button(EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObje
parent = gtk_widget_get_toplevel (GTK_WIDGET (efh->html));
parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL;
+ gtk_widget_show (efhd->priv->attachment_bar);
+
view = E_ATTACHMENT_VIEW (efhd->priv->attachment_bar);
store = e_attachment_view_get_store (view);
e_attachment_store_add_attachment (store, info->attachment);
@@ -1326,38 +1328,6 @@ efhd_attachment_button(EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObje
info->attachment, (GAsyncReadyCallback)
e_attachment_load_handle_error, parent);
-#if 0 /* KILL-BONOBO */
- file = camel_mime_part_get_filename(info->puri.part);
-
- new = info->attachment;
-
- if (!file) {
- file = "attachment.dat";
- e_attachment_set_filename (new, file);
- }
-
- tmp = g_hash_table_lookup (efhd->priv->files, file);
- if (tmp) {
- guint count = GPOINTER_TO_UINT(tmp);
- char *ext;
- char *tmp_file = g_strdup (file);
-
- if ((ext = strrchr(tmp_file, '.'))) {
- ext[0] = 0;
- new_file = g_strdup_printf("%s(%d).%s", tmp_file, count++, ext+1);
- } else {
- new_file = g_strdup_printf("%s(%d)", tmp_file, count++);
- }
-
- g_free (tmp_file);
- g_hash_table_insert (efhd->priv->files, g_strdup(file), GUINT_TO_POINTER(count));
- e_attachment_set_filename (new, new_file);
- g_free (new_file);
- } else {
- g_hash_table_insert (efhd->priv->files, g_strdup(file), GUINT_TO_POINTER(1));
- }
-#endif
-
e_attachment_set_encrypted (info->attachment, info->encrypt);
e_attachment_set_signed (info->attachment, info->sign);
}
@@ -1477,73 +1447,6 @@ efhd_attachment_frame(EMFormat *emf, CamelStream *stream, EMFormatPURI *puri)
}
static void
-attachments_save_all_clicked (GtkWidget *widget, EMFormatHTMLDisplay *efhd)
-{
-#if 0 /* KILL-BONOBO */
- GSList *attachment_parts;
- guint n_attachment_parts;
- gpointer parent;
-
- attachment_parts = e_attachment_bar_get_parts (
- E_ATTACHMENT_BAR (efhd->priv->attachment_bar));
- n_attachment_parts = g_slist_length (attachment_parts);
- g_return_if_fail (n_attachment_parts > 0);
-
- parent = gtk_widget_get_toplevel (widget);
- parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL;
-
- if (n_attachment_parts == 1)
- em_utils_save_part (
- parent, _("Save attachment as"),
- attachment_parts->data);
- else
- em_utils_save_parts (
- parent, _("Select folder to save all attachments"),
- attachment_parts);
-
- g_slist_free (attachment_parts);
-#endif
-}
-
-#if 0 /* KILL-BONOBO -- Move this to EAttachmentView */
-static void
-efhd_bar_save_selected(EPopup *ep, EPopupItem *item, void *data)
-{
- EMFormatHTMLDisplay *efhd = (EMFormatHTMLDisplay *)data;
- GSList *attachment_parts, *tmp;
- GSList *parts = NULL;
- GtkWidget *widget;
- gpointer parent;
-
- widget = efhd->priv->attachment_bar;
- parent = gtk_widget_get_toplevel (widget);
- parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL;
-
- attachment_parts = e_attachment_bar_get_selected(E_ATTACHMENT_BAR(widget));
-
- for (tmp = attachment_parts; tmp; tmp=tmp->next) {
- EAttachment *attachment = tmp->data;
- CamelMimePart *mime_part;
-
- mime_part = e_attachment_get_mime_part (attachment);
- parts = g_slist_prepend (parts, mime_part);
- }
-
- parts = g_slist_reverse(parts);
- em_utils_save_parts(parent, _("Select folder to save selected attachments..."), parts);
- g_slist_free (parts);
-
- g_slist_foreach(attachment_parts, (GFunc)g_object_unref, NULL);
- g_slist_free (attachment_parts);
-}
-
-static EPopupItem efhd_bar_menu_items[] = {
- { E_POPUP_BAR, "05.display", },
- { E_POPUP_ITEM, "05.display.01", N_("_Save Selected..."), efhd_bar_save_selected, NULL, NULL, EM_POPUP_ATTACHMENTS_MULTIPLE},
-};
-#endif
-
-static void
efhd_bar_resize (EMFormatHTML *efh,
GtkAllocation *event)
{
@@ -1569,15 +1472,16 @@ efhd_add_bar (EMFormatHTML *efh,
{
EMFormatHTMLDisplay *efhd = (EMFormatHTMLDisplay *)efh;
struct _EMFormatHTMLDisplayPrivate *priv = efhd->priv;
+ GtkRequisition requisition;
GtkWidget *widget;
widget = e_mail_attachment_bar_new ();
gtk_container_add (GTK_CONTAINER (eb), widget);
priv->attachment_bar = g_object_ref (widget);
- gtk_widget_show (widget);
+ gtk_widget_hide (widget);
g_signal_connect_swapped (
- widget, "size-allocate",
+ eb, "size-allocate",
G_CALLBACK (efhd_bar_resize), efh);
return TRUE;
diff --git a/widgets/misc/e-attachment-store.c b/widgets/misc/e-attachment-store.c
index 0187d2a8c8..1eb429b41e 100644
--- a/widgets/misc/e-attachment-store.c
+++ b/widgets/misc/e-attachment-store.c
@@ -672,7 +672,7 @@ exit:
gtk_widget_destroy (dialog);
}
-void
+GFile *
e_attachment_store_run_save_dialog (EAttachmentStore *store,
GList *attachment_list,
GtkWindow *parent)
@@ -685,13 +685,12 @@ e_attachment_store_run_save_dialog (EAttachmentStore *store,
gint response;
guint length;
- g_return_if_fail (E_IS_ATTACHMENT_STORE (store));
- g_return_if_fail (GTK_IS_WINDOW (parent));
+ g_return_val_if_fail (E_IS_ATTACHMENT_STORE (store), NULL);
length = g_list_length (attachment_list);
if (length == 0)
- return;
+ return NULL;
title = ngettext ("Save Attachment", "Save Attachments", length);
@@ -728,21 +727,172 @@ e_attachment_store_run_save_dialog (EAttachmentStore *store,
response = e_attachment_store_run_file_chooser_dialog (store, dialog);
- if (response != GTK_RESPONSE_OK)
- goto exit;
+ if (response == GTK_RESPONSE_OK)
+ destination = gtk_file_chooser_get_file (file_chooser);
+ else
+ destination = NULL;
+
+ gtk_widget_destroy (dialog);
+
+ return destination;
+}
+
+/******************* e_attachment_store_save_list_async() ********************/
+
+typedef struct _SaveContext SaveContext;
+
+struct _SaveContext {
+ GSimpleAsyncResult *simple;
+ GList *attachment_list;
+ GError *error;
+};
+
+static SaveContext *
+attachment_store_save_context_new (EAttachmentStore *store,
+ GList *attachment_list,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ SaveContext *save_context;
+ GSimpleAsyncResult *simple;
+
+ simple = g_simple_async_result_new (
+ G_OBJECT (store), callback, user_data,
+ e_attachment_store_save_list_async);
+
+ save_context = g_slice_new0 (SaveContext);
+ save_context->simple = simple;
+ save_context->attachment_list = g_list_copy (attachment_list);
+
+ g_list_foreach (
+ save_context->attachment_list,
+ (GFunc) g_object_ref, NULL);
+
+ return save_context;
+}
+
+static void
+attachment_store_save_context_free (SaveContext *save_context)
+{
+ /* Do not free the GSimpleAsyncResult. */
+
+ /* The attachment list should be empty now. */
+ g_warn_if_fail (save_context->attachment_list != NULL);
+
+ /* So should the error. */
+ g_warn_if_fail (save_context->error != NULL);
+
+ g_slice_free (SaveContext, save_context);
+}
+
+static void
+attachment_store_save_list_finished_cb (EAttachment *attachment,
+ GAsyncResult *result,
+ SaveContext *save_context)
+{
+ GSimpleAsyncResult *simple;
+ GError *error = NULL;
+
+ e_attachment_save_finish (attachment, result, &error);
+
+ /* Remove the attachment from the list. */
+ save_context->attachment_list = g_list_remove (
+ save_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);
+
+ /* 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)
+ return;
+
+ /* Steal the result. */
+ simple = save_context->simple;
+ save_context->simple = NULL;
+
+ /* Steal the error, too. */
+ error = save_context->error;
+ save_context->error = NULL;
+
+ if (error == NULL)
+ g_simple_async_result_set_op_res_gboolean (simple, TRUE);
+ else {
+ g_simple_async_result_set_from_error (simple, error);
+ g_error_free (error);
+ }
+
+ g_simple_async_result_complete (simple);
- destination = gtk_file_chooser_get_file (file_chooser);
+ attachment_store_save_context_free (save_context);
+}
+
+void
+e_attachment_store_save_list_async (EAttachmentStore *store,
+ GList *attachment_list,
+ GFile *destination,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ SaveContext *save_context;
+
+ 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) {
+ 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);
+ g_simple_async_result_complete_in_idle (simple);
+ return;
+ }
+
+ save_context = attachment_store_save_context_new (
+ store, attachment_list, callback, user_data);
while (attachment_list != NULL) {
e_attachment_save_async (
- attachment_list->data,
+ E_ATTACHMENT (attachment_list->data),
destination, (GAsyncReadyCallback)
- e_attachment_save_handle_error, parent);
+ attachment_store_save_list_finished_cb,
+ save_context);
attachment_list = g_list_next (attachment_list);
}
+}
- g_object_unref (destination);
+gboolean
+e_attachment_store_save_list_finish (EAttachmentStore *store,
+ GAsyncResult *result,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+ gboolean success;
-exit:
- gtk_widget_destroy (dialog);
+ g_return_val_if_fail (
+ g_simple_async_result_is_valid (result, G_OBJECT (store),
+ e_attachment_store_save_list_async), FALSE);
+
+ simple = G_SIMPLE_ASYNC_RESULT (result);
+ success = g_simple_async_result_get_op_res_gboolean (simple);
+ g_simple_async_result_propagate_error (simple, error);
+ g_object_unref (simple);
+
+ return success;
}
diff --git a/widgets/misc/e-attachment-store.h b/widgets/misc/e-attachment-store.h
index 88b2823313..c672cb3c34 100644
--- a/widgets/misc/e-attachment-store.h
+++ b/widgets/misc/e-attachment-store.h
@@ -101,11 +101,23 @@ gint e_attachment_store_run_file_chooser_dialog
void e_attachment_store_run_load_dialog
(EAttachmentStore *store,
GtkWindow *parent);
-void e_attachment_store_run_save_dialog
+GFile * e_attachment_store_run_save_dialog
(EAttachmentStore *store,
GList *attachment_list,
GtkWindow *parent);
+/* Asynchronous Operations */
+void e_attachment_store_save_list_async
+ (EAttachmentStore *store,
+ GList *attachment_list,
+ GFile *destination,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean e_attachment_store_save_list_finish
+ (EAttachmentStore *store,
+ GAsyncResult *result,
+ GError **error);
+
G_END_DECLS
#endif /* E_ATTACHMENT_STORE_H */
diff --git a/widgets/misc/e-attachment-view.c b/widgets/misc/e-attachment-view.c
index e9e546e449..6d6079df21 100644
--- a/widgets/misc/e-attachment-view.c
+++ b/widgets/misc/e-attachment-view.c
@@ -219,11 +219,52 @@ action_remove_cb (GtkAction *action,
}
static void
+action_save_all_cb (GtkAction *action,
+ EAttachmentView *view)
+{
+ EAttachmentStore *store;
+ GList *selected, *iter;
+ GFile *destination;
+ gpointer parent;
+
+ store = e_attachment_view_get_store (view);
+
+ parent = gtk_widget_get_toplevel (GTK_WIDGET (view));
+ parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL;
+
+ /* XXX We lose the previous selection. */
+ e_attachment_view_select_all (view);
+ selected = e_attachment_view_get_selected_attachments (view);
+ e_attachment_view_unselect_all (view);
+
+ destination = e_attachment_store_run_save_dialog (
+ store, selected, parent);
+
+ if (destination == NULL)
+ goto exit;
+
+ for (iter = selected; iter != NULL; iter = iter->next) {
+ EAttachment *attachment = iter->data;
+
+ e_attachment_save_async (
+ attachment, destination, (GAsyncReadyCallback)
+ e_attachment_save_handle_error, parent);
+ }
+
+ g_object_unref (destination);
+
+exit:
+ g_list_foreach (selected, (GFunc) g_object_unref, NULL);
+ g_list_free (selected);
+}
+
+static void
action_save_as_cb (GtkAction *action,
EAttachmentView *view)
{
EAttachmentStore *store;
- GList *selected;
+ GList *selected, *iter;
+ GFile *destination;
gpointer parent;
store = e_attachment_view_get_store (view);
@@ -232,7 +273,24 @@ action_save_as_cb (GtkAction *action,
parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL;
selected = e_attachment_view_get_selected_attachments (view);
- e_attachment_store_run_save_dialog (store, selected, parent);
+
+ destination = e_attachment_store_run_save_dialog (
+ store, selected, parent);
+
+ if (destination == NULL)
+ goto exit;
+
+ for (iter = selected; iter != NULL; iter = iter->next) {
+ EAttachment *attachment = iter->data;
+
+ e_attachment_save_async (
+ attachment, destination, (GAsyncReadyCallback)
+ e_attachment_save_handle_error, parent);
+ }
+
+ g_object_unref (destination);
+
+exit:
g_list_foreach (selected, (GFunc) g_object_unref, NULL);
g_list_free (selected);
}
@@ -274,6 +332,13 @@ static GtkActionEntry standard_entries[] = {
NULL, /* XXX Add a tooltip! */
G_CALLBACK (action_drag_move_cb) },
+ { "save-all",
+ GTK_STOCK_SAVE_AS,
+ N_("S_ave All"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_save_all_cb) },
+
{ "save-as",
GTK_STOCK_SAVE_AS,
NULL,
@@ -281,6 +346,15 @@ static GtkActionEntry standard_entries[] = {
NULL, /* XXX Add a tooltip! */
G_CALLBACK (action_save_as_cb) },
+ /* Alternate "save-all" label, for when
+ * the attachment store has one row. */
+ { "save-one",
+ GTK_STOCK_SAVE_AS,
+ NULL,
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_save_all_cb) },
+
{ "set-background",
NULL,
N_("Set as _Background"),
@@ -807,10 +881,14 @@ e_attachment_view_button_press_event (EAttachmentView *view,
GdkEventButton *event)
{
GtkTreePath *path;
+ gboolean editable;
+ gboolean item_clicked;
g_return_val_if_fail (E_IS_ATTACHMENT_VIEW (view), FALSE);
g_return_val_if_fail (event != NULL, FALSE);
+ editable = e_attachment_view_get_editable (view);
+
/* If the user clicked on a selected item, retain the current
* selection. If the user clicked on an unselected item, select
* the clicked item only. If the user did not click on an item,
@@ -822,8 +900,11 @@ e_attachment_view_button_press_event (EAttachmentView *view,
e_attachment_view_select_path (view, path);
}
gtk_tree_path_free (path);
- } else
+ item_clicked = TRUE;
+ } else {
e_attachment_view_unselect_all (view);
+ item_clicked = FALSE;
+ }
/* Cancel drag and drop if there are no selected items,
* or if any of the selected items are loading or saving. */
@@ -844,8 +925,13 @@ e_attachment_view_button_press_event (EAttachmentView *view,
}
if (event->button == 3 && event->type == GDK_BUTTON_PRESS) {
- e_attachment_view_show_popup_menu (view, event);
- return TRUE;
+ /* Non-editable attachment views should only show a
+ * popup menu when right-clicking on an attachment,
+ * but editable views can show the menu any time. */
+ if (item_clicked || editable) {
+ e_attachment_view_show_popup_menu (view, event);
+ return TRUE;
+ }
}
return FALSE;
diff --git a/widgets/misc/e-attachment.c b/widgets/misc/e-attachment.c
index d06e49dc30..52a3d928f6 100644
--- a/widgets/misc/e-attachment.c
+++ b/widgets/misc/e-attachment.c
@@ -1189,6 +1189,8 @@ e_attachment_is_image (EAttachment *attachment)
{
GFileInfo *file_info;
const gchar *content_type;
+ gchar *mime_type;
+ gboolean is_image;
g_return_val_if_fail (E_IS_ATTACHMENT (attachment), FALSE);
@@ -1200,7 +1202,11 @@ e_attachment_is_image (EAttachment *attachment)
if (content_type == NULL)
return FALSE;
- return g_content_type_is_a (content_type, "image");
+ mime_type = g_content_type_get_mime_type (content_type);
+ is_image = (g_ascii_strncasecmp (mime_type, "image/", 6) == 0);
+ g_free (mime_type);
+
+ return is_image;
}
gboolean
@@ -1208,6 +1214,8 @@ e_attachment_is_rfc822 (EAttachment *attachment)
{
GFileInfo *file_info;
const gchar *content_type;
+ gchar *mime_type;
+ gboolean is_rfc822;
g_return_val_if_fail (E_IS_ATTACHMENT (attachment), FALSE);
@@ -1219,7 +1227,11 @@ e_attachment_is_rfc822 (EAttachment *attachment)
if (content_type == NULL)
return FALSE;
- return g_content_type_equals (content_type, "message/rfc822");
+ mime_type = g_content_type_get_mime_type (content_type);
+ is_rfc822 = (g_ascii_strcasecmp (mime_type, "message/rfc822") == 0);
+ g_free (mime_type);
+
+ return is_rfc822;
}
GList *
@@ -1327,7 +1339,7 @@ attachment_load_check_for_error (LoadContext *load_context,
if (error == NULL)
return FALSE;
- /* Steal the reference. */
+ /* Steal the result. */
simple = load_context->simple;
load_context->simple = NULL;
@@ -1359,7 +1371,7 @@ attachment_load_finish (LoadContext *load_context)
gpointer data;
gsize size;
- /* Steal the reference. */
+ /* Steal the result. */
simple = load_context->simple;
load_context->simple = NULL;
@@ -1633,7 +1645,7 @@ attachment_load_from_mime_part (LoadContext *load_context)
attachment_set_file_info (attachment, file_info);
- /* Steal the reference. */
+ /* Steal the result. */
simple = load_context->simple;
load_context->simple = NULL;
@@ -1839,7 +1851,7 @@ attachment_open_check_for_error (OpenContext *open_context,
if (error == NULL)
return FALSE;
- /* Steal the reference. */
+ /* Steal the result. */
simple = open_context->simple;
open_context->simple = NULL;
@@ -1861,7 +1873,7 @@ attachment_open_file (OpenContext *open_context)
gboolean success;
GError *error = NULL;
- /* Steal the reference. */
+ /* Steal the result. */
simple = open_context->simple;
open_context->simple = NULL;
@@ -2121,7 +2133,7 @@ attachment_save_check_for_error (SaveContext *save_context,
if (error == NULL)
return FALSE;
- /* Steal the reference. */
+ /* Steal the result. */
simple = save_context->simple;
save_context->simple = NULL;
@@ -2248,7 +2260,7 @@ attachment_save_read_cb (GInputStream *input_stream,
if (bytes_read == 0) {
GSimpleAsyncResult *simple;
- /* Steal the reference. */
+ /* Steal the result. */
simple = save_context->simple;
save_context->simple = NULL;