evolution-3.6.4/widgets/misc/e-mail-signature-editor.c

No issues found

Incomplete coverage

Tool Failure ID Location Function Message Data
clang-analyzer no-output-found e-mail-signature-editor.c Message(text='Unable to locate XML output from invoke-clang-analyzer') None
clang-analyzer no-output-found e-mail-signature-editor.c Message(text='Unable to locate XML output from invoke-clang-analyzer') None
Failure running clang-analyzer ('no-output-found')
Message
Unable to locate XML output from invoke-clang-analyzer
Failure running clang-analyzer ('no-output-found')
Message
Unable to locate XML output from invoke-clang-analyzer
  1 /*
  2  * e-mail-signature-editor.c
  3  *
  4  * This program is free software; you can redistribute it and/or
  5  * modify it under the terms of the GNU Lesser General Public
  6  * License as published by the Free Software Foundation; either
  7  * version 2 of the License, or (at your option) version 3.
  8  *
  9  * This program is distributed in the hope that it will be useful,
 10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 12  * Lesser General Public License for more details.
 13  *
 14  * You should have received a copy of the GNU Lesser General Public
 15  * License along with the program; if not, see <http://www.gnu.org/licenses/>
 16  *
 17  */
 18 
 19 #include "e-mail-signature-editor.h"
 20 
 21 #include <string.h>
 22 #include <glib/gi18n.h>
 23 
 24 #include <libevolution-utils/e-alert-dialog.h>
 25 #include <libevolution-utils/e-alert-sink.h>
 26 #include <misc/e-alert-bar.h>
 27 #include <misc/e-web-view-gtkhtml.h>
 28 
 29 #define E_MAIL_SIGNATURE_EDITOR_GET_PRIVATE(obj) \
 30 	(G_TYPE_INSTANCE_GET_PRIVATE \
 31 	((obj), E_TYPE_MAIL_SIGNATURE_EDITOR, EMailSignatureEditorPrivate))
 32 
 33 typedef struct _AsyncContext AsyncContext;
 34 
 35 struct _EMailSignatureEditorPrivate {
 36 	GtkActionGroup *action_group;
 37 	EFocusTracker *focus_tracker;
 38 	GCancellable *cancellable;
 39 	ESourceRegistry *registry;
 40 	ESource *source;
 41 	gchar *original_name;
 42 
 43 	GtkWidget *entry;		/* not referenced */
 44 	GtkWidget *alert_bar;		/* not referenced */
 45 };
 46 
 47 struct _AsyncContext {
 48 	ESource *source;
 49 	GCancellable *cancellable;
 50 	gchar *contents;
 51 	gsize length;
 52 };
 53 
 54 enum {
 55 	PROP_0,
 56 	PROP_FOCUS_TRACKER,
 57 	PROP_REGISTRY,
 58 	PROP_SOURCE
 59 };
 60 
 61 static const gchar *ui =
 62 "<ui>\n"
 63 "  <menubar name='main-menu'>\n"
 64 "    <placeholder name='pre-edit-menu'>\n"
 65 "      <menu action='file-menu'>\n"
 66 "        <menuitem action='save-and-close'/>\n"
 67 "        <separator/>"
 68 "        <menuitem action='close'/>\n"
 69 "      </menu>\n"
 70 "    </placeholder>\n"
 71 "  </menubar>\n"
 72 "  <toolbar name='main-toolbar'>\n"
 73 "    <placeholder name='pre-main-toolbar'>\n"
 74 "      <toolitem action='save-and-close'/>\n"
 75 "    </placeholder>\n"
 76 "  </toolbar>\n"
 77 "</ui>";
 78 
 79 /* Forward Declarations */
 80 static void	e_mail_signature_editor_alert_sink_init
 81 					(EAlertSinkInterface *interface);
 82 
 83 G_DEFINE_TYPE_WITH_CODE (
 84 	EMailSignatureEditor,
 85 	e_mail_signature_editor,
 86 	GTKHTML_TYPE_EDITOR,
 87 	G_IMPLEMENT_INTERFACE (
 88 		E_TYPE_ALERT_SINK,
 89 		e_mail_signature_editor_alert_sink_init))
 90 
 91 static void
 92 async_context_free (AsyncContext *async_context)
 93 {
 94 	if (async_context->source != NULL)
 95 		g_object_unref (async_context->source);
 96 
 97 	if (async_context->cancellable != NULL)
 98 		g_object_unref (async_context->cancellable);
 99 
100 	g_free (async_context->contents);
101 
102 	g_slice_free (AsyncContext, async_context);
103 }
104 
105 static void
106 mail_signature_editor_loaded_cb (GObject *object,
107                                  GAsyncResult *result,
108                                  gpointer user_data)
109 {
110 	ESource *source;
111 	EMailSignatureEditor *editor;
112 	ESourceMailSignature *extension;
113 	const gchar *extension_name;
114 	const gchar *mime_type;
115 	gchar *contents = NULL;
116 	gboolean is_html;
117 	GError *error = NULL;
118 
119 	source = E_SOURCE (object);
120 	editor = E_MAIL_SIGNATURE_EDITOR (user_data);
121 
122 	e_source_mail_signature_load_finish (
123 		source, result, &contents, NULL, &error);
124 
125 	/* Ignore cancellations. */
126 	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
127 		g_warn_if_fail (contents == NULL);
128 		g_object_unref (editor);
129 		g_error_free (error);
130 		return;
131 
132 	} else if (error != NULL) {
133 		g_warn_if_fail (contents == NULL);
134 		e_alert_submit (
135 			E_ALERT_SINK (editor),
136 			"widgets:no-load-signature",
137 			error->message, NULL);
138 		g_object_unref (editor);
139 		g_error_free (error);
140 		return;
141 	}
142 
143 	g_return_if_fail (contents != NULL);
144 
145 	/* The load operation should have set the MIME type. */
146 	extension_name = E_SOURCE_EXTENSION_MAIL_SIGNATURE;
147 	extension = e_source_get_extension (source, extension_name);
148 	mime_type = e_source_mail_signature_get_mime_type (extension);
149 	is_html = (g_strcmp0 (mime_type, "text/html") == 0);
150 
151 	gtkhtml_editor_set_html_mode (GTKHTML_EDITOR (editor), is_html);
152 
153 	if (is_html) {
154 		gtkhtml_editor_insert_html (
155 			GTKHTML_EDITOR (editor), contents);
156 	} else {
157 		gtkhtml_editor_insert_text (
158 			GTKHTML_EDITOR (editor), contents);
159 
160 		gtkhtml_editor_run_command (GTKHTML_EDITOR (editor), "cursor-position-save");
161 		gtkhtml_editor_run_command (GTKHTML_EDITOR (editor), "select-all");
162 		gtkhtml_editor_run_command (GTKHTML_EDITOR (editor), "style-pre");
163 		gtkhtml_editor_run_command (GTKHTML_EDITOR (editor), "unselect-all");
164 		gtkhtml_editor_run_command (GTKHTML_EDITOR (editor), "cursor-position-restore");
165 	}
166 
167 	g_free (contents);
168 
169 	g_object_unref (editor);
170 }
171 
172 static gboolean
173 mail_signature_editor_delete_event_cb (EMailSignatureEditor *editor,
174                                        GdkEvent *event)
175 {
176 	GtkActionGroup *action_group;
177 	GtkAction *action;
178 
179 	action_group = editor->priv->action_group;
180 	action = gtk_action_group_get_action (action_group, "close");
181 	gtk_action_activate (action);
182 
183 	return TRUE;
184 }
185 
186 static void
187 action_close_cb (GtkAction *action,
188                  EMailSignatureEditor *editor)
189 {
190 	gboolean something_changed = FALSE;
191 	const gchar *original_name;
192 	const gchar *signature_name;
193 
194 	original_name = editor->priv->original_name;
195 	signature_name = gtk_entry_get_text (GTK_ENTRY (editor->priv->entry));
196 
197 	something_changed |= gtkhtml_editor_has_undo (GTKHTML_EDITOR (editor));
198 	something_changed |= (strcmp (signature_name, original_name) != 0);
199 
200 	if (something_changed) {
201 		gint response;
202 
203 		response = e_alert_run_dialog_for_args (
204 			GTK_WINDOW (editor),
205 			"widgets:ask-signature-changed", NULL);
206 		if (response == GTK_RESPONSE_YES) {
207 			GtkActionGroup *action_group;
208 
209 			action_group = editor->priv->action_group;
210 			action = gtk_action_group_get_action (
211 				action_group, "save-and-close");
212 			gtk_action_activate (action);
213 			return;
214 		} else if (response == GTK_RESPONSE_CANCEL)
215 			return;
216 	}
217 
218 	gtk_widget_destroy (GTK_WIDGET (editor));
219 }
220 
221 static void
222 action_save_and_close_cb (GtkAction *action,
223                           EMailSignatureEditor *editor)
224 {
225 	GtkEntry *entry;
226 	EAsyncClosure *closure;
227 	GAsyncResult *result;
228 	ESource *source;
229 	gchar *display_name;
230 	GError *error = NULL;
231 
232 	entry = GTK_ENTRY (editor->priv->entry);
233 	source = e_mail_signature_editor_get_source (editor);
234 
235 	display_name = g_strstrip (g_strdup (gtk_entry_get_text (entry)));
236 
237 	/* Make sure the signature name is not blank. */
238 	if (*display_name == '\0') {
239 		e_alert_submit (
240 			E_ALERT_SINK (editor),
241 			"widgets:blank-signature", NULL);
242 		gtk_widget_grab_focus (GTK_WIDGET (entry));
243 		g_free (display_name);
244 		return;
245 	}
246 
247 	e_source_set_display_name (source, display_name);
248 
249 	g_free (display_name);
250 
251 	/* Cancel any ongoing load or save operations. */
252 	if (editor->priv->cancellable != NULL) {
253 		g_cancellable_cancel (editor->priv->cancellable);
254 		g_object_unref (editor->priv->cancellable);
255 	}
256 
257 	editor->priv->cancellable = g_cancellable_new ();
258 
259 	closure = e_async_closure_new ();
260 
261 	e_mail_signature_editor_commit (
262 		editor, editor->priv->cancellable,
263 		e_async_closure_callback, closure);
264 
265 	result = e_async_closure_wait (closure);
266 
267 	e_mail_signature_editor_commit_finish (editor, result, &error);
268 
269 	e_async_closure_free (closure);
270 
271 	/* Ignore cancellations. */
272 	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
273 		g_error_free (error);
274 
275 	} else if (error != NULL) {
276 		e_alert_submit (
277 			E_ALERT_SINK (editor),
278 			"widgets:no-save-signature",
279 			error->message, NULL);
280 		g_error_free (error);
281 
282 	/* Only destroy the editor if the save was successful. */
283 	} else {
284 		gtk_widget_destroy (GTK_WIDGET (editor));
285 	}
286 }
287 
288 static GtkActionEntry entries[] = {
289 
290 	{ "close",
291 	  GTK_STOCK_CLOSE,
292 	  N_("_Close"),
293 	  "<Control>w",
294 	  N_("Close"),
295 	  G_CALLBACK (action_close_cb) },
296 
297 	{ "save-and-close",
298 	  GTK_STOCK_SAVE,
299 	  N_("_Save and Close"),
300 	  "<Control>Return",
301 	  N_("Save and Close"),
302 	  G_CALLBACK (action_save_and_close_cb) },
303 
304 	{ "file-menu",
305 	  NULL,
306 	  N_("_File"),
307 	  NULL,
308 	  NULL,
309 	  NULL }
310 };
311 
312 static void
313 mail_signature_editor_set_registry (EMailSignatureEditor *editor,
314                                     ESourceRegistry *registry)
315 {
316 	g_return_if_fail (E_IS_SOURCE_REGISTRY (registry));
317 	g_return_if_fail (editor->priv->registry == NULL);
318 
319 	editor->priv->registry = g_object_ref (registry);
320 }
321 
322 static void
323 mail_signature_editor_set_source (EMailSignatureEditor *editor,
324                                   ESource *source)
325 {
326 	GDBusObject *dbus_object = NULL;
327 	const gchar *extension_name;
328 	GError *error = NULL;
329 
330 	g_return_if_fail (source == NULL || E_IS_SOURCE (source));
331 	g_return_if_fail (editor->priv->source == NULL);
332 
333 	if (source != NULL)
334 		dbus_object = e_source_ref_dbus_object (source);
335 
336 	/* Clone the source so we can make changes to it freely. */
337 	editor->priv->source = e_source_new (dbus_object, NULL, &error);
338 
339 	if (dbus_object != NULL)
340 		g_object_unref (dbus_object);
341 
342 	/* This should rarely fail.  If the file was loaded successfully
343 	 * once then it should load successfully here as well, unless an
344 	 * I/O error occurs. */
345 	if (error != NULL) {
346 		g_warning ("%s: %s", G_STRFUNC, error->message);
347 		g_error_free (error);
348 	}
349 
350 	/* Make sure the source has a mail signature extension. */
351 	extension_name = E_SOURCE_EXTENSION_MAIL_SIGNATURE;
352 	e_source_get_extension (editor->priv->source, extension_name);
353 }
354 
355 static void
356 mail_signature_editor_set_property (GObject *object,
357                                     guint property_id,
358                                     const GValue *value,
359                                     GParamSpec *pspec)
360 {
361 	switch (property_id) {
362 		case PROP_REGISTRY:
363 			mail_signature_editor_set_registry (
364 				E_MAIL_SIGNATURE_EDITOR (object),
365 				g_value_get_object (value));
366 			return;
367 
368 		case PROP_SOURCE:
369 			mail_signature_editor_set_source (
370 				E_MAIL_SIGNATURE_EDITOR (object),
371 				g_value_get_object (value));
372 			return;
373 	}
374 
375 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
376 }
377 
378 static void
379 mail_signature_editor_get_property (GObject *object,
380                                     guint property_id,
381                                     GValue *value,
382                                     GParamSpec *pspec)
383 {
384 	switch (property_id) {
385 		case PROP_FOCUS_TRACKER:
386 			g_value_set_object (
387 				value,
388 				e_mail_signature_editor_get_focus_tracker (
389 				E_MAIL_SIGNATURE_EDITOR (object)));
390 			return;
391 
392 		case PROP_REGISTRY:
393 			g_value_set_object (
394 				value,
395 				e_mail_signature_editor_get_registry (
396 				E_MAIL_SIGNATURE_EDITOR (object)));
397 			return;
398 
399 		case PROP_SOURCE:
400 			g_value_set_object (
401 				value,
402 				e_mail_signature_editor_get_source (
403 				E_MAIL_SIGNATURE_EDITOR (object)));
404 			return;
405 	}
406 
407 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
408 }
409 
410 static void
411 mail_signature_editor_dispose (GObject *object)
412 {
413 	EMailSignatureEditorPrivate *priv;
414 
415 	priv = E_MAIL_SIGNATURE_EDITOR_GET_PRIVATE (object);
416 
417 	if (priv->action_group != NULL) {
418 		g_object_unref (priv->action_group);
419 		priv->action_group = NULL;
420 	}
421 
422 	if (priv->focus_tracker != NULL) {
423 		g_object_unref (priv->focus_tracker);
424 		priv->focus_tracker = NULL;
425 	}
426 
427 	if (priv->cancellable != NULL) {
428 		g_cancellable_cancel (priv->cancellable);
429 		g_object_unref (priv->cancellable);
430 		priv->cancellable = NULL;
431 	}
432 
433 	if (priv->registry != NULL) {
434 		g_object_unref (priv->registry);
435 		priv->registry = NULL;
436 	}
437 
438 	if (priv->source != NULL) {
439 		g_object_unref (priv->source);
440 		priv->source = NULL;
441 	}
442 
443 	/* Chain up to parent's dispose() method. */
444 	G_OBJECT_CLASS (e_mail_signature_editor_parent_class)->
445 		dispose (object);
446 }
447 
448 static void
449 mail_signature_editor_finalize (GObject *object)
450 {
451 	EMailSignatureEditorPrivate *priv;
452 
453 	priv = E_MAIL_SIGNATURE_EDITOR_GET_PRIVATE (object);
454 
455 	g_free (priv->original_name);
456 
457 	/* Chain up to parent's finalize() method. */
458 	G_OBJECT_CLASS (e_mail_signature_editor_parent_class)->
459 		finalize (object);
460 }
461 
462 static void
463 mail_signature_editor_constructed (GObject *object)
464 {
465 	EMailSignatureEditor *editor;
466 	GtkActionGroup *action_group;
467 	EFocusTracker *focus_tracker;
468 	GtkhtmlEditor *gtkhtml_editor;
469 	GtkUIManager *ui_manager;
470 	GDBusObject *dbus_object;
471 	ESource *source;
472 	GtkAction *action;
473 	GtkWidget *container;
474 	GtkWidget *widget;
475 	const gchar *display_name;
476 	GError *error = NULL;
477 
478 	/* Chain up to parent's constructed() method. */
479 	G_OBJECT_CLASS (e_mail_signature_editor_parent_class)->
480 		constructed (object);
481 
482 	editor = E_MAIL_SIGNATURE_EDITOR (object);
483 
484 	gtkhtml_editor = GTKHTML_EDITOR (editor);
485 	ui_manager = gtkhtml_editor_get_ui_manager (gtkhtml_editor);
486 
487 	/* Because we are loading from a hard-coded string, there is
488 	 * no chance of I/O errors.  Failure here implies a malformed
489 	 * UI definition.  Full stop. */
490 	gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, &error);
491 	if (error != NULL)
492 		g_error ("%s", error->message);
493 
494 	action_group = gtk_action_group_new ("signature");
495 	gtk_action_group_set_translation_domain (
496 		action_group, GETTEXT_PACKAGE);
497 	gtk_action_group_add_actions (
498 		action_group, entries,
499 		G_N_ELEMENTS (entries), editor);
500 	gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
501 	editor->priv->action_group = g_object_ref (action_group);
502 
503 	/* Hide page properties because it is not inherited in the mail. */
504 	action = gtkhtml_editor_get_action (gtkhtml_editor, "properties-page");
505 	gtk_action_set_visible (action, FALSE);
506 
507 	action = gtkhtml_editor_get_action (
508 		gtkhtml_editor, "context-properties-page");
509 	gtk_action_set_visible (action, FALSE);
510 
511 	gtk_ui_manager_ensure_update (ui_manager);
512 
513 	gtk_window_set_title (GTK_WINDOW (editor), _("Edit Signature"));
514 
515 	/* Construct the signature name entry. */
516 
517 	container = gtkhtml_editor->vbox;
518 
519 	widget = gtk_hbox_new (FALSE, 6);
520 	gtk_container_set_border_width (GTK_CONTAINER (widget), 6);
521 	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
522 	/* Position 2 should be between the main and style toolbars. */
523 	gtk_box_reorder_child (GTK_BOX (container), widget, 2);
524 	gtk_widget_show (widget);
525 
526 	container = widget;
527 
528 	widget = gtk_entry_new ();
529 	gtk_box_pack_end (GTK_BOX (container), widget, TRUE, TRUE, 0);
530 	editor->priv->entry = widget;  /* not referenced */
531 	gtk_widget_show (widget);
532 
533 	widget = gtk_label_new_with_mnemonic (_("_Signature Name:"));
534 	gtk_label_set_mnemonic_widget (GTK_LABEL (widget), editor->priv->entry);
535 	gtk_box_pack_end (GTK_BOX (container), widget, FALSE, FALSE, 0);
536 	gtk_widget_show (widget);
537 
538 	g_signal_connect (
539 		editor, "delete-event",
540 		G_CALLBACK (mail_signature_editor_delete_event_cb), NULL);
541 
542 	/* Construct the alert bar for errors. */
543 
544 	container = gtkhtml_editor->vbox;
545 
546 	widget = e_alert_bar_new ();
547 	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
548 	/* Position 5 should be between the style toolbar and editing area. */
549 	gtk_box_reorder_child (GTK_BOX (container), widget, 5);
550 	editor->priv->alert_bar = widget;  /* not referenced */
551 	/* EAlertBar controls its own visibility. */
552 
553 	/* Configure an EFocusTracker to manage selection actions.
554 	 *
555 	 * XXX GtkhtmlEditor does not manage its own selection actions,
556 	 *     which is technically a bug but works in our favor here
557 	 *     because it won't cause any conflicts with EFocusTracker. */
558 
559 	focus_tracker = e_focus_tracker_new (GTK_WINDOW (editor));
560 
561 	action = gtkhtml_editor_get_action (gtkhtml_editor, "cut");
562 	e_focus_tracker_set_cut_clipboard_action (focus_tracker, action);
563 
564 	action = gtkhtml_editor_get_action (gtkhtml_editor, "copy");
565 	e_focus_tracker_set_copy_clipboard_action (focus_tracker, action);
566 
567 	action = gtkhtml_editor_get_action (gtkhtml_editor, "paste");
568 	e_focus_tracker_set_paste_clipboard_action (focus_tracker, action);
569 
570 	action = gtkhtml_editor_get_action (gtkhtml_editor, "select-all");
571 	e_focus_tracker_set_select_all_action (focus_tracker, action);
572 
573 	editor->priv->focus_tracker = focus_tracker;
574 
575 	source = e_mail_signature_editor_get_source (editor);
576 
577 	display_name = e_source_get_display_name (source);
578 	if (display_name == NULL || *display_name == '\0')
579 		display_name = _("Unnamed");
580 
581 	/* Set the entry text before we grab focus. */
582 	g_free (editor->priv->original_name);
583 	editor->priv->original_name = g_strdup (display_name);
584 	gtk_entry_set_text (GTK_ENTRY (editor->priv->entry), display_name);
585 
586 	/* Set the focus appropriately.  If this is a new signature, draw
587 	 * the user's attention to the signature name entry.  Otherwise go
588 	 * straight to the editing area. */
589 	if (source == NULL)
590 		gtk_widget_grab_focus (editor->priv->entry);
591 	else {
592 		GtkHTML *html;
593 
594 		html = gtkhtml_editor_get_html (gtkhtml_editor);
595 		gtk_widget_grab_focus (GTK_WIDGET (html));
596 	}
597 
598 	/* Load file content only for an existing signature.
599 	 * (A new signature will not yet have a GDBusObject.) */
600 	dbus_object = e_source_ref_dbus_object (source);
601 	if (dbus_object != NULL) {
602 		GCancellable *cancellable;
603 
604 		cancellable = g_cancellable_new ();
605 
606 		e_source_mail_signature_load (
607 			source,
608 			G_PRIORITY_DEFAULT,
609 			cancellable,
610 			mail_signature_editor_loaded_cb,
611 			g_object_ref (editor));
612 
613 		g_warn_if_fail (editor->priv->cancellable == NULL);
614 		editor->priv->cancellable = cancellable;
615 
616 		g_object_unref (dbus_object);
617 	}
618 }
619 
620 static void
621 mail_signature_editor_cut_clipboard (GtkhtmlEditor *editor)
622 {
623 	/* Do nothing.  EFocusTracker handles this. */
624 }
625 
626 static void
627 mail_signature_editor_copy_clipboard (GtkhtmlEditor *editor)
628 {
629 	/* Do nothing.  EFocusTracker handles this. */
630 }
631 
632 static void
633 mail_signature_editor_paste_clipboard (GtkhtmlEditor *editor)
634 {
635 	/* Do nothing.  EFocusTracker handles this. */
636 }
637 
638 static void
639 mail_signature_editor_select_all (GtkhtmlEditor *editor)
640 {
641 	/* Do nothing.  EFocusTracker handles this. */
642 }
643 
644 static void
645 mail_signature_editor_submit_alert (EAlertSink *alert_sink,
646                                     EAlert *alert)
647 {
648 	EMailSignatureEditorPrivate *priv;
649 	EAlertBar *alert_bar;
650 	GtkWidget *dialog;
651 	GtkWindow *parent;
652 
653 	priv = E_MAIL_SIGNATURE_EDITOR_GET_PRIVATE (alert_sink);
654 
655 	switch (e_alert_get_message_type (alert)) {
656 		case GTK_MESSAGE_INFO:
657 		case GTK_MESSAGE_WARNING:
658 		case GTK_MESSAGE_ERROR:
659 			alert_bar = E_ALERT_BAR (priv->alert_bar);
660 			e_alert_bar_add_alert (alert_bar, alert);
661 			break;
662 
663 		default:
664 			parent = GTK_WINDOW (alert_sink);
665 			dialog = e_alert_dialog_new (parent, alert);
666 			gtk_dialog_run (GTK_DIALOG (dialog));
667 			gtk_widget_destroy (dialog);
668 			break;
669 	}
670 }
671 
672 static void
673 e_mail_signature_editor_class_init (EMailSignatureEditorClass *class)
674 {
675 	GObjectClass *object_class;
676 	GtkhtmlEditorClass *editor_class;
677 
678 	g_type_class_add_private (class, sizeof (EMailSignatureEditorPrivate));
679 
680 	object_class = G_OBJECT_CLASS (class);
681 	object_class->set_property = mail_signature_editor_set_property;
682 	object_class->get_property = mail_signature_editor_get_property;
683 	object_class->dispose = mail_signature_editor_dispose;
684 	object_class->finalize = mail_signature_editor_finalize;
685 	object_class->constructed = mail_signature_editor_constructed;
686 
687 	editor_class = GTKHTML_EDITOR_CLASS (class);
688 	editor_class->cut_clipboard = mail_signature_editor_cut_clipboard;
689 	editor_class->copy_clipboard = mail_signature_editor_copy_clipboard;
690 	editor_class->paste_clipboard = mail_signature_editor_paste_clipboard;
691 	editor_class->select_all = mail_signature_editor_select_all;
692 
693 	g_object_class_install_property (
694 		object_class,
695 		PROP_FOCUS_TRACKER,
696 		g_param_spec_object (
697 			"focus-tracker",
698 			NULL,
699 			NULL,
700 			E_TYPE_FOCUS_TRACKER,
701 			G_PARAM_READABLE |
702 			G_PARAM_STATIC_STRINGS));
703 
704 	g_object_class_install_property (
705 		object_class,
706 		PROP_REGISTRY,
707 		g_param_spec_object (
708 			"registry",
709 			"Registry",
710 			"Data source registry",
711 			E_TYPE_SOURCE_REGISTRY,
712 			G_PARAM_READWRITE |
713 			G_PARAM_CONSTRUCT_ONLY |
714 			G_PARAM_STATIC_STRINGS));
715 
716 	g_object_class_install_property (
717 		object_class,
718 		PROP_SOURCE,
719 		g_param_spec_object (
720 			"source",
721 			NULL,
722 			NULL,
723 			E_TYPE_SOURCE,
724 			G_PARAM_READWRITE |
725 			G_PARAM_CONSTRUCT_ONLY |
726 			G_PARAM_STATIC_STRINGS));
727 }
728 
729 static void
730 e_mail_signature_editor_alert_sink_init (EAlertSinkInterface *interface)
731 {
732 	interface->submit_alert = mail_signature_editor_submit_alert;
733 }
734 
735 static void
736 e_mail_signature_editor_init (EMailSignatureEditor *editor)
737 {
738 	editor->priv = E_MAIL_SIGNATURE_EDITOR_GET_PRIVATE (editor);
739 }
740 
741 GtkWidget *
742 e_mail_signature_editor_new (ESourceRegistry *registry,
743                              ESource *source)
744 {
745 	g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
746 
747 	if (source != NULL)
748 		g_return_val_if_fail (E_IS_SOURCE (source), NULL);
749 
750 	return g_object_new (
751 		E_TYPE_MAIL_SIGNATURE_EDITOR,
752 		"html", e_web_view_gtkhtml_new (),
753 		"registry", registry,
754 		"source", source, NULL);
755 }
756 
757 EFocusTracker *
758 e_mail_signature_editor_get_focus_tracker (EMailSignatureEditor *editor)
759 {
760 	g_return_val_if_fail (E_IS_MAIL_SIGNATURE_EDITOR (editor), NULL);
761 
762 	return editor->priv->focus_tracker;
763 }
764 
765 ESourceRegistry *
766 e_mail_signature_editor_get_registry (EMailSignatureEditor *editor)
767 {
768 	g_return_val_if_fail (E_IS_MAIL_SIGNATURE_EDITOR (editor), NULL);
769 
770 	return editor->priv->registry;
771 }
772 
773 ESource *
774 e_mail_signature_editor_get_source (EMailSignatureEditor *editor)
775 {
776 	g_return_val_if_fail (E_IS_MAIL_SIGNATURE_EDITOR (editor), NULL);
777 
778 	return editor->priv->source;
779 }
780 
781 /********************** e_mail_signature_editor_commit() *********************/
782 
783 static void
784 mail_signature_editor_replace_cb (GObject *object,
785                                   GAsyncResult *result,
786                                   gpointer user_data)
787 {
788 	GSimpleAsyncResult *simple;
789 	GError *error = NULL;
790 
791 	simple = G_SIMPLE_ASYNC_RESULT (user_data);
792 
793 	e_source_mail_signature_replace_finish (
794 		E_SOURCE (object), result, &error);
795 
796 	if (error != NULL)
797 		g_simple_async_result_take_error (simple, error);
798 
799 	g_simple_async_result_complete (simple);
800 
801 	g_object_unref (simple);
802 }
803 
804 static void
805 mail_signature_editor_commit_cb (GObject *object,
806                                  GAsyncResult *result,
807                                  gpointer user_data)
808 {
809 	GSimpleAsyncResult *simple;
810 	AsyncContext *async_context;
811 	GError *error = NULL;
812 
813 	simple = G_SIMPLE_ASYNC_RESULT (user_data);
814 	async_context = g_simple_async_result_get_op_res_gpointer (simple);
815 
816 	e_source_registry_commit_source_finish (
817 		E_SOURCE_REGISTRY (object), result, &error);
818 
819 	if (error != NULL) {
820 		g_simple_async_result_take_error (simple, error);
821 		g_simple_async_result_complete (simple);
822 		g_object_unref (simple);
823 		return;
824 	}
825 
826 	/* We can call this on our scratch source because only its UID is
827 	 * really needed, which even a new scratch source already knows. */
828 	e_source_mail_signature_replace (
829 		async_context->source,
830 		async_context->contents,
831 		async_context->length,
832 		G_PRIORITY_DEFAULT,
833 		async_context->cancellable,
834 		mail_signature_editor_replace_cb,
835 		simple);
836 }
837 
838 void
839 e_mail_signature_editor_commit (EMailSignatureEditor *editor,
840                                 GCancellable *cancellable,
841                                 GAsyncReadyCallback callback,
842                                 gpointer user_data)
843 {
844 	GSimpleAsyncResult *simple;
845 	AsyncContext *async_context;
846 	ESourceMailSignature *extension;
847 	ESourceRegistry *registry;
848 	ESource *source;
849 	const gchar *extension_name;
850 	const gchar *mime_type;
851 	gchar *contents;
852 	gboolean is_html;
853 	gsize length;
854 
855 	g_return_if_fail (E_IS_MAIL_SIGNATURE_EDITOR (editor));
856 
857 	registry = e_mail_signature_editor_get_registry (editor);
858 	source = e_mail_signature_editor_get_source (editor);
859 	is_html = gtkhtml_editor_get_html_mode (GTKHTML_EDITOR (editor));
860 
861 	if (is_html) {
862 		mime_type = "text/html";
863 		contents = gtkhtml_editor_get_text_html (
864 			GTKHTML_EDITOR (editor), &length);
865 	} else {
866 		mime_type = "text/plain";
867 		contents = gtkhtml_editor_get_text_plain (
868 			GTKHTML_EDITOR (editor), &length);
869 	}
870 
871 	extension_name = E_SOURCE_EXTENSION_MAIL_SIGNATURE;
872 	extension = e_source_get_extension (source, extension_name);
873 	e_source_mail_signature_set_mime_type (extension, mime_type);
874 
875 	async_context = g_slice_new0 (AsyncContext);
876 	async_context->source = g_object_ref (source);
877 	async_context->contents = contents;  /* takes ownership */
878 	async_context->length = length;
879 
880 	if (G_IS_CANCELLABLE (cancellable))
881 		async_context->cancellable = g_object_ref (cancellable);
882 
883 	simple = g_simple_async_result_new (
884 		G_OBJECT (editor), callback, user_data,
885 		e_mail_signature_editor_commit);
886 
887 	g_simple_async_result_set_op_res_gpointer (
888 		simple, async_context, (GDestroyNotify) async_context_free);
889 
890 	e_source_registry_commit_source (
891 		registry, source,
892 		async_context->cancellable,
893 		mail_signature_editor_commit_cb,
894 		simple);
895 }
896 
897 gboolean
898 e_mail_signature_editor_commit_finish (EMailSignatureEditor *editor,
899                                        GAsyncResult *result,
900                                        GError **error)
901 {
902 	GSimpleAsyncResult *simple;
903 
904 	g_return_val_if_fail (
905 		g_simple_async_result_is_valid (
906 		result, G_OBJECT (editor),
907 		e_mail_signature_editor_commit), FALSE);
908 
909 	simple = G_SIMPLE_ASYNC_RESULT (result);
910 
911 	/* Assume success unless a GError is set. */
912 	return !g_simple_async_result_propagate_error (simple, error);
913 }