From 826372c35155cb47f940905e27b304e9ef63441d Mon Sep 17 00:00:00 2001 From: Matthew Barnes Date: Sat, 27 Jul 2013 10:31:24 -0400 Subject: Add e_web_view_cursor_image_save(). Prompts the user to choose a destination file and then asynchronously saves the image under the cursor to the destination file. --- .../evolution-util/evolution-util-sections.txt | 1 + e-util/e-web-view.c | 235 +++++++++++++++++++++ e-util/e-web-view.h | 1 + 3 files changed, 237 insertions(+) diff --git a/doc/reference/evolution-util/evolution-util-sections.txt b/doc/reference/evolution-util/evolution-util-sections.txt index ed4a25dd3b..f4878fd4fd 100644 --- a/doc/reference/evolution-util/evolution-util-sections.txt +++ b/doc/reference/evolution-util/evolution-util-sections.txt @@ -4411,6 +4411,7 @@ e_web_view_update_actions e_web_view_get_selection_html e_web_view_update_fonts e_web_view_cursor_image_copy +e_web_view_cursor_image_save e_web_view_request e_web_view_request_finish e_web_view_install_request_handler diff --git a/e-util/e-web-view.c b/e-util/e-web-view.c index 45b48c4e19..a762c45513 100644 --- a/e-util/e-web-view.c +++ b/e-util/e-web-view.c @@ -75,6 +75,8 @@ struct _EWebViewPrivate { }; struct _AsyncContext { + EActivity *activity; + GFile *destination; GInputStream *input_stream; }; @@ -151,6 +153,8 @@ G_DEFINE_TYPE_WITH_CODE ( static void async_context_free (AsyncContext *async_context) { + g_clear_object (&async_context->activity); + g_clear_object (&async_context->destination); g_clear_object (&async_context->input_stream); g_slice_free (AsyncContext, async_context); @@ -2824,6 +2828,237 @@ e_web_view_cursor_image_copy (EWebView *web_view) } } +/* Helper for e_web_view_cursor_image_save() */ +static void +web_view_cursor_image_save_splice_cb (GObject *source_object, + GAsyncResult *result, + gpointer user_data) +{ + EActivity *activity; + EAlertSink *alert_sink; + AsyncContext *async_context; + GError *local_error = NULL; + + async_context = (AsyncContext *) user_data; + + activity = async_context->activity; + alert_sink = e_activity_get_alert_sink (activity); + + g_output_stream_splice_finish ( + G_OUTPUT_STREAM (source_object), result, &local_error); + + if (e_activity_handle_cancellation (activity, local_error)) { + g_error_free (local_error); + + } else if (local_error != NULL) { + e_alert_submit ( + alert_sink, + "widgets:no-image-save", + local_error->message, NULL); + g_error_free (local_error); + + } else { + e_activity_set_state (activity, E_ACTIVITY_COMPLETED); + } + + async_context_free (async_context); +} + +/* Helper for e_web_view_cursor_image_save() */ +static void +web_view_cursor_image_save_replace_cb (GObject *source_object, + GAsyncResult *result, + gpointer user_data) +{ + EActivity *activity; + EAlertSink *alert_sink; + GCancellable *cancellable; + GFileOutputStream *output_stream; + AsyncContext *async_context; + GError *local_error = NULL; + + async_context = (AsyncContext *) user_data; + + activity = async_context->activity; + alert_sink = e_activity_get_alert_sink (activity); + cancellable = e_activity_get_cancellable (activity); + + output_stream = g_file_replace_finish ( + G_FILE (source_object), result, &local_error); + + /* Sanity check. */ + g_return_if_fail ( + ((output_stream != NULL) && (local_error == NULL)) || + ((output_stream == NULL) && (local_error != NULL))); + + if (e_activity_handle_cancellation (activity, local_error)) { + g_error_free (local_error); + async_context_free (async_context); + + } else if (local_error != NULL) { + e_alert_submit ( + alert_sink, + "widgets:no-image-save", + local_error->message, NULL); + g_error_free (local_error); + async_context_free (async_context); + + } else { + g_output_stream_splice_async ( + G_OUTPUT_STREAM (output_stream), + async_context->input_stream, + G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | + G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET, + G_PRIORITY_DEFAULT, + cancellable, + web_view_cursor_image_save_splice_cb, + async_context); + } + + g_clear_object (&output_stream); +} + +/* Helper for e_web_view_cursor_image_save() */ +static void +web_view_cursor_image_save_request_cb (GObject *source_object, + GAsyncResult *result, + gpointer user_data) +{ + EActivity *activity; + EAlertSink *alert_sink; + GCancellable *cancellable; + GInputStream *input_stream; + AsyncContext *async_context; + GError *local_error = NULL; + + async_context = (AsyncContext *) user_data; + + activity = async_context->activity; + alert_sink = e_activity_get_alert_sink (activity); + cancellable = e_activity_get_cancellable (activity); + + input_stream = e_web_view_request_finish ( + E_WEB_VIEW (source_object), result, &local_error); + + /* Sanity check. */ + g_return_if_fail ( + ((input_stream != NULL) && (local_error == NULL)) || + ((input_stream == NULL) && (local_error != NULL))); + + if (e_activity_handle_cancellation (activity, local_error)) { + g_error_free (local_error); + async_context_free (async_context); + + } else if (local_error != NULL) { + e_alert_submit ( + alert_sink, + "widgets:no-image-save", + local_error->message, NULL); + g_error_free (local_error); + async_context_free (async_context); + + } else { + async_context->input_stream = g_object_ref (input_stream); + + /* Open an output stream to the destination file. */ + g_file_replace_async ( + async_context->destination, + NULL, FALSE, + G_FILE_CREATE_REPLACE_DESTINATION, + G_PRIORITY_DEFAULT, + cancellable, + web_view_cursor_image_save_replace_cb, + async_context); + } + + g_clear_object (&input_stream); +} + +/** + * e_web_view_cursor_image_save: + * @web_view: an #EWebView + * + * Prompts the user to choose a destination file and then asynchronously + * saves the image under the cursor to the destination file. + * + * This function triggers a #EWebView::new-activity signal emission so + * the asynchronous operation can be tracked and/or cancelled. + **/ +void +e_web_view_cursor_image_save (EWebView *web_view) +{ + GtkFileChooser *file_chooser; + GFile *destination = NULL; + GtkWidget *dialog; + gchar *suggestion; + gpointer toplevel; + + g_return_if_fail (E_IS_WEB_VIEW (web_view)); + + if (web_view->priv->cursor_image_src == NULL) + return; + + toplevel = gtk_widget_get_toplevel (GTK_WIDGET (web_view)); + toplevel = gtk_widget_is_toplevel (toplevel) ? toplevel : NULL; + + dialog = gtk_file_chooser_dialog_new ( + _("Save Image"), toplevel, + GTK_FILE_CHOOSER_ACTION_SAVE, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, NULL); + + gtk_dialog_set_default_response ( + GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT); + + file_chooser = GTK_FILE_CHOOSER (dialog); + gtk_file_chooser_set_local_only (file_chooser, FALSE); + gtk_file_chooser_set_do_overwrite_confirmation (file_chooser, TRUE); + + suggestion = e_web_view_suggest_filename ( + web_view, web_view->priv->cursor_image_src); + + if (suggestion != NULL) { + gtk_file_chooser_set_current_name (file_chooser, suggestion); + g_free (suggestion); + } + + if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) + destination = gtk_file_chooser_get_file (file_chooser); + + gtk_widget_destroy (dialog); + + if (destination != NULL) { + EActivity *activity; + GCancellable *cancellable; + AsyncContext *async_context; + gchar *text; + gchar *uri; + + activity = e_web_view_new_activity (web_view); + cancellable = e_activity_get_cancellable (activity); + + uri = g_file_get_uri (destination); + text = g_strdup_printf (_("Saving image to '%s'"), uri); + e_activity_set_text (activity, text); + g_free (text); + g_free (uri); + + async_context = g_slice_new0 (AsyncContext); + async_context->activity = g_object_ref (activity); + async_context->destination = g_object_ref (destination); + + e_web_view_request ( + web_view, + web_view->priv->cursor_image_src, + cancellable, + web_view_cursor_image_save_request_cb, + async_context); + + g_object_unref (activity); + g_object_unref (destination); + } +} + /* Helper for e_web_view_request() */ static void web_view_request_send_cb (GObject *source_object, diff --git a/e-util/e-web-view.h b/e-util/e-web-view.h index 3f7b4e10b5..2f99b7a248 100644 --- a/e-util/e-web-view.h +++ b/e-util/e-web-view.h @@ -186,6 +186,7 @@ void e_web_view_update_actions (EWebView *web_view); gchar * e_web_view_get_selection_html (EWebView *web_view); void e_web_view_update_fonts (EWebView *web_view); void e_web_view_cursor_image_copy (EWebView *web_view); +void e_web_view_cursor_image_save (EWebView *web_view); void e_web_view_request (EWebView *web_view, const gchar *uri, GCancellable *cancellable, -- cgit