[evolution] Bug 751588 - Port to WebKit2
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution] Bug 751588 - Port to WebKit2
- Date: Thu, 11 Aug 2016 08:12:20 +0000 (UTC)
commit 332789ff89d85f8302ae53d6abe2cd993cd28eea
Author: Tomas Popela <tpopela redhat com>
Date: Thu Aug 11 10:13:00 2016 +0200
Bug 751588 - Port to WebKit2
Makefile.am | 1 +
addressbook/gui/contact-editor/e-contact-editor.c | 4 +-
addressbook/gui/widgets/eab-contact-display.c | 39 +-
addressbook/gui/widgets/eab-contact-formatter.c | 61 -
addressbook/gui/widgets/eab-contact-formatter.h | 1 -
calendar/gui/e-comp-editor-page-attachments.c | 12 +-
calendar/gui/itip-utils.c | 234 +-
composer/e-composer-actions.c | 98 +-
composer/e-composer-private.c | 60 +-
composer/e-composer-private.h | 6 +-
composer/e-msg-composer.c | 978 +-
composer/e-msg-composer.h | 13 +-
configure.ac | 22 +-
data/org.gnome.evolution.mail.gschema.xml.in | 15 +-
doc/reference/evolution-util/Makefile.am | 1 -
e-util/Makefile.am | 24 +-
e-util/e-attachment-bar.c | 77 +-
e-util/e-attachment-button.c | 929 --
e-util/e-attachment-button.h | 95 -
e-util/e-attachment-store.c | 227 +-
e-util/e-attachment-store.h | 15 +
e-util/e-attachment-view.c | 242 +-
e-util/e-attachment.c | 303 +-
e-util/e-attachment.h | 29 +-
e-util/e-content-editor.c | 3583 ++++
e-util/e-content-editor.h | 1021 ++
e-util/e-content-request.c | 188 +
e-util/e-content-request.h | 93 +
e-util/e-emoticon.c | 6 +
e-util/e-emoticon.h | 1 +
e-util/e-file-request.c | 222 +-
e-util/e-file-request.h | 11 +-
e-util/e-focus-tracker.c | 12 +-
e-util/e-html-editor-actions.c | 828 +-
e-util/e-html-editor-actions.h | 8 +-
e-util/e-html-editor-cell-dialog.c | 609 +-
e-util/e-html-editor-cell-dialog.h | 2 -
e-util/e-html-editor-dialog.h | 10 +
e-util/e-html-editor-find-dialog.c | 128 +-
e-util/e-html-editor-hrule-dialog.c | 275 +-
e-util/e-html-editor-hrule-dialog.h | 2 -
e-util/e-html-editor-image-dialog.c | 358 +-
e-util/e-html-editor-image-dialog.h | 3 +-
e-util/e-html-editor-link-dialog.c | 282 +-
e-util/e-html-editor-link-dialog.h | 2 -
e-util/e-html-editor-manager.ui | 7 +-
e-util/e-html-editor-page-dialog.c | 235 +-
e-util/e-html-editor-private.h | 16 +-
e-util/e-html-editor-replace-dialog.c | 242 +-
e-util/e-html-editor-selection.c | 8120 ---------
e-util/e-html-editor-selection.h | 258 -
e-util/e-html-editor-spell-check-dialog.c | 313 +-
e-util/e-html-editor-table-dialog.c | 630 +-
e-util/e-html-editor-text-dialog.c | 85 +-
e-util/e-html-editor-utils.c | 653 -
e-util/e-html-editor-utils.h | 115 -
e-util/e-html-editor-view.c |15621 ------------------
e-util/e-html-editor-view.h | 342 -
e-util/e-html-editor.c | 528 +-
e-util/e-html-editor.h | 20 +-
e-util/e-mail-signature-editor.c | 162 +-
e-util/e-mail-signature-editor.h | 9 +-
e-util/e-mail-signature-manager.c | 79 +-
e-util/e-mail-signature-preview.c | 86 +-
e-util/e-marshal.list | 1 +
e-util/e-misc-utils.c | 54 +-
e-util/e-misc-utils.h | 6 +-
e-util/e-search-bar.c | 193 +-
e-util/e-simple-async-result.c | 221 +
e-util/e-simple-async-result.h | 90 +
e-util/e-spell-checker.c | 399 +-
e-util/e-spell-checker.h | 8 +
e-util/e-stock-request.c | 310 +-
e-util/e-stock-request.h | 11 +-
e-util/e-util-enums.h | 479 +-
e-util/e-util.h | 19 +-
e-util/e-web-view-preview.c | 12 +-
e-util/e-web-view.c | 2225 ++-
e-util/e-web-view.h | 102 +-
e-util/test-html-editor-units-utils.c | 1045 ++
e-util/test-html-editor-units-utils.h | 89 +
e-util/test-html-editor-units.c | 2823 ++++
e-util/test-html-editor.c | 206 +-
em-format/Makefile.am | 7 +-
em-format/e-mail-formatter-attachment-bar.c | 104 -
em-format/e-mail-formatter-attachment.c | 254 +-
em-format/e-mail-formatter-audio.c | 2 +-
em-format/e-mail-formatter-enums.h | 1 -
em-format/e-mail-formatter-extension.c | 61 -
em-format/e-mail-formatter-extension.h | 11 -
em-format/e-mail-formatter-headers.c | 4 +-
em-format/e-mail-formatter-message-rfc822.c | 4 -
em-format/e-mail-formatter-quote-attachment.c | 127 -
em-format/e-mail-formatter-quote-message-rfc822.c | 4 -
em-format/e-mail-formatter-quote.c | 2 -
em-format/e-mail-formatter-secure-button.c | 395 +-
em-format/e-mail-formatter.c | 35 +-
em-format/e-mail-formatter.h | 6 +-
em-format/e-mail-parser-application-smime.c | 2 +-
em-format/e-mail-parser-attachment-bar.c | 78 -
em-format/e-mail-parser-inlinepgp-encrypted.c | 2 +-
em-format/e-mail-parser-inlinepgp-signed.c | 2 +-
em-format/e-mail-parser-message.c | 6 -
em-format/e-mail-parser-multipart-encrypted.c | 2 +-
em-format/e-mail-parser-multipart-signed.c | 2 +-
em-format/e-mail-parser-secure-button.c | 5 +-
em-format/e-mail-parser-text-plain.c | 2 +-
em-format/e-mail-parser.c | 6 +-
em-format/e-mail-part-attachment-bar.c | 98 -
em-format/e-mail-part-attachment-bar.h | 70 -
em-format/e-mail-part-attachment.c | 2 +-
em-format/e-mail-part-attachment.h | 2 +-
em-format/e-mail-part-headers.c | 36 +-
em-format/e-mail-part-secure-button.c | 321 +
em-format/e-mail-part-secure-button.h | 61 +
em-format/e-mail-part-utils.c | 5 +
em-format/e-mail-part.c | 25 +-
em-format/e-mail-part.h | 13 +-
mail/Makefile.am | 2 +
mail/e-cid-request.c | 146 +
mail/e-cid-request.h | 62 +
mail/e-http-request.c | 335 +-
mail/e-http-request.h | 12 +-
mail/e-mail-browser.c | 57 +-
mail/e-mail-config-identity-page.c | 26 +-
mail/e-mail-display-popup-extension.c | 6 +-
mail/e-mail-display-popup-extension.h | 5 +-
mail/e-mail-display.c | 2115 ++--
mail/e-mail-display.h | 14 +-
mail/e-mail-notes.c | 207 +-
mail/e-mail-paned-view.c | 14 +-
mail/e-mail-printer.c | 136 +-
mail/e-mail-reader-utils.c | 389 +-
mail/e-mail-reader.c | 148 +-
mail/e-mail-request.c | 573 +-
mail/e-mail-request.h | 11 +-
mail/em-composer-utils.c | 397 +-
mail/em-composer-utils.h | 15 +-
modules/Makefile.am | 3 +-
modules/addressbook/eab-composer-util.c | 279 +-
modules/composer-autosave/e-autosave-utils.c | 60 +-
modules/composer-autosave/e-composer-autosave.c | 12 +-
modules/itip-formatter/Makefile.am | 5 +-
modules/itip-formatter/e-mail-formatter-itip.c | 23 +-
modules/itip-formatter/e-mail-parser-itip.c | 21 +-
modules/itip-formatter/e-mail-part-itip.c | 111 +-
modules/itip-formatter/e-mail-part-itip.h | 74 +-
.../itip-formatter/itip-view-elements-defines.h | 65 +
modules/itip-formatter/itip-view.c | 2583 ++--
modules/itip-formatter/itip-view.h | 26 +-
modules/itip-formatter/web-extension/Makefile.am | 26 +
.../module-itip-formatter-dom-utils.c | 642 +
.../module-itip-formatter-dom-utils.h | 111 +
.../module-itip-formatter-web-extension.c | 646 +
.../module-itip-formatter-web-extension.h | 26 +
modules/mail/e-mail-attachment-handler.c | 102 +-
modules/mail/e-mail-shell-backend.c | 34 +-
modules/mail/e-mail-shell-content.c | 44 +-
modules/mail/e-mail-shell-view-actions.c | 36 +
modules/mail/e-mail-shell-view-actions.h | 2 +
modules/mail/e-mail-shell-view-private.c | 60 +-
modules/mail/e-mail-shell-view-private.h | 2 +
modules/mail/em-composer-prefs.c | 3 +-
.../e-mail-display-popup-prefer-plain.c | 86 +-
modules/settings/Makefile.am | 4 +-
modules/settings/e-settings-content-editor.c | 224 +
modules/settings/e-settings-content-editor.h | 64 +
modules/settings/e-settings-html-editor-view.c | 223 -
modules/settings/e-settings-html-editor-view.h | 64 -
modules/settings/e-settings-spell-checker.c | 3 +-
modules/settings/evolution-module-settings.c | 6 +-
.../e-mail-display-popup-text-highlight.c | 98 +-
modules/vcard-inline/e-mail-formatter-vcard.c | 9 +-
modules/vcard-inline/e-mail-part-vcard.c | 222 +-
modules/vcard-inline/e-mail-part-vcard.h | 4 -
modules/web-inspector/evolution-web-inspector.c | 167 -
modules/webkit-editor/Makefile.am | 31 +
modules/webkit-editor/e-webkit-editor-extension.c | 101 +
modules/webkit-editor/e-webkit-editor-extension.h | 62 +
modules/webkit-editor/e-webkit-editor.c | 6291 +++++++
modules/webkit-editor/e-webkit-editor.h | 68 +
.../webkit-editor/evolution-module-webkit-editor.c | 36 +
modules/webkit-editor/web-extension/Makefile.am | 38 +
.../web-extension/e-composer-dom-functions.c | 832 +
.../web-extension/e-composer-dom-functions.h | 48 +
.../web-extension/e-dialogs-dom-functions.c | 1455 ++
.../web-extension/e-dialogs-dom-functions.h | 134 +
.../web-extension/e-editor-dom-functions.c |17386 ++++++++++++++++++++
.../web-extension/e-editor-dom-functions.h | 378 +
.../webkit-editor/web-extension/e-editor-page.c | 940 ++
.../webkit-editor/web-extension/e-editor-page.h | 197 +
.../web-extension/e-editor-undo-redo-manager.c | 2831 ++++
.../web-extension/e-editor-undo-redo-manager.h | 175 +
.../web-extension/e-editor-web-extension-main.c | 57 +
.../web-extension/e-editor-web-extension-names.h | 26 +
.../web-extension/e-editor-web-extension.c | 2501 +++
.../web-extension/e-editor-web-extension.h | 82 +
.../Makefile.am | 14 +-
.../webkit-inspector/evolution-webkit-inspector.c | 140 +
plugins/external-editor/external-editor.c | 153 +-
plugins/mail-to-task/mail-to-task.c | 14 +-
.../mailing-list-actions/mailing-list-actions.c | 51 +-
plugins/templates/templates.c | 93 +-
po/POTFILES.in | 4 +-
shell/e-shell.c | 4 +-
shell/main.c | 4 +-
ui/evolution-mail.ui | 1 +
web-extensions/Makefile.am | 44 +
web-extensions/e-dom-utils.c | 2022 +++
web-extensions/e-dom-utils.h | 169 +
web-extensions/e-web-extension-main.c | 61 +
web-extensions/e-web-extension-names.h | 26 +
web-extensions/e-web-extension.c | 999 ++
web-extensions/e-web-extension.h | 72 +
214 files changed, 59038 insertions(+), 38043 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index 8d65a34..addfd44 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -71,6 +71,7 @@ SUBDIRS = \
mail \
calendar \
art \
+ web-extensions \
plugins \
modules \
$(MAINT_SUBDIR) \
diff --git a/addressbook/gui/contact-editor/e-contact-editor.c
b/addressbook/gui/contact-editor/e-contact-editor.c
index 488fc32..4704528 100644
--- a/addressbook/gui/contact-editor/e-contact-editor.c
+++ b/addressbook/gui/contact-editor/e-contact-editor.c
@@ -995,7 +995,7 @@ fill_in_email (EContactEditor *editor)
email_location = eab_get_email_type_index (attr);
slot = get_ui_slot (attr);
if (slot < 1)
- slot = EMAIL_SLOTS + 1; //add at the end
+ slot = EMAIL_SLOTS + 1; /* add at the end */
gtk_list_store_append (data_store, &iter);
gtk_list_store_set (data_store, &iter,
@@ -2103,7 +2103,7 @@ fill_in_im (EContactEditor *editor)
slot = get_ui_slot (attr);
if (slot < 0)
- slot = IM_SLOTS + 1; //attach at the end
+ slot = IM_SLOTS + 1; /* attach at the end */
gtk_list_store_append (data_store, &iter);
gtk_list_store_set (data_store, &iter,
diff --git a/addressbook/gui/widgets/eab-contact-display.c b/addressbook/gui/widgets/eab-contact-display.c
index cd7fafd..8378563 100644
--- a/addressbook/gui/widgets/eab-contact-display.c
+++ b/addressbook/gui/widgets/eab-contact-display.c
@@ -28,7 +28,7 @@
#include <string.h>
#include <glib/gi18n.h>
-#include <webkit/webkit.h>
+#include <webkit2/webkit2.h>
#include "e-contact-map.h"
#include "eab-contact-formatter.h"
@@ -386,19 +386,31 @@ contact_display_object_requested (WebKitWebView *web_view,
#endif
static void
-contact_display_load_status_changed (WebKitWebView *web_view,
- GParamSpec *pspec,
- gpointer user_data)
+contact_display_load_changed (WebKitWebView *web_view,
+ WebKitLoadEvent load_event,
+ gpointer user_data)
{
- WebKitLoadStatus load_status;
- WebKitDOMDocument *document;
+ GDBusProxy *web_extension;
+ GVariant* result;
- load_status = webkit_web_view_get_load_status (web_view);
- if (load_status != WEBKIT_LOAD_FINISHED)
+ if (load_event != WEBKIT_LOAD_FINISHED)
return;
- document = webkit_web_view_get_dom_document (web_view);
- eab_contact_formatter_bind_dom (document);
+ web_extension = e_web_view_get_web_extension_proxy (E_WEB_VIEW (web_view));
+ if (web_extension) {
+ result = g_dbus_proxy_call_sync (
+ web_extension,
+ "EABContactFormatterBindDOM",
+ g_variant_new (
+ "(t)",
+ webkit_web_view_get_page_id (web_view)),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL, /* cancellable */
+ NULL);
+ if (result)
+ g_variant_unref (result);
+ }
}
static void
@@ -514,15 +526,12 @@ eab_contact_display_init (EABContactDisplay *display)
G_CALLBACK (contact_display_object_requested), display);
#endif
e_signal_connect_notify (
- web_view, "notify::load-status",
- G_CALLBACK (contact_display_load_status_changed), NULL);
+ web_view, "notify::load-changed",
+ G_CALLBACK (contact_display_load_changed), NULL);
g_signal_connect (
web_view, "style-updated",
G_CALLBACK (load_contact), NULL);
- e_web_view_install_request_handler (E_WEB_VIEW (display), E_TYPE_FILE_REQUEST);
- e_web_view_install_request_handler (E_WEB_VIEW (display), E_TYPE_STOCK_REQUEST);
-
action_group = gtk_action_group_new ("internal-mailto");
gtk_action_group_set_translation_domain (action_group, domain);
gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
diff --git a/addressbook/gui/widgets/eab-contact-formatter.c b/addressbook/gui/widgets/eab-contact-formatter.c
index 4869811..d2e217b 100644
--- a/addressbook/gui/widgets/eab-contact-formatter.c
+++ b/addressbook/gui/widgets/eab-contact-formatter.c
@@ -1383,64 +1383,3 @@ eab_contact_formatter_format_contact (EABContactFormatter *formatter,
else
render_compact (formatter, contact, output_buffer);
}
-
-static void
-collapse_contacts_list (WebKitDOMEventTarget *event_target,
- WebKitDOMEvent *event,
- gpointer user_data)
-{
- WebKitDOMDocument *document;
- WebKitDOMElement *list;
- gchar *id, *list_id;
- gchar *imagesdir, *src;
- gboolean hidden;
-
- document = user_data;
- id = webkit_dom_element_get_id (WEBKIT_DOM_ELEMENT (event_target));
-
- list_id = g_strconcat ("list-", id, NULL);
- list = webkit_dom_document_get_element_by_id (document, list_id);
- g_free (id);
- g_free (list_id);
-
- if (list == NULL)
- return;
-
- imagesdir = g_filename_to_uri (EVOLUTION_IMAGESDIR, NULL, NULL);
- hidden = webkit_dom_html_element_get_hidden (WEBKIT_DOM_HTML_ELEMENT (list));
-
- if (hidden)
- src = g_strdup_printf ("evo-file://%s/minus.png", imagesdir);
- else
- src = g_strdup_printf ("evo-file://%s/plus.png", imagesdir);
-
- webkit_dom_html_element_set_hidden (
- WEBKIT_DOM_HTML_ELEMENT (list), !hidden);
- webkit_dom_html_image_element_set_src (
- WEBKIT_DOM_HTML_IMAGE_ELEMENT (event_target), src);
-
- g_free (src);
- g_free (imagesdir);
-}
-
-void
-eab_contact_formatter_bind_dom (WebKitDOMDocument *document)
-{
- WebKitDOMNodeList *nodes;
- gulong ii, length;
-
- nodes = webkit_dom_document_get_elements_by_class_name (
- document, "_evo_collapse_button");
-
- length = webkit_dom_node_list_get_length (nodes);
- for (ii = 0; ii < length; ii++) {
- WebKitDOMNode *node;
-
- node = webkit_dom_node_list_item (nodes, ii);
- webkit_dom_event_target_add_event_listener (
- WEBKIT_DOM_EVENT_TARGET (node), "click",
- G_CALLBACK (collapse_contacts_list), FALSE, document);
- }
-
- g_object_unref (nodes);
-}
diff --git a/addressbook/gui/widgets/eab-contact-formatter.h b/addressbook/gui/widgets/eab-contact-formatter.h
index b4acc62..b691f31 100644
--- a/addressbook/gui/widgets/eab-contact-formatter.h
+++ b/addressbook/gui/widgets/eab-contact-formatter.h
@@ -75,7 +75,6 @@ void eab_contact_formatter_format_contact
(EABContactFormatter *formatter,
EContact *contact,
GString *output_buffer);
-void eab_contact_formatter_bind_dom (WebKitDOMDocument *document);
G_END_DECLS
diff --git a/calendar/gui/e-comp-editor-page-attachments.c b/calendar/gui/e-comp-editor-page-attachments.c
index 776f3a2..5910c7a 100644
--- a/calendar/gui/e-comp-editor-page-attachments.c
+++ b/calendar/gui/e-comp-editor-page-attachments.c
@@ -177,17 +177,7 @@ ecep_attachments_attachment_loaded_cb (EAttachment *attachment,
}
if (!e_attachment_load_finish (attachment, result, &error)) {
- GtkTreeRowReference *reference;
-
- reference = e_attachment_get_reference (attachment);
- if (gtk_tree_row_reference_valid (reference)) {
- GtkTreeModel *model;
-
- model = gtk_tree_row_reference_get_model (reference);
-
- e_attachment_store_remove_attachment (
- E_ATTACHMENT_STORE (model), attachment);
- }
+ g_signal_emit_by_name (attachment, "load-failed", NULL);
/* Ignore cancellations. */
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
diff --git a/calendar/gui/itip-utils.c b/calendar/gui/itip-utils.c
index 5a688b0..c873e99 100644
--- a/calendar/gui/itip-utils.c
+++ b/calendar/gui/itip-utils.c
@@ -1639,17 +1639,18 @@ find_enabled_identity (ESourceRegistry *registry,
return mail_identity;
}
-static void
-setup_from (ECalComponentItipMethod method,
- ECalComponent *comp,
- ECalClient *cal_client,
- EComposerHeaderTable *table)
+static gchar *
+get_identity_uid_for_from (EShell *shell,
+ ECalComponentItipMethod method,
+ ECalComponent *comp,
+ ECalClient *cal_client)
{
EClientCache *client_cache;
ESourceRegistry *registry;
ESource *source = NULL;
+ gchar *identity_uid = NULL;
- client_cache = e_composer_header_table_ref_client_cache (table);
+ client_cache = e_shell_get_client_cache (shell);
registry = e_client_cache_ref_registry (client_cache);
/* always use organizer's email when user is an organizer */
@@ -1673,16 +1674,14 @@ setup_from (ECalComponentItipMethod method,
}
if (source != NULL) {
- const gchar *uid;
-
- uid = e_source_get_uid (source);
- e_composer_header_table_set_identity_uid (table, uid);
+ identity_uid = g_strdup (e_source_get_uid (source));
g_object_unref (source);
}
- g_object_unref (client_cache);
g_object_unref (registry);
+
+ return identity_uid;
}
typedef struct {
@@ -1771,83 +1770,64 @@ itip_send_component_begin (ItipSendComponentData *isc,
}
}
+typedef struct _CreateComposerData {
+ gchar *identity_uid;
+ EDestination **destinations;
+ gchar *subject;
+ gchar *ical_string;
+ gchar *content_type;
+ gchar *event_body_text;
+ GSList *attachments_list;
+ ECalComponent *comp;
+ gboolean show_only;
+} CreateComposerData;
+
static void
-itip_send_component_complete (ItipSendComponentData *isc)
+itip_send_component_composer_created_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
{
- GSettings *settings;
- EMsgComposer *composer;
+ CreateComposerData *ccd = user_data;
EComposerHeaderTable *table;
- EDestination **destinations;
- ECalComponent *comp = NULL;
- icalcomponent *top_level = NULL;
- icaltimezone *default_zone;
- gchar *ical_string = NULL;
- gchar *content_type = NULL;
- gchar *subject = NULL;
+ EMsgComposer *composer;
+ GSettings *settings;
gboolean use_24hour_format;
+ GError *error = NULL;
- g_return_if_fail (isc != NULL);
+ g_return_if_fail (ccd != NULL);
- if (isc->completed)
+ composer = e_msg_composer_new_finish (result, &error);
+ if (error) {
+ g_warning ("%s: Failed to create msg composer: %s", G_STRFUNC, error->message);
+ g_clear_error (&error);
return;
-
- isc->success = FALSE;
+ }
settings = e_util_ref_settings ("org.gnome.evolution.calendar");
use_24hour_format = g_settings_get_boolean (settings, "use-24hour-format");
g_object_unref (settings);
- default_zone = calendar_config_get_icaltimezone ();
-
- /* Tidy up the comp */
- comp = comp_compliant (
- isc->registry, isc->method, isc->send_comp, isc->cal_client,
- isc->zones, default_zone, isc->strip_alarms);
-
- if (comp == NULL)
- goto cleanup;
-
- /* Recipients */
- destinations = comp_to_list (
- isc->registry, isc->method, comp, isc->users, FALSE,
- isc->only_new_attendees ? g_object_get_data (
- G_OBJECT (isc->send_comp), "new-attendees") : NULL);
- if (isc->method != E_CAL_COMPONENT_METHOD_PUBLISH) {
- if (destinations == NULL) {
- /* We sent them all via the server */
- isc->success = TRUE;
- goto cleanup;
- }
- }
-
- /* Subject information */
- subject = comp_subject (isc->registry, isc->method, comp);
-
- composer = e_msg_composer_new (e_shell_get_default ());
table = e_msg_composer_get_header_table (composer);
- setup_from (isc->method, isc->send_comp, isc->cal_client, table);
- e_composer_header_table_set_subject (table, subject);
- e_composer_header_table_set_destinations_to (table, destinations);
-
- e_destination_freev (destinations);
+ if (ccd->identity_uid)
+ e_composer_header_table_set_identity_uid (table, ccd->identity_uid);
- /* Content type */
- content_type = comp_content_type (comp, isc->method);
+ e_composer_header_table_set_subject (table, ccd->subject);
+ e_composer_header_table_set_destinations_to (table, ccd->destinations);
- top_level = comp_toplevel_with_zones (isc->method, comp, isc->cal_client, isc->zones);
- ical_string = icalcomponent_as_ical_string_r (top_level);
-
- if (e_cal_component_get_vtype (comp) == E_CAL_COMPONENT_EVENT) {
- e_msg_composer_set_body (composer, ical_string, content_type);
+ if (e_cal_component_get_vtype (ccd->comp) == E_CAL_COMPONENT_EVENT) {
+ if (ccd->event_body_text)
+ e_msg_composer_set_body_text (composer, ccd->event_body_text, TRUE);
+ else
+ e_msg_composer_set_body (composer, ccd->ical_string, ccd->content_type);
} else {
CamelMimePart *attachment;
const gchar *filename;
gchar *description;
gchar *body;
- filename = comp_filename (comp);
- description = comp_description (comp, use_24hour_format);
+ filename = comp_filename (ccd->comp);
+ description = comp_description (ccd->comp, use_24hour_format);
body = camel_text_to_html (description, CAMEL_MIME_FILTER_TOHTML_PRE, 0);
e_msg_composer_set_body_text (composer, body, TRUE);
@@ -1855,8 +1835,8 @@ itip_send_component_complete (ItipSendComponentData *isc)
attachment = camel_mime_part_new ();
camel_mime_part_set_content (
- attachment, ical_string,
- strlen (ical_string), content_type);
+ attachment, ccd->ical_string,
+ strlen (ccd->ical_string), ccd->content_type);
if (filename != NULL && *filename != '\0')
camel_mime_part_set_filename (attachment, filename);
if (description != NULL && *description != '\0')
@@ -1868,23 +1848,89 @@ itip_send_component_complete (ItipSendComponentData *isc)
g_free (description);
}
- append_cal_attachments (composer, comp, isc->attachments_list);
- isc->attachments_list = NULL;
+ append_cal_attachments (composer, ccd->comp, ccd->attachments_list);
+ ccd->attachments_list = NULL;
- if (isc->method == E_CAL_COMPONENT_METHOD_PUBLISH && !isc->users)
+ if (ccd->show_only)
gtk_widget_show (GTK_WIDGET (composer));
else
e_msg_composer_send (composer);
+ e_destination_freev (ccd->destinations);
+ g_clear_object (&ccd->comp);
+ g_free (ccd->identity_uid);
+ g_free (ccd->subject);
+ g_free (ccd->ical_string);
+ g_free (ccd->content_type);
+ g_free (ccd->event_body_text);
+ g_free (ccd);
+}
+
+static void
+itip_send_component_complete (ItipSendComponentData *isc)
+{
+ CreateComposerData *ccd;
+ EDestination **destinations;
+ ECalComponent *comp = NULL;
+ EShell *shell;
+ icalcomponent *top_level = NULL;
+ icaltimezone *default_zone;
+
+ g_return_if_fail (isc != NULL);
+
+ if (isc->completed)
+ return;
+
+ isc->success = FALSE;
+
+ default_zone = calendar_config_get_icaltimezone ();
+
+ /* Tidy up the comp */
+ comp = comp_compliant (
+ isc->registry, isc->method, isc->send_comp, isc->cal_client,
+ isc->zones, default_zone, isc->strip_alarms);
+
+ if (comp == NULL)
+ goto cleanup;
+
+ /* Recipients */
+ destinations = comp_to_list (
+ isc->registry, isc->method, comp, isc->users, FALSE,
+ isc->only_new_attendees ? g_object_get_data (
+ G_OBJECT (isc->send_comp), "new-attendees") : NULL);
+ if (isc->method != E_CAL_COMPONENT_METHOD_PUBLISH) {
+ if (destinations == NULL) {
+ /* We sent them all via the server */
+ isc->success = TRUE;
+ goto cleanup;
+ }
+ }
+
+ shell = e_shell_get_default ();
+ top_level = comp_toplevel_with_zones (isc->method, comp, isc->cal_client, isc->zones);
+
+ ccd = g_new0 (CreateComposerData, 1);
+ ccd->identity_uid = get_identity_uid_for_from (shell, isc->method, isc->send_comp, isc->cal_client);
+ ccd->destinations = destinations;
+ ccd->subject = comp_subject (isc->registry, isc->method, comp);
+ ccd->ical_string = icalcomponent_as_ical_string_r (top_level);
+ ccd->content_type = comp_content_type (comp, isc->method);
+ ccd->event_body_text = NULL;
+ ccd->attachments_list = isc->attachments_list;
+ ccd->comp = comp;
+ ccd->show_only = isc->method == E_CAL_COMPONENT_METHOD_PUBLISH && !isc->users;
+
+ isc->attachments_list = NULL;
+ comp = NULL;
+
+ e_msg_composer_new (shell, itip_send_component_composer_created_cb, ccd);
+
isc->success = TRUE;
cleanup:
g_clear_object (&comp);
if (top_level != NULL)
icalcomponent_free (top_level);
- g_free (content_type);
- g_free (subject);
- g_free (ical_string);
}
static void
@@ -2119,15 +2165,11 @@ reply_to_calendar_comp (ESourceRegistry *registry,
GSList *attachments_list)
{
EShell *shell;
- EMsgComposer *composer;
- EComposerHeaderTable *table;
- EDestination **destinations;
ECalComponent *comp = NULL;
icalcomponent *top_level = NULL;
icaltimezone *default_zone;
- gchar *subject = NULL;
- gchar *ical_string = NULL;
gboolean retval = FALSE;
+ CreateComposerData *ccd;
g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), FALSE);
@@ -2143,24 +2185,15 @@ reply_to_calendar_comp (ESourceRegistry *registry,
if (comp == NULL)
goto cleanup;
- /* Recipients */
- destinations = comp_to_list (
- registry, method, comp, NULL, reply_all, NULL);
-
- /* Subject information */
- subject = comp_subject (registry, method, comp);
-
- composer = e_msg_composer_new (shell);
- table = e_msg_composer_get_header_table (composer);
-
- setup_from (method, send_comp, cal_client, table);
- e_composer_header_table_set_subject (table, subject);
- e_composer_header_table_set_destinations_to (table, destinations);
-
- e_destination_freev (destinations);
-
top_level = comp_toplevel_with_zones (method, comp, cal_client, zones);
- ical_string = icalcomponent_as_ical_string_r (top_level);
+
+ ccd = g_new0 (CreateComposerData, 1);
+ ccd->identity_uid = get_identity_uid_for_from (shell, method, send_comp, cal_client);
+ ccd->destinations = comp_to_list (registry, method, comp, NULL, reply_all, NULL);
+ ccd->subject = comp_subject (registry, method, comp);
+ ccd->ical_string = icalcomponent_as_ical_string_r (top_level);
+ ccd->comp = comp;
+ ccd->show_only = TRUE;
if (e_cal_component_get_vtype (comp) == E_CAL_COMPONENT_EVENT) {
@@ -2268,11 +2301,12 @@ reply_to_calendar_comp (ESourceRegistry *registry,
g_string_append (body, html_description);
g_free (html_description);
- e_msg_composer_set_body_text (composer, body->str, TRUE);
- g_string_free (body, TRUE);
+ ccd->event_body_text = g_string_free (body, FALSE);
}
- gtk_widget_show (GTK_WIDGET (composer));
+ comp = NULL;
+
+ e_msg_composer_new (shell, itip_send_component_composer_created_cb, ccd);
retval = TRUE;
@@ -2283,8 +2317,6 @@ reply_to_calendar_comp (ESourceRegistry *registry,
if (top_level != NULL)
icalcomponent_free (top_level);
- g_free (subject);
- g_free (ical_string);
return retval;
}
diff --git a/composer/e-composer-actions.c b/composer/e-composer-actions.c
index 5995ef0..77e1b88 100644
--- a/composer/e-composer-actions.c
+++ b/composer/e-composer-actions.c
@@ -65,40 +65,57 @@ action_close_cb (GtkAction *action,
}
static void
+action_new_message_composer_created_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ EMsgComposer *composer;
+ GError *error = NULL;
+
+ composer = e_msg_composer_new_finish (result, &error);
+ if (error) {
+ g_warning ("%s: Failed to create msg composer: %s", G_STRFUNC, error->message);
+ g_clear_error (&error);
+ } else {
+ gtk_widget_show (GTK_WIDGET (composer));
+ }
+}
+
+static void
action_new_message_cb (GtkAction *action,
EMsgComposer *composer)
{
- EMsgComposer *new_composer;
EShell *shell;
shell = e_msg_composer_get_shell (composer);
- new_composer = e_msg_composer_new (shell);
- gtk_widget_show (GTK_WIDGET (new_composer));
+ e_msg_composer_new (shell, action_new_message_composer_created_cb, NULL);
}
static void
-action_pgp_encrypt_cb (GtkToggleAction *action,
- EMsgComposer *composer)
+composer_set_content_editor_changed (EMsgComposer *composer)
{
EHTMLEditor *editor;
- EHTMLEditorView *view;
+ EContentEditor *cnt_editor;
editor = e_msg_composer_get_editor (composer);
- view = e_html_editor_get_view (editor);
- e_html_editor_view_set_changed (view, TRUE);
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ e_content_editor_set_changed (cnt_editor, TRUE);
+
+}
+
+static void
+action_pgp_encrypt_cb (GtkToggleAction *action,
+ EMsgComposer *composer)
+{
+ composer_set_content_editor_changed (composer);
}
static void
action_pgp_sign_cb (GtkToggleAction *action,
EMsgComposer *composer)
{
- EHTMLEditor *editor;
- EHTMLEditorView *view;
-
- editor = e_msg_composer_get_editor (composer);
- view = e_html_editor_get_view (editor);
- e_html_editor_view_set_changed (view, TRUE);
+ composer_set_content_editor_changed (composer);
}
static void
@@ -150,7 +167,6 @@ action_save_cb (GtkAction *action,
EMsgComposer *composer)
{
EHTMLEditor *editor;
- EHTMLEditorView *view;
const gchar *filename;
gint fd;
GError *error = NULL;
@@ -195,8 +211,7 @@ action_save_cb (GtkAction *action,
return;
}
- view = e_html_editor_get_view (editor);
- e_html_editor_view_set_changed (view, TRUE);
+ composer_set_content_editor_changed (composer);
}
static void
@@ -256,37 +271,14 @@ static void
action_smime_encrypt_cb (GtkToggleAction *action,
EMsgComposer *composer)
{
- EHTMLEditor *editor;
- EHTMLEditorView *view;
-
- editor = e_msg_composer_get_editor (composer);
- view = e_html_editor_get_view (editor);
- e_html_editor_view_set_changed (view, TRUE);
+ composer_set_content_editor_changed (composer);
}
static void
action_smime_sign_cb (GtkToggleAction *action,
EMsgComposer *composer)
{
- EHTMLEditor *editor;
- EHTMLEditorView *view;
-
- editor = e_msg_composer_get_editor (composer);
- view = e_html_editor_get_view (editor);
- e_html_editor_view_set_changed (view, TRUE);
-}
-
-static void
-action_unicode_smileys_cb (GtkToggleAction *action,
- EMsgComposer *composer)
-{
- EHTMLEditor *editor;
- EHTMLEditorView *view;
-
- editor = e_msg_composer_get_editor (composer);
- view = e_html_editor_get_view (editor);
- e_html_editor_view_set_unicode_smileys (view,
- gtk_toggle_action_get_active (action));
+ composer_set_content_editor_changed (composer);
}
static void
@@ -520,10 +512,10 @@ static GtkToggleActionEntry toggle_entries[] = {
{ "unicode-smileys",
NULL,
- N_("Unicode emoticons"),
+ N_("Unicode smilyes"),
NULL,
- N_("Use Unicode characters for emoticons."),
- G_CALLBACK (action_unicode_smileys_cb),
+ N_("Use Unicode characters for smileys."),
+ NULL, /* Handled by property bindings */
FALSE },
{ "view-bcc",
@@ -566,14 +558,14 @@ e_composer_actions_init (EMsgComposer *composer)
GtkAccelGroup *accel_group;
GtkUIManager *ui_manager;
EHTMLEditor *editor;
- EHTMLEditorView *view;
+ EContentEditor *cnt_editor;
gboolean visible;
GIcon *gcr_gnupg_icon;
g_return_if_fail (E_IS_MSG_COMPOSER (composer));
editor = e_msg_composer_get_editor (composer);
- view = e_html_editor_get_view (editor);
+ cnt_editor = e_html_editor_get_content_editor (editor);
ui_manager = e_html_editor_get_ui_manager (editor);
/* Composer Actions */
@@ -678,32 +670,32 @@ e_composer_actions_init (EMsgComposer *composer)
}
e_binding_bind_property (
- view, "html-mode",
+ cnt_editor, "html-mode",
ACTION (PICTURE_GALLERY), "sensitive",
G_BINDING_SYNC_CREATE);
e_binding_bind_property (
- view, "editable",
+ cnt_editor, "editable",
e_html_editor_get_action (editor, "edit-menu"), "sensitive",
G_BINDING_SYNC_CREATE);
e_binding_bind_property (
- view, "editable",
+ cnt_editor, "editable",
e_html_editor_get_action (editor, "format-menu"), "sensitive",
G_BINDING_SYNC_CREATE);
e_binding_bind_property (
- view, "editable",
+ cnt_editor, "editable",
e_html_editor_get_action (editor, "insert-menu"), "sensitive",
G_BINDING_SYNC_CREATE);
e_binding_bind_property (
- view, "editable",
+ cnt_editor, "editable",
e_html_editor_get_action (editor, "options-menu"), "sensitive",
G_BINDING_SYNC_CREATE);
e_binding_bind_property (
- view, "editable",
+ cnt_editor, "editable",
e_html_editor_get_action (editor, "picture-gallery"), "sensitive",
G_BINDING_SYNC_CREATE);
diff --git a/composer/e-composer-private.c b/composer/e-composer-private.c
index 65b8dd5..2b20b28 100644
--- a/composer/e-composer-private.c
+++ b/composer/e-composer-private.c
@@ -64,14 +64,14 @@ static void
composer_update_gallery_visibility (EMsgComposer *composer)
{
EHTMLEditor *editor;
- EHTMLEditorView *view;
+ EContentEditor *cnt_editor;
GtkToggleAction *toggle_action;
gboolean gallery_active;
gboolean is_html;
editor = e_msg_composer_get_editor (composer);
- view = e_html_editor_get_view (editor);
- is_html = e_html_editor_view_get_html_mode (view);
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ is_html = e_content_editor_get_html_mode (cnt_editor);
toggle_action = GTK_TOGGLE_ACTION (ACTION (PICTURE_GALLERY));
gallery_active = gtk_toggle_action_get_active (toggle_action);
@@ -94,7 +94,7 @@ e_composer_private_constructed (EMsgComposer *composer)
EShell *shell;
EClientCache *client_cache;
EHTMLEditor *editor;
- EHTMLEditorView *view;
+ EContentEditor *cnt_editor;
GtkUIManager *ui_manager;
GtkAction *action;
GtkWidget *container;
@@ -109,7 +109,7 @@ e_composer_private_constructed (EMsgComposer *composer)
editor = e_msg_composer_get_editor (composer);
ui_manager = e_html_editor_get_ui_manager (editor);
- view = e_html_editor_get_view (editor);
+ cnt_editor = e_html_editor_get_content_editor (editor);
settings = e_util_ref_settings ("org.gnome.evolution.mail");
@@ -136,10 +136,9 @@ e_composer_private_constructed (EMsgComposer *composer)
priv->saved_editable = FALSE;
priv->drop_occured = FALSE;
priv->dnd_is_uri = FALSE;
+ priv->dnd_history_saved = FALSE;
priv->check_if_signature_is_changed = FALSE;
priv->ignore_next_signature_change = FALSE;
- priv->dnd_history_saved = FALSE;
- priv->ignore_next_paste_clipboard_signals_emission = FALSE;
priv->focused_entry = NULL;
@@ -214,7 +213,7 @@ e_composer_private_constructed (EMsgComposer *composer)
E_COMPOSER_HEADER_TABLE (widget),
E_COMPOSER_HEADER_SUBJECT);
e_binding_bind_property (
- view, "spell-checker",
+ cnt_editor, "spell-checker",
header->input_widget, "spell-checker",
G_BINDING_SYNC_CREATE);
@@ -233,7 +232,7 @@ e_composer_private_constructed (EMsgComposer *composer)
gtk_widget_show (widget);
e_binding_bind_property (
- view, "editable",
+ cnt_editor, "editable",
widget, "sensitive",
G_BINDING_SYNC_CREATE);
@@ -255,11 +254,12 @@ e_composer_private_constructed (EMsgComposer *composer)
priv->gallery_scrolled_window = g_object_ref (widget);
gtk_widget_show (widget);
- /* Reparent the scrolled window containing the web view
- * widget into the content area of the top attachment pane. */
-
- widget = GTK_WIDGET (view);
- widget = gtk_widget_get_parent (widget);
+ widget = GTK_WIDGET (cnt_editor);
+ if (GTK_IS_SCROLLABLE (cnt_editor)) {
+ /* Scrollables are packed in a scrolled window */
+ widget = gtk_widget_get_parent (widget);
+ g_warn_if_fail (GTK_IS_SCROLLED_WINDOW (widget));
+ }
gtk_widget_reparent (widget, container);
/* Construct the picture gallery. */
@@ -275,7 +275,7 @@ e_composer_private_constructed (EMsgComposer *composer)
g_free (gallery_path);
e_signal_connect_notify_swapped (
- view, "notify::html-mode",
+ cnt_editor, "notify::html-mode",
G_CALLBACK (composer_update_gallery_visibility), composer);
g_signal_connect_swapped (
@@ -290,7 +290,6 @@ e_composer_private_constructed (EMsgComposer *composer)
for (ii = 0; ii < E_COMPOSER_NUM_HEADERS; ii++) {
EComposerHeaderTable *table;
EComposerHeader *header;
- GtkAction *action;
table = E_COMPOSER_HEADER_TABLE (priv->header_table);
header = e_composer_header_table_get_header (table, ii);
@@ -520,6 +519,7 @@ e_composer_paste_image (EMsgComposer *composer,
e_attachment_load_handle_error, composer);
g_object_unref (attachment);
+
g_free (uri);
return TRUE;
@@ -670,7 +670,7 @@ composer_load_signature_cb (EMailSignatureComboBox *combo_box,
gboolean is_html;
GError *error = NULL;
EHTMLEditor *editor;
- EHTMLEditorView *view;
+ EContentEditor *cnt_editor;
e_mail_signature_combo_box_load_selected_finish (
combo_box, result, &contents, &length, &is_html, &error);
@@ -690,10 +690,10 @@ composer_load_signature_cb (EMailSignatureComboBox *combo_box,
}
editor = e_msg_composer_get_editor (composer);
- view = e_html_editor_get_view (editor);
+ cnt_editor = e_html_editor_get_content_editor (editor);
- new_signature_id = e_html_editor_view_insert_signature (
- view,
+ new_signature_id = e_content_editor_insert_signature (
+ cnt_editor,
contents,
is_html,
gtk_combo_box_get_active_id (GTK_COMBO_BOX (combo_box)),
@@ -710,13 +710,11 @@ composer_load_signature_cb (EMailSignatureComboBox *combo_box,
}
static void
-html_editor_view_is_ready_cb (EHTMLEditorView *view,
- EMsgComposer *composer)
+content_editor_load_finished_cb (EContentEditor *cnt_editor,
+ EMsgComposer *composer)
{
g_signal_handlers_disconnect_by_func (
- view,
- G_CALLBACK (html_editor_view_is_ready_cb),
- composer);
+ cnt_editor, G_CALLBACK (content_editor_load_finished_cb), composer);
e_composer_update_signature (composer);
}
@@ -727,7 +725,7 @@ e_composer_update_signature (EMsgComposer *composer)
EComposerHeaderTable *table;
EMailSignatureComboBox *combo_box;
EHTMLEditor *editor;
- EHTMLEditorView *view;
+ EContentEditor *cnt_editor;
g_return_if_fail (E_IS_MSG_COMPOSER (composer));
@@ -739,13 +737,13 @@ e_composer_update_signature (EMsgComposer *composer)
table = e_msg_composer_get_header_table (composer);
combo_box = e_composer_header_table_get_signature_combo_box (table);
editor = e_msg_composer_get_editor (composer);
- view = e_html_editor_get_view (editor);
+ cnt_editor = e_html_editor_get_content_editor (editor);
- if (!e_html_editor_view_is_ready (view)) {
+ if (!e_content_editor_is_ready (cnt_editor)) {
g_signal_connect (
- view, "is-ready",
- G_CALLBACK (html_editor_view_is_ready_cb), composer);
-
+ cnt_editor, "load-finished",
+ G_CALLBACK (content_editor_load_finished_cb),
+ composer);
return;
}
diff --git a/composer/e-composer-private.h b/composer/e-composer-private.h
index 9a90499..b2c50df 100644
--- a/composer/e-composer-private.h
+++ b/composer/e-composer-private.h
@@ -95,17 +95,17 @@ struct _EMsgComposerPrivate {
gboolean busy;
gboolean disable_signature;
gboolean is_from_draft;
+ gboolean is_from_new_message;
/* The web view is uneditable while the editor is busy.
* This is used to restore the previous editable state. */
gboolean saved_editable;
gboolean set_signature_from_message;
gboolean drop_occured;
gboolean dnd_is_uri;
- gboolean check_if_signature_is_changed;
- gboolean ignore_next_signature_change;
gboolean is_sending_message;
gboolean dnd_history_saved;
- gboolean ignore_next_paste_clipboard_signals_emission;
+ gboolean check_if_signature_is_changed;
+ gboolean ignore_next_signature_change;
gboolean last_signal_was_paste_primary;
gint focused_entry_selection_start;
diff --git a/composer/e-msg-composer.c b/composer/e-msg-composer.c
index c472fcc..713d02a 100644
--- a/composer/e-msg-composer.c
+++ b/composer/e-msg-composer.c
@@ -133,7 +133,7 @@ static void add_attachments_from_multipart (EMsgComposer *composer,
gboolean just_inlines,
gint depth);
-/* used by e_msg_composer_new_with_message () */
+/* used by e_msg_composer_setup_with_message () */
static void handle_multipart (EMsgComposer *composer,
CamelMultipart *multipart,
gboolean keep_signature,
@@ -1043,11 +1043,11 @@ composer_add_evolution_composer_mode_header (CamelMedium *medium,
{
gboolean html_mode;
EHTMLEditor *editor;
- EHTMLEditorView *view;
+ EContentEditor *cnt_editor;
editor = e_msg_composer_get_editor (composer);
- view = e_html_editor_get_view (editor);
- html_mode = e_html_editor_view_get_html_mode (view);
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ html_mode = e_content_editor_get_html_mode (cnt_editor);
camel_medium_add_header (
medium,
@@ -1262,12 +1262,18 @@ composer_build_message (EMsgComposer *composer,
} else {
gchar *text;
EHTMLEditor *editor;
- EHTMLEditorView *view;
+ EContentEditor *cnt_editor;
editor = e_msg_composer_get_editor (composer);
- view = e_html_editor_get_view (editor);
+ cnt_editor = e_html_editor_get_content_editor (editor);
data = g_byte_array_new ();
- text = e_html_editor_view_get_text_plain (view);
+
+ text = e_content_editor_get_content (
+ cnt_editor,
+ E_CONTENT_EDITOR_GET_TEXT_PLAIN |
+ E_CONTENT_EDITOR_GET_PROCESSED,
+ NULL, NULL);
+
g_byte_array_append (data, (guint8 *) text, strlen (text));
g_free (text);
@@ -1330,15 +1336,14 @@ composer_build_message (EMsgComposer *composer,
if ((flags & COMPOSER_FLAG_HTML_CONTENT) != 0 ||
(flags & COMPOSER_FLAG_SAVE_DRAFT) != 0) {
gchar *text;
- guint count;
gsize length;
gboolean pre_encode;
EHTMLEditor *editor;
- EHTMLEditorView *view;
- GList *inline_images = NULL;
+ EContentEditor *cnt_editor;
+ GSList *inline_images_parts = NULL, *link;
editor = e_msg_composer_get_editor (composer);
- view = e_html_editor_get_view (editor);
+ cnt_editor = e_html_editor_get_content_editor (editor);
data = g_byte_array_new ();
if ((flags & COMPOSER_FLAG_SAVE_DRAFT) != 0) {
@@ -1350,10 +1355,19 @@ composer_build_message (EMsgComposer *composer,
composer_add_evolution_composer_mode_header (
CAMEL_MEDIUM (context->message), composer);
- text = e_html_editor_view_get_text_html_for_drafts_with_images (
- view, from_domain, &inline_images);
- } else
- text = e_html_editor_view_get_text_html (view, from_domain, &inline_images);
+ text = e_content_editor_get_content (
+ cnt_editor,
+ E_CONTENT_EDITOR_GET_TEXT_HTML |
+ E_CONTENT_EDITOR_GET_INLINE_IMAGES,
+ from_domain, &inline_images_parts);
+ } else {
+ text = e_content_editor_get_content (
+ cnt_editor,
+ E_CONTENT_EDITOR_GET_TEXT_HTML |
+ E_CONTENT_EDITOR_GET_PROCESSED |
+ E_CONTENT_EDITOR_GET_INLINE_IMAGES,
+ from_domain, &inline_images_parts);
+ }
length = strlen (text);
g_byte_array_append (data, (guint8 *) text, (guint) length);
@@ -1409,9 +1423,7 @@ composer_build_message (EMsgComposer *composer,
/* If there are inlined images, construct a multipart/related
* containing the multipart/alternative and the images. */
- count = g_list_length (inline_images);
- if (count > 0) {
- guint ii;
+ if (inline_images_parts) {
CamelMultipart *html_with_images;
html_with_images = camel_multipart_new ();
@@ -1430,10 +1442,10 @@ composer_build_message (EMsgComposer *composer,
g_object_unref (body);
- for (ii = 0; ii < count; ii++) {
- CamelMimePart *part = g_list_nth_data (inline_images, ii);
- camel_multipart_add_part (
- html_with_images, part);
+ for (link = inline_images_parts; link; link = g_slist_next (link)) {
+ CamelMimePart *part = link->data;
+
+ camel_multipart_add_part (html_with_images, part);
}
context->top_level_part =
@@ -1442,7 +1454,7 @@ composer_build_message (EMsgComposer *composer,
context->top_level_part =
CAMEL_DATA_WRAPPER (body);
}
- g_list_free_full (inline_images, g_object_unref);
+ g_slist_free_full (inline_images_parts, g_object_unref);
}
/* If there are attachments, wrap what we've built so far
@@ -1553,18 +1565,26 @@ set_editor_text (EMsgComposer *composer,
gboolean set_signature)
{
EHTMLEditor *editor;
- EHTMLEditorView *view;
+ EContentEditor *cnt_editor;
g_return_if_fail (E_IS_MSG_COMPOSER (composer));
g_return_if_fail (text != NULL);
editor = e_msg_composer_get_editor (composer);
- view = e_html_editor_get_view (editor);
+ cnt_editor = e_html_editor_get_content_editor (editor);
if (is_html)
- e_html_editor_view_set_text_html (view, text);
+ e_content_editor_insert_content (
+ cnt_editor,
+ text,
+ E_CONTENT_EDITOR_INSERT_TEXT_HTML |
+ E_CONTENT_EDITOR_INSERT_REPLACE_ALL);
else
- e_html_editor_view_set_text_plain (view, text);
+ e_content_editor_insert_content (
+ cnt_editor,
+ text,
+ E_CONTENT_EDITOR_INSERT_TEXT_PLAIN |
+ E_CONTENT_EDITOR_INSERT_REPLACE_ALL);
if (set_signature)
e_composer_update_signature (composer);
@@ -1581,10 +1601,10 @@ attachment_store_changed_cb (EMsgComposer *composer)
* changes on close. */
editor = e_msg_composer_get_editor (composer);
if (editor) {
- EHTMLEditorView *view;
+ EContentEditor *cnt_editor;
- view = e_html_editor_get_view (editor);
- e_html_editor_view_set_changed (view, TRUE);
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ e_content_editor_set_changed (cnt_editor, TRUE);
}
}
@@ -1694,8 +1714,8 @@ msg_composer_paste_clipboard_targets_cb (GtkClipboard *clipboard,
gint n_targets,
EMsgComposer *composer)
{
- EHTMLEditor *editor = e_msg_composer_get_editor (composer);
- EHTMLEditorView *editor_view = e_html_editor_get_view (editor);
+ EHTMLEditor *editor;
+ EContentEditor *cnt_editor;
if (targets == NULL || n_targets < 0)
return;
@@ -1708,62 +1728,55 @@ msg_composer_paste_clipboard_targets_cb (GtkClipboard *clipboard,
return;
}
- if (!e_html_editor_view_get_html_mode (editor_view) &&
+ editor = e_msg_composer_get_editor (composer);
+ cnt_editor = e_html_editor_get_content_editor (editor);
+
+ if (!e_content_editor_get_html_mode (cnt_editor) &&
gtk_targets_include_image (targets, n_targets, TRUE)) {
e_composer_paste_image (composer, clipboard);
return;
}
- composer->priv->ignore_next_paste_clipboard_signals_emission = TRUE;
-
- g_signal_emit_by_name (
- editor_view,
- composer->priv->last_signal_was_paste_primary ?
- "paste-primary-clipboard" : "paste-clipboard");
+ if (composer->priv->last_signal_was_paste_primary) {
+ e_content_editor_paste_primary (cnt_editor);
+ } else
+ e_content_editor_paste (cnt_editor);
}
-static void
-msg_composer_paste_primary_clipboard_cb (EHTMLEditorView *view,
+static gboolean
+msg_composer_paste_primary_clipboard_cb (EContentEditor *cnt_editor,
EMsgComposer *composer)
{
- if (composer->priv->ignore_next_paste_clipboard_signals_emission)
- composer->priv->ignore_next_paste_clipboard_signals_emission = FALSE;
- else {
- GtkClipboard *clipboard;
+ GtkClipboard *clipboard;
- clipboard = gtk_clipboard_get (GDK_SELECTION_PRIMARY);
+ clipboard = gtk_clipboard_get (GDK_SELECTION_PRIMARY);
- composer->priv->last_signal_was_paste_primary = TRUE;
+ composer->priv->last_signal_was_paste_primary = TRUE;
- gtk_clipboard_request_targets (
- clipboard, (GtkClipboardTargetsReceivedFunc)
- msg_composer_paste_clipboard_targets_cb, composer);
+ gtk_clipboard_request_targets (
+ clipboard, (GtkClipboardTargetsReceivedFunc)
+ msg_composer_paste_clipboard_targets_cb, composer);
- g_signal_stop_emission_by_name (view, "paste-primary-clipboard");
- }
+ return TRUE;
}
-static void
-msg_composer_paste_clipboard_cb (EHTMLEditorView *view,
+static gboolean
+msg_composer_paste_clipboard_cb (EContentEditor *cnt_editor,
EMsgComposer *composer)
{
- if (composer->priv->ignore_next_paste_clipboard_signals_emission)
- composer->priv->ignore_next_paste_clipboard_signals_emission = FALSE;
- else {
- GtkClipboard *clipboard;
+ GtkClipboard *clipboard;
- clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
+ clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
- composer->priv->last_signal_was_paste_primary = FALSE;
+ composer->priv->last_signal_was_paste_primary = FALSE;
- gtk_clipboard_request_targets (
- clipboard, (GtkClipboardTargetsReceivedFunc)
- msg_composer_paste_clipboard_targets_cb, composer);
+ gtk_clipboard_request_targets (
+ clipboard, (GtkClipboardTargetsReceivedFunc)
+ msg_composer_paste_clipboard_targets_cb, composer);
- g_signal_stop_emission_by_name (view, "paste-clipboard");
- }
+ return TRUE;
}
-
+#if 0 /* FIXME WK2 */
static gboolean
msg_composer_drag_motion_cb (GtkWidget *widget,
GdkDragContext *context,
@@ -1792,50 +1805,6 @@ msg_composer_drag_motion_cb (GtkWidget *widget,
return FALSE;
}
-static void
-insert_nbsp_history_event (EHTMLEditorView *editor_view,
- gboolean delete,
- guint x,
- guint y)
-{
- EHTMLEditorViewHistoryEvent *event;
- WebKitDOMDocument *document;
- WebKitDOMDocumentFragment *fragment;
-
- document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (editor_view));
-
- event = g_new0 (EHTMLEditorViewHistoryEvent, 1);
- event->type = HISTORY_AND;
- e_html_editor_view_insert_new_history_event (editor_view, event);
-
- fragment = webkit_dom_document_create_document_fragment (document);
- webkit_dom_node_append_child (
- WEBKIT_DOM_NODE (fragment),
- WEBKIT_DOM_NODE (
- webkit_dom_document_create_text_node (document, UNICODE_NBSP)),
- NULL);
-
- event = g_new0 (EHTMLEditorViewHistoryEvent, 1);
- event->type = HISTORY_DELETE;
-
- if (delete)
- g_object_set_data (G_OBJECT (fragment), "history-delete-key", GINT_TO_POINTER (1));
-
- event->data.fragment = fragment;
-
- event->before.start.x = x;
- event->before.start.y = y;
- event->before.end.x = x;
- event->before.end.y = y;
-
- event->after.start.x = x;
- event->after.start.y = y;
- event->after.end.x = x;
- event->after.end.y = y;
-
- e_html_editor_view_insert_new_history_event (editor_view, event);
-}
-
static gboolean
msg_composer_drag_drop_cb (GtkWidget *widget,
GdkDragContext *context,
@@ -1855,195 +1824,21 @@ msg_composer_drag_drop_cb (GtkWidget *widget,
EHTMLEditorView *editor_view = e_html_editor_get_view (editor);
if ((gpointer) editor_view == (gpointer) source_widget) {
- EHTMLEditorSelection *selection;
- EHTMLEditorViewHistoryEvent *event;
- gboolean start_to_start, end_to_end;
- gchar *range_text;
- guint x, y;
- WebKitDOMDocument *document;
- WebKitDOMDocumentFragment *fragment;
- WebKitDOMDOMSelection *dom_selection;
- WebKitDOMDOMWindow *dom_window;
- WebKitDOMRange *beginning_of_line = NULL;
- WebKitDOMRange *range = NULL, *range_clone = NULL;
-
- selection = e_html_editor_view_get_selection (editor_view);
- document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (editor_view));
-
- if (!(dom_window = webkit_dom_document_get_default_view (document)))
- return FALSE;
-
- if (!(dom_selection = webkit_dom_dom_window_get_selection (dom_window))) {
- g_object_unref (dom_window);
- return FALSE;
- }
-
- if (webkit_dom_dom_selection_get_range_count (dom_selection) < 1) {
- g_object_unref (dom_selection);
- g_object_unref (dom_window);
- return FALSE;
- }
-
- /* Obtain the dragged content. */
- range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
- range_clone = webkit_dom_range_clone_range (range, NULL);
-
- /* Create the history event for the content that will
- * be removed by DnD. */
- event = g_new0 (EHTMLEditorViewHistoryEvent, 1);
- event->type = HISTORY_DELETE;
-
- e_html_editor_selection_get_selection_coordinates (
- selection,
- &event->before.start.x,
- &event->before.start.y,
- &event->before.end.x,
- &event->before.end.y);
-
- x = event->before.start.x;
- y = event->before.start.y;
-
- event->after.start.x = x;
- event->after.start.y = y;
- event->after.end.x = x;
- event->after.end.y = y;
-
- /* Save the content that will be removed. */
- fragment = webkit_dom_range_clone_contents (range_clone, NULL);
-
- /* Extend the cloned range to point one character after
- * the selection ends to later check if there is a whitespace
- * after it. */
- webkit_dom_range_set_end (
- range_clone,
- webkit_dom_range_get_end_container (range_clone, NULL),
- webkit_dom_range_get_end_offset (range_clone, NULL) + 1,
- NULL);
- range_text = webkit_dom_range_get_text (range_clone);
-
- /* Check if the current selection starts on the beginning
- * of line. */
- webkit_dom_dom_selection_modify (
- dom_selection, "extend", "left", "lineboundary");
- beginning_of_line = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
- start_to_start = webkit_dom_range_compare_boundary_points (
- beginning_of_line, 0 /* START_TO_START */, range, NULL) == 0;
-
- /* Restore the selection to state before the check. */
- webkit_dom_dom_selection_remove_all_ranges (dom_selection);
- webkit_dom_dom_selection_add_range (dom_selection, range);
- g_object_unref (beginning_of_line);
-
- /* Check if the current selection end on the end of the line. */
- webkit_dom_dom_selection_modify (
- dom_selection, "extend", "right", "lineboundary");
- beginning_of_line = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
- end_to_end = webkit_dom_range_compare_boundary_points (
- beginning_of_line, 2 /* END_TO_END */, range, NULL) == 0;
-
- /* Dragging the whole line. */
- if (start_to_start && end_to_end) {
- WebKitDOMNode *container, *actual_block, *tmp_block;
-
- /* Select the whole line (to the beginning of the next
- * one so we can reuse the undo code while undoing this.
- * Because of this we need to special mark the event
- * with history-drag-and-drop to correct the selection
- * after undoing it (otherwise the beginning of the next
- * line will be selected as well. */
- webkit_dom_dom_selection_modify (
- dom_selection, "extend", "right", "character");
- g_object_unref (beginning_of_line);
- beginning_of_line = webkit_dom_dom_selection_get_range_at (dom_selection, 0,
NULL);
-
- container = webkit_dom_range_get_end_container (range, NULL);
- actual_block = e_html_editor_get_parent_block_node_from_child (container);
-
- tmp_block = webkit_dom_range_get_end_container (beginning_of_line, NULL);
- if ((tmp_block = e_html_editor_get_parent_block_node_from_child (tmp_block)))
{
- e_html_editor_selection_get_selection_coordinates (
- selection,
- &event->before.start.x,
- &event->before.start.y,
- &event->before.end.x,
- &event->before.end.y);
-
- /* Create the right content for the history event. */
- fragment = webkit_dom_document_create_document_fragment (document);
- /* The removed line. */
- webkit_dom_node_append_child (
- WEBKIT_DOM_NODE (fragment),
- webkit_dom_node_clone_node (actual_block, TRUE),
- NULL);
- /* The following block, but empty. */
- webkit_dom_node_append_child (
- WEBKIT_DOM_NODE (fragment),
- webkit_dom_node_clone_node (tmp_block, FALSE),
- NULL);
- g_object_set_data (
- G_OBJECT (fragment),
- "history-drag-and-drop",
- GINT_TO_POINTER (1));
- /* It should act as a Delete key press. */
- g_object_set_data (
- G_OBJECT (fragment),
- "history-delete-key",
- GINT_TO_POINTER (1));
- }
- }
-
- event->data.fragment = fragment;
- e_html_editor_view_insert_new_history_event (editor_view, event);
-
- /* Selection is ending on the end of the line, check if
- * there is a space before the selection start. If so, it
- * will be removed and we need create the history event
- * for it. */
- if (end_to_end) {
- gchar *range_text_start;
- glong start_offset;
-
- start_offset = webkit_dom_range_get_start_offset (range_clone, NULL);
- webkit_dom_range_set_start (
- range_clone,
- webkit_dom_range_get_start_container (range_clone, NULL),
- start_offset > 0 ? start_offset - 1 : 0,
+ GDBusProxy *web_extension;
+
+ web_extension = e_html_editor_view_get_web_extension_proxy (editor_view);
+ if (web_extension) {
+ g_dbus_proxy_call_sync (
+ web_extension,
+ "DOMSaveDragAndDropHistory",
+ g_variant_new (
+ "(t)",
+ webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (editor_view))),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
NULL);
-
- range_text_start = webkit_dom_range_get_text (range_clone);
- if (g_str_has_prefix (range_text_start, " ") ||
- g_str_has_prefix (range_text_start, UNICODE_NBSP))
- insert_nbsp_history_event (editor_view, FALSE, x, y);
-
- g_free (range_text_start);
}
-
- /* WebKit removes the space (if presented) after selection and
- * we need to create a new history event for it. */
- if (g_str_has_suffix (range_text, " ") ||
- g_str_has_suffix (range_text, UNICODE_NBSP))
- insert_nbsp_history_event (editor_view, TRUE, x, y);
-
- g_free (range_text);
-
- /* Restore the selection to original state. */
- webkit_dom_dom_selection_remove_all_ranges (dom_selection);
- webkit_dom_dom_selection_add_range (dom_selection, range);
- g_object_unref (beginning_of_line);
-
- /* All the things above were about removing the content,
- * create an AND event to continue later with inserting
- * the dropped content. */
- event = g_new0 (EHTMLEditorViewHistoryEvent, 1);
- event->type = HISTORY_AND;
- e_html_editor_view_insert_new_history_event (editor_view, event);
-
- g_object_unref (dom_selection);
- g_object_unref (dom_window);
-
- g_object_unref (range);
- g_object_unref (range_clone);
-
return FALSE;
}
}
@@ -2086,6 +1881,7 @@ msg_composer_drag_data_received_after_cb (GtkWidget *widget,
{
EHTMLEditor *editor;
EHTMLEditorView *view;
+ GDBusProxy *web_extension;
if (!composer->priv->drop_occured)
goto out;
@@ -2096,8 +1892,20 @@ msg_composer_drag_data_received_after_cb (GtkWidget *widget,
editor = e_msg_composer_get_editor (composer);
view = e_html_editor_get_view (editor);
- e_html_editor_view_save_history_for_drop (view);
- e_html_editor_view_check_magic_links (view, FALSE);
+ web_extension = e_html_editor_view_get_web_extension_proxy (view);
+ if (!web_extension)
+ goto out;
+
+ g_dbus_proxy_call_sync (
+ web_extension,
+ "DOMCleanAfterDragAndDrop",
+ g_variant_new (
+ "(t)",
+ webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (view))),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL);
out:
composer->priv->drop_occured = FALSE;
@@ -2140,28 +1948,22 @@ msg_composer_drag_data_received_cb (GtkWidget *widget,
EMsgComposer *composer)
{
EHTMLEditor *editor;
- EHTMLEditorView *html_editor_view;
- EHTMLEditorSelection *editor_selection;
+ EContentEditor *cnt_editor;
gboolean html_mode, same_widget = FALSE;
GtkWidget *source_widget;
editor = e_msg_composer_get_editor (composer);
- html_editor_view = e_html_editor_get_view (editor);
- html_mode = e_html_editor_view_get_html_mode (html_editor_view);
- editor_selection = e_html_editor_view_get_selection (html_editor_view);
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ html_mode = e_content_editor_get_html_mode (cnt_editor);
composer->priv->dnd_history_saved = TRUE;
/* When we are doing DnD just inside the web view, the DnD is supposed
* to move things around. */
source_widget = gtk_drag_get_source_widget (context);
- if (E_IS_HTML_EDITOR_VIEW (source_widget)) {
- EHTMLEditor *editor = e_msg_composer_get_editor (composer);
- EHTMLEditorView *editor_view = e_html_editor_get_view (editor);
-
- if ((gpointer) editor_view == (gpointer) source_widget)
- same_widget = TRUE;
- }
+ if (E_IS_CONTENT_EDITOR (source_widget) &&
+ ((gpointer) cnt_editor == (gpointer) source_widget))
+ same_widget = TRUE;
/* Leave DnD inside the view on WebKit. */
if (composer->priv->drop_occured && same_widget) {
@@ -2215,21 +2017,20 @@ msg_composer_drag_data_received_cb (GtkWidget *widget,
return;
}
- e_html_editor_selection_set_on_point (editor_selection, x, y);
+ e_content_editor_move_caret_on_coordinates (cnt_editor, x, y, FALSE);
list_len = length;
do {
text = next_uri ((guchar **) &data, &len, &list_len);
- e_html_editor_selection_insert_html (editor_selection, text);
+ e_content_editor_insert_content (
+ cnt_editor,
+ text,
+ E_CONTENT_EDITOR_INSERT_TEXT_HTML);
g_free (text);
} while (list_len);
- e_html_editor_view_check_magic_links (html_editor_view, FALSE);
- e_html_editor_view_force_spell_check_in_viewport (html_editor_view);
-
- e_html_editor_selection_scroll_to_caret (editor_selection);
-
gtk_drag_finish (context, TRUE, FALSE, time);
+
return;
}
@@ -2253,38 +2054,38 @@ msg_composer_drag_data_received_cb (GtkWidget *widget,
return;
}
- e_html_editor_selection_set_on_point (editor_selection, x, y);
+ e_content_editor_move_caret_on_coordinates (cnt_editor, x, y, FALSE);
list_len = length;
do {
uri = next_uri ((guchar **) &data, &len, &list_len);
- e_html_editor_selection_insert_image (editor_selection, uri);
+ e_content_editor_insert_image (cnt_editor, uri);
g_free (uri);
} while (list_len);
gtk_drag_finish (context, TRUE, FALSE, time);
} else {
- EAttachmentView *view = e_msg_composer_get_attachment_view (composer);
-
+ EAttachmentView *attachment_view =
+ e_msg_composer_get_attachment_view (composer);
/* 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),
+ E_ATTACHMENT_PANED (attachment_view),
context, x, y, selection, info, time);
}
}
-
+#endif
static void
msg_composer_notify_header_cb (EMsgComposer *composer)
{
+ EContentEditor *cnt_editor;
EHTMLEditor *editor;
- EHTMLEditorView *view;
editor = e_msg_composer_get_editor (composer);
- view = e_html_editor_get_view (editor);
- e_html_editor_view_set_changed (view, TRUE);
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ e_content_editor_set_changed (cnt_editor, TRUE);
}
static gboolean
@@ -2408,6 +2209,16 @@ msg_composer_quit_requested_cb (EShell *shell,
}
static void
+msg_composer_set_editor (EMsgComposer *composer,
+ EHTMLEditor *editor)
+{
+ g_return_if_fail (E_IS_HTML_EDITOR (editor));
+ g_return_if_fail (composer->priv->editor == NULL);
+
+ composer->priv->editor = g_object_ref_sink (editor);
+}
+
+static void
msg_composer_set_shell (EMsgComposer *composer,
EShell *shell)
{
@@ -2427,6 +2238,12 @@ msg_composer_set_property (GObject *object,
GParamSpec *pspec)
{
switch (property_id) {
+ case PROP_EDITOR:
+ msg_composer_set_editor (
+ E_MSG_COMPOSER (object),
+ g_value_get_object (value));
+ return;
+
case PROP_SHELL:
msg_composer_set_shell (
E_MSG_COMPOSER (object),
@@ -2450,6 +2267,12 @@ msg_composer_get_property (GObject *object,
E_MSG_COMPOSER (object)));
return;
+ case PROP_EDITOR:
+ g_value_set_object (
+ value, e_msg_composer_get_editor (
+ E_MSG_COMPOSER (object)));
+ return;
+
case PROP_FOCUS_TRACKER:
g_value_set_object (
value, e_msg_composer_get_focus_tracker (
@@ -2514,9 +2337,8 @@ composer_notify_activity_cb (EActivityBar *activity_bar,
EMsgComposer *composer)
{
EHTMLEditor *editor;
- EHTMLEditorView *view;
- WebKitWebView *web_view;
- gboolean editable;
+ EContentEditor *cnt_editor;
+ gboolean editable = TRUE;
gboolean busy;
busy = (e_activity_bar_get_activity (activity_bar) != NULL);
@@ -2530,16 +2352,15 @@ composer_notify_activity_cb (EActivityBar *activity_bar,
e_msg_composer_save_focused_widget (composer);
editor = e_msg_composer_get_editor (composer);
- view = e_html_editor_get_view (editor);
- web_view = WEBKIT_WEB_VIEW (view);
+ cnt_editor = e_html_editor_get_content_editor (editor);
if (busy) {
- editable = webkit_web_view_get_editable (web_view);
- webkit_web_view_set_editable (web_view, FALSE);
+ editable = e_content_editor_is_editable (cnt_editor);
+ e_content_editor_set_editable (cnt_editor, FALSE);
composer->priv->saved_editable = editable;
} else {
editable = composer->priv->saved_editable;
- webkit_web_view_set_editable (web_view, editable);
+ e_content_editor_set_editable (cnt_editor, editable);
}
g_object_notify (G_OBJECT (composer), "busy");
@@ -2554,11 +2375,11 @@ msg_composer_constructed (GObject *object)
EShell *shell;
EMsgComposer *composer;
EActivityBar *activity_bar;
- EAttachmentView *view;
+ EAttachmentView *attachment_view;
EAttachmentStore *store;
EComposerHeaderTable *table;
EHTMLEditor *editor;
- EHTMLEditorView *html_editor_view;
+ EContentEditor *cnt_editor;
GtkUIManager *ui_manager;
GtkToggleAction *action;
GtkTargetList *target_list;
@@ -2568,16 +2389,21 @@ msg_composer_constructed (GObject *object)
const gchar *id;
gboolean active;
+ /* Chain up to parent's constructed() method. */
+ G_OBJECT_CLASS (e_msg_composer_parent_class)->constructed (object);
+
composer = E_MSG_COMPOSER (object);
+ g_return_if_fail (E_IS_HTML_EDITOR (composer->priv->editor));
+
shell = e_msg_composer_get_shell (composer);
e_composer_private_constructed (composer);
editor = e_msg_composer_get_editor (composer);
- html_editor_view = e_html_editor_get_view (editor);
+ cnt_editor = e_html_editor_get_content_editor (editor);
ui_manager = e_html_editor_get_ui_manager (editor);
- view = e_msg_composer_get_attachment_view (composer);
+ attachment_view = e_msg_composer_get_attachment_view (composer);
table = E_COMPOSER_HEADER_TABLE (composer->priv->header_table);
gtk_window_set_title (GTK_WINDOW (composer), _("Compose Message"));
@@ -2625,40 +2451,45 @@ msg_composer_constructed (GObject *object)
gtk_toggle_action_set_active (action, active);
action = GTK_TOGGLE_ACTION (ACTION (UNICODE_SMILEYS));
- active = g_settings_get_boolean (settings, "composer-unicode-smileys");
- gtk_toggle_action_set_active (action, active);
+ g_settings_bind (settings, "composer-unicode-smileys",
+ action, "active",
+ G_SETTINGS_BIND_DEFAULT);
+
g_object_unref (settings);
/* Clipboard Support */
g_signal_connect (
- html_editor_view, "paste-clipboard",
+ cnt_editor, "paste-clipboard",
G_CALLBACK (msg_composer_paste_clipboard_cb), composer);
g_signal_connect (
- html_editor_view, "paste-primary-clipboard",
+ cnt_editor, "paste-primary-clipboard",
G_CALLBACK (msg_composer_paste_primary_clipboard_cb), composer);
- e_html_editor_view_reconnect_paste_clipboard_signals (html_editor_view);
/* Drag-and-Drop Support */
+#if 0 /* FIXME WK2 */
+ EHTMLEditorView *view;
+
+ view = e_html_editor_get_view (editor);
g_signal_connect (
- html_editor_view, "drag-motion",
+ view, "drag-motion",
G_CALLBACK (msg_composer_drag_motion_cb), composer);
- g_signal_connect (
- html_editor_view, "drag-drop",
+ g_signal_connect (
+ view, "drag-drop",
G_CALLBACK (msg_composer_drag_drop_cb), composer);
g_signal_connect (
- html_editor_view, "drag-data-received",
+ view, "drag-data-received",
G_CALLBACK (msg_composer_drag_data_received_cb), composer);
/* Used for fixing various stuff after WebKit processed the DnD data. */
g_signal_connect_after (
- html_editor_view, "drag-data-received",
+ view, "drag-data-received",
G_CALLBACK (msg_composer_drag_data_received_after_cb), composer);
-
+#endif
g_signal_connect (
composer->priv->gallery_icon_view, "drag-data-get",
G_CALLBACK (msg_composer_gallery_drag_data_get), NULL);
@@ -2694,7 +2525,7 @@ msg_composer_constructed (GObject *object)
/* Attachments */
- store = e_attachment_view_get_store (view);
+ store = e_attachment_view_get_store (attachment_view);
g_signal_connect_swapped (
store, "row-deleted",
@@ -2705,12 +2536,12 @@ msg_composer_constructed (GObject *object)
G_CALLBACK (attachment_store_changed_cb), composer);
/* Initialization may have tripped the "changed" state. */
- e_html_editor_view_set_changed (html_editor_view, FALSE);
+ e_content_editor_set_changed (cnt_editor, FALSE);
- target_list = e_attachment_view_get_target_list (view);
+ target_list = e_attachment_view_get_target_list (attachment_view);
targets = gtk_target_table_new_from_list (target_list, &n_targets);
- target_list = gtk_drag_dest_get_target_list (GTK_WIDGET (html_editor_view));
+ target_list = gtk_drag_dest_get_target_list (GTK_WIDGET (cnt_editor));
gtk_target_list_add_table (target_list, drag_dest_targets, G_N_ELEMENTS (drag_dest_targets));
gtk_target_list_add_table (target_list, targets, n_targets);
@@ -2724,8 +2555,6 @@ msg_composer_constructed (GObject *object)
e_extensible_load_extensions (E_EXTENSIBLE (composer));
e_msg_composer_set_body_text (composer, "", TRUE);
- /* Chain up to parent's constructed() method. */
- G_OBJECT_CLASS (e_msg_composer_parent_class)->constructed (object);
}
static void
@@ -2782,7 +2611,7 @@ msg_composer_map (GtkWidget *widget)
EComposerHeaderTable *table;
GtkWidget *input_widget;
EHTMLEditor *editor;
- EHTMLEditorView *view;
+ EContentEditor *cnt_editor;
const gchar *text;
/* Chain up to parent's map() method. */
@@ -2813,8 +2642,8 @@ msg_composer_map (GtkWidget *widget)
}
/* Jump to the editor as a last resort. */
- view = e_html_editor_get_view (editor);
- gtk_widget_grab_focus (GTK_WIDGET (view));
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ gtk_widget_grab_focus (GTK_WIDGET (cnt_editor));
}
static gboolean
@@ -2824,11 +2653,11 @@ msg_composer_key_press_event (GtkWidget *widget,
EMsgComposer *composer;
GtkWidget *input_widget;
EHTMLEditor *editor;
- EHTMLEditorView *view;
+ EContentEditor *cnt_editor;
composer = E_MSG_COMPOSER (widget);
editor = e_msg_composer_get_editor (composer);
- view = e_html_editor_get_view (editor);
+ cnt_editor = e_html_editor_get_content_editor (editor);
input_widget =
e_composer_header_table_get_header (
@@ -2848,15 +2677,15 @@ msg_composer_key_press_event (GtkWidget *widget,
}
if (event->keyval == GDK_KEY_Tab && gtk_widget_is_focus (input_widget)) {
- gtk_widget_grab_focus (GTK_WIDGET (view));
+ gtk_widget_grab_focus (GTK_WIDGET (cnt_editor));
return TRUE;
}
- if (gtk_widget_is_focus (GTK_WIDGET (view))) {
+ if (gtk_widget_is_focus (GTK_WIDGET (cnt_editor))) {
if (event->keyval == GDK_KEY_ISO_Left_Tab) {
gboolean view_processed = FALSE;
- g_signal_emit_by_name (view, "key-press-event", event, &view_processed);
+ g_signal_emit_by_name (cnt_editor, "key-press-event", event, &view_processed);
if (!view_processed)
gtk_widget_grab_focus (input_widget);
@@ -2942,6 +2771,17 @@ e_msg_composer_class_init (EMsgComposerClass *class)
g_object_class_install_property (
object_class,
+ PROP_EDITOR,
+ g_param_spec_object (
+ "editor",
+ NULL,
+ NULL,
+ E_TYPE_HTML_EDITOR,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY));
+
+ g_object_class_install_property (
+ object_class,
PROP_FOCUS_TRACKER,
g_param_spec_object (
"focus-tracker",
@@ -3019,31 +2859,87 @@ e_msg_composer_class_init (EMsgComposerClass *class)
static void
e_msg_composer_init (EMsgComposer *composer)
{
- EHTMLEditorView *view;
-
composer->priv = E_MSG_COMPOSER_GET_PRIVATE (composer);
+}
- composer->priv->editor = g_object_ref_sink (e_html_editor_new ());
- view = e_html_editor_get_view (composer->priv->editor);
- e_html_editor_view_set_is_editting_message (view, TRUE);
+static void
+e_msg_composer_editor_created_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GtkWidget *editor;
+ ESimpleAsyncResult *eresult = user_data;
+ GError *error = NULL;
+
+ g_return_if_fail (E_IS_SIMPLE_ASYNC_RESULT (eresult));
+
+ editor = e_html_editor_new_finish (result, &error);
+ if (error) {
+ g_warning ("%s: Failed to create HTML editor: %s", G_STRFUNC, error->message);
+ g_clear_error (&error);
+ } else {
+ e_simple_async_result_set_op_pointer (eresult, editor);
+ e_simple_async_result_complete (eresult);
+ }
+
+ g_object_unref (eresult);
}
/**
* e_msg_composer_new:
* @shell: an #EShell
+ * @callback: called when the composer is ready
+ * @user_data: user data passed to @callback
+ *
+ * Asynchronously creates an #EMsgComposer. The operation is finished
+ * with e_msg_composer_new_finish() called from within the @callback.
+ *
+ * Since: 3.22
+ **/
+void
+e_msg_composer_new (EShell *shell,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ ESimpleAsyncResult *eresult;
+
+ g_return_if_fail (E_IS_SHELL (shell));
+ g_return_if_fail (callback != NULL);
+
+ eresult = e_simple_async_result_new (NULL, callback, user_data, e_msg_composer_new);
+ e_simple_async_result_set_user_data (eresult, g_object_ref (shell), g_object_unref);
+
+ e_html_editor_new (e_msg_composer_editor_created_cb, eresult);
+}
+
+/**
+ * e_msg_composer_new_finish:
+ * @result: a #GAsyncResult provided by the callback from e_msg_composer_new()
+ * @error: optional #GError for errors
*
- * Create a new message composer widget.
+ * Finishes call of e_msg_composer_new().
*
- * Returns: A pointer to the newly created widget
+ * Since: 3.22
**/
EMsgComposer *
-e_msg_composer_new (EShell *shell)
+e_msg_composer_new_finish (GAsyncResult *result,
+ GError **error)
{
- g_return_val_if_fail (E_IS_SHELL (shell), NULL);
+ ESimpleAsyncResult *eresult;
+ EHTMLEditor *html_editor;
+
+ g_return_val_if_fail (E_IS_SIMPLE_ASYNC_RESULT (result), NULL);
+ g_return_val_if_fail (g_async_result_is_tagged (result, e_msg_composer_new), NULL);
+
+ eresult = E_SIMPLE_ASYNC_RESULT (result);
+
+ html_editor = e_simple_async_result_get_op_pointer (eresult);
+ g_return_val_if_fail (E_IS_HTML_EDITOR (html_editor), NULL);
- return g_object_new (
- E_TYPE_MSG_COMPOSER,
- "shell", shell, NULL);
+ return g_object_new (E_TYPE_MSG_COMPOSER,
+ "shell", e_simple_async_result_get_user_data (eresult),
+ "editor", html_editor,
+ NULL);
}
/**
@@ -3110,7 +3006,7 @@ add_attachments_handle_mime_part (EMsgComposer *composer,
CamelContentType *content_type;
CamelDataWrapper *wrapper;
EHTMLEditor *editor;
- EHTMLEditorView *view;
+ EContentEditor *cnt_editor;
if (!mime_part)
return;
@@ -3118,7 +3014,7 @@ add_attachments_handle_mime_part (EMsgComposer *composer,
content_type = camel_mime_part_get_content_type (mime_part);
wrapper = camel_medium_get_content (CAMEL_MEDIUM (mime_part));
editor = e_msg_composer_get_editor (composer);
- view = e_html_editor_get_view (editor);
+ cnt_editor = e_html_editor_get_content_editor (editor);
if (CAMEL_IS_MULTIPART (wrapper)) {
/* another layer of multipartness... */
@@ -3128,10 +3024,10 @@ add_attachments_handle_mime_part (EMsgComposer *composer,
} else if (just_inlines) {
if (camel_mime_part_get_content_id (mime_part) ||
camel_mime_part_get_content_location (mime_part))
- e_html_editor_view_add_inline_image_from_mime_part (
- view, mime_part);
+ e_content_editor_insert_image_from_mime_part (
+ cnt_editor, mime_part);
} else if (related && camel_content_type_is (content_type, "image", "*")) {
- e_html_editor_view_add_inline_image_from_mime_part (view, mime_part);
+ e_content_editor_insert_image_from_mime_part (cnt_editor, mime_part);
} else if (camel_content_type_is (content_type, "text", "*") &&
camel_mime_part_get_filename (mime_part) == NULL) {
/* Do nothing if this is a text/anything without a
@@ -3525,56 +3421,26 @@ handle_multipart (EMsgComposer *composer,
}
} else if (depth == 0 && i == 0) {
- EHTMLEditor *editor;
- gboolean is_message_from_draft, is_html = FALSE;
gchar *html = NULL;
gssize length = 0;
- editor = e_msg_composer_get_editor (composer);
- is_message_from_draft = e_html_editor_view_is_message_from_draft (
- e_html_editor_get_view (editor));
- is_html = camel_content_type_is (content_type, "text", "html");
-
/* Since the first part is not multipart/alternative,
* this must be the body. */
+ html = emcu_part_to_html (
+ composer, mime_part, &length, keep_signature, cancellable);
- /* If we are opening message from Drafts */
- if (is_message_from_draft) {
- /* Extract the body */
- CamelDataWrapper *dw;
-
- dw = camel_medium_get_content ((CamelMedium *) mime_part);
- if (dw) {
- CamelStream *mem = camel_stream_mem_new ();
- GByteArray *bytes;
-
- camel_data_wrapper_decode_to_stream_sync (dw, mem, cancellable, NULL);
- camel_stream_close (mem, cancellable, NULL);
-
- bytes = camel_stream_mem_get_byte_array (CAMEL_STREAM_MEM (mem));
- if (bytes && bytes->len)
- html = g_strndup ((const gchar *) bytes->data, bytes->len);
-
- g_object_unref (mem);
- }
- } else {
- is_html = TRUE;
- html = emcu_part_to_html (
- composer, mime_part, &length, keep_signature, cancellable);
- }
-
- if (html)
- e_msg_composer_set_pending_body (composer, html, length, is_html);
+ e_msg_composer_set_pending_body (composer, html, length, TRUE);
} else if (camel_mime_part_get_content_id (mime_part) ||
camel_mime_part_get_content_location (mime_part)) {
/* special in-line attachment */
EHTMLEditor *editor;
+ EContentEditor *cnt_editor;
editor = e_msg_composer_get_editor (composer);
- e_html_editor_view_add_inline_image_from_mime_part (
- e_html_editor_get_view (editor), mime_part);
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ e_content_editor_insert_image_from_mime_part (cnt_editor, mime_part);
} else {
/* normal attachment */
e_msg_composer_attach (composer, mime_part);
@@ -3586,9 +3452,7 @@ static void
set_signature_gui (EMsgComposer *composer)
{
EHTMLEditor *editor;
- EHTMLEditorView *view;
- WebKitDOMDocument *document;
- WebKitDOMElement *element;
+ EContentEditor *cnt_editor;
EComposerHeaderTable *table;
EMailSignatureComboBox *combo_box;
gchar *uid = NULL;
@@ -3597,16 +3461,11 @@ set_signature_gui (EMsgComposer *composer)
combo_box = e_composer_header_table_get_signature_combo_box (table);
editor = e_msg_composer_get_editor (composer);
- view = e_html_editor_get_view (editor);
- document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (view));
-
- if ((element = webkit_dom_document_query_selector (document, ".-x-evo-signature[id]", NULL)))
- uid = webkit_dom_element_get_id (element);
+ cnt_editor = e_html_editor_get_content_editor (editor);
- /* The combo box active ID is the signature's ESource UID. */
- if (uid != NULL) {
+ if ((uid = e_content_editor_get_current_signature_uid (cnt_editor))) {
+ /* The combo box active ID is the signature's ESource UID. */
gtk_combo_box_set_active_id (GTK_COMBO_BOX (combo_box), uid);
- g_free (uid);
}
}
@@ -3657,25 +3516,25 @@ composer_add_auto_recipients (ESource *source,
}
/**
- * e_msg_composer_new_with_message:
- * @shell: an #EShell
+ * e_msg_composer_setup_with_message:
+ * @composer: an #EMsgComposer
* @message: The message to use as the source
* @keep_signature: Keep message signature, if any
* @override_identity_uid: (allow none): Optional identity UID to use, or %NULL
* @cancellable: optional #GCancellable object, or %NULL
*
- * Create a new message composer widget.
+ * Sets up the message @composer with a specific @message.
*
* Note: Designed to work only for messages constructed using Evolution.
*
- * Returns: A pointer to the newly created widget
+ * Since: 3.22
**/
-EMsgComposer *
-e_msg_composer_new_with_message (EShell *shell,
- CamelMimeMessage *message,
- gboolean keep_signature,
- const gchar *override_identity_uid,
- GCancellable *cancellable)
+void
+e_msg_composer_setup_with_message (EMsgComposer *composer,
+ CamelMimeMessage *message,
+ gboolean keep_signature,
+ const gchar *override_identity_uid,
+ GCancellable *cancellable)
{
CamelInternetAddress *from, *to, *cc, *bcc;
GList *To = NULL, *Cc = NULL, *Bcc = NULL, *postto = NULL;
@@ -3685,19 +3544,18 @@ e_msg_composer_new_with_message (EShell *shell,
CamelContentType *content_type;
struct _camel_header_raw *headers;
CamelDataWrapper *content;
- EMsgComposer *composer;
EMsgComposerPrivate *priv;
EComposerHeaderTable *table;
ESource *source = NULL;
EHTMLEditor *editor;
- EHTMLEditorView *view;
+ EContentEditor *cnt_editor;
GtkToggleAction *action;
struct _camel_header_raw *xev;
gchar *identity_uid;
gint len, i;
gboolean is_message_from_draft = FALSE;
- g_return_val_if_fail (E_IS_SHELL (shell), NULL);
+ g_return_if_fail (E_IS_MSG_COMPOSER (composer));
headers = CAMEL_MIME_PART (message)->headers;
while (headers != NULL) {
@@ -3711,11 +3569,10 @@ e_msg_composer_new_with_message (EShell *shell,
headers = headers->next;
}
- composer = e_msg_composer_new (shell);
priv = E_MSG_COMPOSER_GET_PRIVATE (composer);
- editor = e_msg_composer_get_editor (composer);
table = e_msg_composer_get_header_table (composer);
- view = e_html_editor_get_view (editor);
+ editor = e_msg_composer_get_editor (composer);
+ cnt_editor = e_html_editor_get_content_editor (editor);
if (postto) {
e_composer_header_table_set_post_to_list (table, postto);
@@ -3737,7 +3594,7 @@ e_msg_composer_new_with_message (EShell *shell,
}
if (!identity_uid) {
source = em_utils_guess_mail_identity_with_recipients (
- e_shell_get_registry (shell), message, NULL, NULL);
+ e_shell_get_registry (e_msg_composer_get_shell (composer)), message, NULL,
NULL);
if (source)
identity_uid = e_source_dup_uid (source);
}
@@ -3878,10 +3735,8 @@ e_msg_composer_new_with_message (EShell *shell,
composer_mode = camel_medium_get_header (
CAMEL_MEDIUM (message), "X-Evolution-Composer-Mode");
- if (composer_mode && *composer_mode) {
+ if (composer_mode && *composer_mode)
is_message_from_draft = TRUE;
- e_html_editor_view_set_is_message_from_draft (view, TRUE);
- }
if (format != NULL) {
gchar **flags;
@@ -3891,22 +3746,12 @@ e_msg_composer_new_with_message (EShell *shell,
flags = g_strsplit (format, ", ", 0);
for (i = 0; flags[i]; i++) {
- if (g_ascii_strcasecmp (flags[i], "text/html") == 0) {
- if (composer_mode && g_ascii_strcasecmp (composer_mode, "text/html") == 0) {
- e_html_editor_view_set_html_mode (
- view, TRUE);
- } else {
- e_html_editor_view_set_html_mode (
- view, FALSE);
- }
- } else if (g_ascii_strcasecmp (flags[i], "text/plain") == 0) {
- if (composer_mode && g_ascii_strcasecmp (composer_mode, "text/html") == 0) {
- e_html_editor_view_set_html_mode (
- view, TRUE);
- } else {
- e_html_editor_view_set_html_mode (
- view, FALSE);
- }
+ if (g_ascii_strcasecmp (flags[i], "text/html") == 0 ||
+ g_ascii_strcasecmp (flags[i], "text/plain") == 0) {
+ gboolean html_mode;
+
+ html_mode = composer_mode && !g_ascii_strcasecmp (composer_mode, "text/html");
+ e_content_editor_set_html_mode (cnt_editor, html_mode);
} else if (g_ascii_strcasecmp (flags[i], "pgp-sign") == 0) {
action = GTK_TOGGLE_ACTION (ACTION (PGP_SIGN));
gtk_toggle_action_set_active (action, TRUE);
@@ -4040,7 +3885,6 @@ e_msg_composer_new_with_message (EShell *shell,
e_msg_composer_set_pending_body (composer, html, length, is_html);
}
- e_html_editor_view_set_is_message_from_edit_as_new (view, TRUE);
priv->set_signature_from_message = TRUE;
/* We wait until now to set the body text because we need to
@@ -4049,38 +3893,36 @@ e_msg_composer_new_with_message (EShell *shell,
e_msg_composer_flush_pending_body (composer);
set_signature_gui (composer);
-
- return composer;
}
/**
- * e_msg_composer_new_redirect:
- * @shell: an #EShell
+ * e_msg_composer_setup_redirect:
+ * @composer: an #EMsgComposer
* @message: The message to use as the source
+ * @identity_uid: (nullable): an identity UID to use, if any
+ * @cancellable: an optional #GCancellable
*
- * Create a new message composer widget.
+ * Sets up the message @composer as a redirect of the @message.
*
- * Returns: A pointer to the newly created widget
+ * Since: 3.22
**/
-EMsgComposer *
-e_msg_composer_new_redirect (EShell *shell,
- CamelMimeMessage *message,
- const gchar *identity_uid,
- GCancellable *cancellable)
+void
+e_msg_composer_setup_redirect (EMsgComposer *composer,
+ CamelMimeMessage *message,
+ const gchar *identity_uid,
+ GCancellable *cancellable)
{
- EMsgComposer *composer;
EComposerHeaderTable *table;
EHTMLEditor *editor;
- EHTMLEditorView *view;
+ EContentEditor *cnt_editor;
const gchar *subject;
- g_return_val_if_fail (E_IS_SHELL (shell), NULL);
- g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), NULL);
+ g_return_if_fail (E_IS_MSG_COMPOSER (composer));
+ g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message));
- composer = e_msg_composer_new_with_message (
- shell, message, TRUE, identity_uid, cancellable);
- table = e_msg_composer_get_header_table (composer);
+ e_msg_composer_setup_with_message (composer, message, TRUE, identity_uid, cancellable);
+ table = e_msg_composer_get_header_table (composer);
subject = camel_mime_message_get_subject (message);
composer->priv->redirect = message;
@@ -4089,10 +3931,8 @@ e_msg_composer_new_redirect (EShell *shell,
e_composer_header_table_set_subject (table, subject);
editor = e_msg_composer_get_editor (composer);
- view = e_html_editor_get_view (editor);
- webkit_web_view_set_editable (WEBKIT_WEB_VIEW (view), FALSE);
-
- return composer;
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ e_content_editor_set_editable (cnt_editor, FALSE);
}
/**
@@ -4149,7 +3989,7 @@ msg_composer_send_cb (EMsgComposer *composer,
CamelMimeMessage *message;
EAlertSink *alert_sink;
EHTMLEditor *editor;
- EHTMLEditorView *view;
+ EContentEditor *cnt_editor;
GError *error = NULL;
alert_sink = e_activity_get_alert_sink (context->activity);
@@ -4182,8 +4022,8 @@ msg_composer_send_cb (EMsgComposer *composer,
/* The callback can set editor 'changed' if anything failed. */
editor = e_msg_composer_get_editor (composer);
- view = e_html_editor_get_view (editor);
- e_html_editor_view_set_changed (view, TRUE);
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ e_content_editor_set_changed (cnt_editor, TRUE);
composer->priv->is_sending_message = TRUE;
@@ -4241,15 +4081,15 @@ msg_composer_save_to_drafts_done_cb (gpointer user_data,
{
EMsgComposer *composer = user_data;
EHTMLEditor *editor;
- EHTMLEditorView *view;
+ EContentEditor *cnt_editor;
g_return_if_fail (E_IS_MSG_COMPOSER (composer));
editor = e_msg_composer_get_editor (composer);
- view = e_html_editor_get_view (editor);
+ cnt_editor = e_html_editor_get_content_editor (editor);
if (e_msg_composer_is_exiting (composer) &&
- !e_html_editor_view_get_changed (view)) {
+ !e_content_editor_get_changed (cnt_editor)) {
gtk_widget_destroy (GTK_WIDGET (composer));
} else if (e_msg_composer_is_exiting (composer)) {
gtk_widget_set_sensitive (GTK_WIDGET (composer), TRUE);
@@ -4266,7 +4106,7 @@ msg_composer_save_to_drafts_cb (EMsgComposer *composer,
CamelMimeMessage *message;
EAlertSink *alert_sink;
EHTMLEditor *editor;
- EHTMLEditorView *view;
+ EContentEditor *cnt_editor;
GError *error = NULL;
alert_sink = e_activity_get_alert_sink (context->activity);
@@ -4308,8 +4148,8 @@ msg_composer_save_to_drafts_cb (EMsgComposer *composer,
/* The callback can set editor 'changed' if anything failed. */
editor = e_msg_composer_get_editor (composer);
- view = e_html_editor_get_view (editor);
- e_html_editor_view_set_changed (view, FALSE);
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ e_content_editor_set_changed (cnt_editor, TRUE);
g_signal_emit (
composer, signals[SAVE_TO_DRAFTS],
@@ -4361,7 +4201,7 @@ msg_composer_save_to_outbox_cb (EMsgComposer *composer,
CamelMimeMessage *message;
EAlertSink *alert_sink;
EHTMLEditor *editor;
- EHTMLEditorView *view;
+ EContentEditor *cnt_editor;
GError *error = NULL;
alert_sink = e_activity_get_alert_sink (context->activity);
@@ -4397,8 +4237,8 @@ msg_composer_save_to_outbox_cb (EMsgComposer *composer,
async_context_free (context);
editor = e_msg_composer_get_editor (composer);
- view = e_html_editor_get_view (editor);
- e_html_editor_view_set_changed (view, FALSE);
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ e_content_editor_set_changed (cnt_editor, TRUE);
}
/**
@@ -4821,27 +4661,22 @@ handle_mailto (EMsgComposer *composer,
}
/**
- * e_msg_composer_new_from_url:
- * @shell: an #EShell
+ * e_msg_composer_setup_from_url:
+ * @composer: an #EMsgComposer
* @url: a mailto URL
*
- * Create a new message composer widget, and fill in fields as
- * defined by the provided URL.
+ * Sets up the message @composer content as defined by the provided URL.
+ *
+ * Since: 3.22
**/
-EMsgComposer *
-e_msg_composer_new_from_url (EShell *shell,
- const gchar *url)
+void
+e_msg_composer_setup_from_url (EMsgComposer *composer,
+ const gchar *url)
{
- EMsgComposer *composer;
-
- g_return_val_if_fail (E_IS_SHELL (shell), NULL);
- g_return_val_if_fail (g_ascii_strncasecmp (url, "mailto:", 7) == 0, NULL);
-
- composer = e_msg_composer_new (shell);
+ g_return_if_fail (E_IS_MSG_COMPOSER (composer));
+ g_return_if_fail (g_ascii_strncasecmp (url, "mailto:", 7) == 0);
handle_mailto (composer, url);
-
- return composer;
}
/**
@@ -4881,7 +4716,7 @@ e_msg_composer_set_body (EMsgComposer *composer,
EMsgComposerPrivate *priv = composer->priv;
EComposerHeaderTable *table;
EHTMLEditor *editor;
- EHTMLEditorView *view;
+ EContentEditor *cnt_editor;
ESource *source;
const gchar *identity_uid;
const gchar *content;
@@ -4889,7 +4724,7 @@ e_msg_composer_set_body (EMsgComposer *composer,
g_return_if_fail (E_IS_MSG_COMPOSER (composer));
editor = e_msg_composer_get_editor (composer);
- view = e_html_editor_get_view (editor);
+ cnt_editor = e_html_editor_get_content_editor (editor);
table = e_msg_composer_get_header_table (composer);
/* Disable signature */
@@ -4901,8 +4736,8 @@ e_msg_composer_set_body (EMsgComposer *composer,
content = _("The composer contains a non-text message body, which cannot be edited.");
set_editor_text (composer, content, TRUE, FALSE);
- e_html_editor_view_set_html_mode (view, FALSE);
- webkit_web_view_set_editable (WEBKIT_WEB_VIEW (view), FALSE);
+ e_content_editor_set_html_mode (cnt_editor, FALSE);
+ e_content_editor_set_editable (cnt_editor, FALSE);
g_free (priv->mime_body);
priv->mime_body = g_strdup (body);
@@ -5202,12 +5037,12 @@ e_msg_composer_get_message (EMsgComposer *composer,
GtkAction *action;
ComposerFlags flags = 0;
EHTMLEditor *editor;
- EHTMLEditorView *view;
+ EContentEditor *cnt_editor;
g_return_if_fail (E_IS_MSG_COMPOSER (composer));
editor = e_msg_composer_get_editor (composer);
- view = e_html_editor_get_view (editor);
+ cnt_editor = e_html_editor_get_content_editor (editor);
simple = g_simple_async_result_new (
G_OBJECT (composer), callback,
@@ -5215,7 +5050,7 @@ e_msg_composer_get_message (EMsgComposer *composer,
g_simple_async_result_set_check_cancellable (simple, cancellable);
- if (e_html_editor_view_get_html_mode (view))
+ if (e_content_editor_get_html_mode (cnt_editor))
flags |= COMPOSER_FLAG_HTML_CONTENT;
action = ACTION (PRIORITIZE_MESSAGE);
@@ -5333,7 +5168,7 @@ e_msg_composer_get_message_draft (EMsgComposer *composer,
gpointer user_data)
{
EHTMLEditor *editor;
- EHTMLEditorView *view;
+ EContentEditor *cnt_editor;
GSimpleAsyncResult *simple;
ComposerFlags flags = COMPOSER_FLAG_SAVE_DRAFT;
GtkAction *action;
@@ -5347,9 +5182,9 @@ e_msg_composer_get_message_draft (EMsgComposer *composer,
g_simple_async_result_set_check_cancellable (simple, cancellable);
editor = e_msg_composer_get_editor (composer);
- view = e_html_editor_get_view (editor);
+ cnt_editor = e_html_editor_get_content_editor (editor);
/* We need to remember composer mode */
- if (e_html_editor_view_get_html_mode (view))
+ if (e_content_editor_get_html_mode (cnt_editor))
flags |= COMPOSER_FLAG_HTML_MODE;
/* We want to save HTML content everytime when we save as draft */
flags |= COMPOSER_FLAG_SAVE_DRAFT;
@@ -5482,44 +5317,22 @@ GByteArray *
e_msg_composer_get_raw_message_text_without_signature (EMsgComposer *composer)
{
EHTMLEditor *editor;
- EHTMLEditorView *view;
- GByteArray *array;
- gint ii, length;
- WebKitDOMDocument *document;
- WebKitDOMNodeList *list;
+ EContentEditor *cnt_editor;
+ gchar *content;
g_return_val_if_fail (E_IS_MSG_COMPOSER (composer), NULL);
editor = e_msg_composer_get_editor (composer);
- view = e_html_editor_get_view (editor);
- document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (view));
- array = g_byte_array_new ();
+ cnt_editor = e_html_editor_get_content_editor (editor);
- list = webkit_dom_document_query_selector_all (
- document, "body > *:not(.-x-evo-signature-wrapper)", NULL);
- length = webkit_dom_node_list_get_length (list);
- for (ii = 0; ii < length; ii++) {
- WebKitDOMNode *node = webkit_dom_node_list_item (list, ii);
-
- if (!WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (node)) {
- gchar *text;
-
- text = webkit_dom_html_element_get_inner_text (WEBKIT_DOM_HTML_ELEMENT (node));
- g_byte_array_append (array, (guint8 *) text, strlen (text));
- g_free (text);
+ content = e_content_editor_get_content (
+ cnt_editor,
+ E_CONTENT_EDITOR_GET_BODY |
+ E_CONTENT_EDITOR_GET_TEXT_PLAIN |
+ E_CONTENT_EDITOR_GET_EXCLUDE_SIGNATURE,
+ NULL, NULL);
- if (WEBKIT_DOM_IS_HTML_DIV_ELEMENT (node))
- g_byte_array_append (array, (const guint8 *) "\n", 1);
- else
- g_byte_array_append (array, (const guint8 *) " ", 1);
- }
-
- g_object_unref (node);
- }
-
- g_object_unref (list);
-
- return array;
+ return g_byte_array_new_take ((guint8 *) content, strlen (content));
}
/**
@@ -5531,25 +5344,21 @@ GByteArray *
e_msg_composer_get_raw_message_text (EMsgComposer *composer)
{
EHTMLEditor *editor;
- EHTMLEditorView *view;
- GByteArray *array;
- gchar *text;
- WebKitDOMDocument *document;
- WebKitDOMHTMLElement *body;
+ EContentEditor *cnt_editor;
+ gchar *content;
g_return_val_if_fail (E_IS_MSG_COMPOSER (composer), NULL);
editor = e_msg_composer_get_editor (composer);
- view = e_html_editor_get_view (editor);
- document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (view));
- body = webkit_dom_document_get_body (document);
+ cnt_editor = e_html_editor_get_content_editor (editor);
- array = g_byte_array_new ();
- text = webkit_dom_html_element_get_inner_text (body);
- g_byte_array_append (array, (guint8 *) text, strlen (text));
- g_free (text);
+ content = e_content_editor_get_content (
+ cnt_editor,
+ E_CONTENT_EDITOR_GET_BODY |
+ E_CONTENT_EDITOR_GET_TEXT_PLAIN,
+ NULL, NULL);
- return array;
+ return g_byte_array_new_take ((guint8 *) content, strlen (content));
}
gboolean
@@ -5580,7 +5389,7 @@ e_msg_composer_can_close (EMsgComposer *composer,
{
gboolean res = FALSE;
EHTMLEditor *editor;
- EHTMLEditorView *view;
+ EContentEditor *cnt_editor;
EComposerHeaderTable *table;
GdkWindow *window;
GtkWidget *widget;
@@ -5589,14 +5398,14 @@ e_msg_composer_can_close (EMsgComposer *composer,
widget = GTK_WIDGET (composer);
editor = e_msg_composer_get_editor (composer);
- view = e_html_editor_get_view (editor);
+ cnt_editor = e_html_editor_get_content_editor (editor);
/* this means that there is an async operation running,
* in which case the composer cannot be closed */
if (!gtk_action_group_get_sensitive (composer->priv->async_actions))
return FALSE;
- if (!e_html_editor_view_get_changed (view))
+ if (!e_content_editor_get_changed (cnt_editor))
return TRUE;
window = gtk_widget_get_window (widget);
@@ -5657,6 +5466,7 @@ e_save_spell_languages (const GList *spell_dicts)
/* Build a list of spell check language codes. */
lang_array = g_ptr_array_new ();
+
while (spell_dicts != NULL) {
ESpellDictionary *dict = spell_dicts->data;
const gchar *language_code;
@@ -5689,14 +5499,8 @@ e_msg_composer_save_focused_widget (EMsgComposer *composer)
widget = gtk_window_get_focus (GTK_WINDOW (composer));
composer->priv->focused_entry = widget;
- if (E_IS_HTML_EDITOR_VIEW (widget)) {
- EHTMLEditorSelection *selection;
-
- selection = e_html_editor_view_get_selection (
- E_HTML_EDITOR_VIEW (widget));
-
- e_html_editor_selection_save (selection);
- }
+ if (E_IS_CONTENT_EDITOR (widget))
+ e_content_editor_selection_save (E_CONTENT_EDITOR (widget));
if (GTK_IS_EDITABLE (widget)) {
gtk_editable_get_selection_bounds (
@@ -5725,15 +5529,11 @@ e_msg_composer_restore_focus_on_composer (EMsgComposer *composer)
composer->priv->focused_entry_selection_end);
}
- if (E_IS_HTML_EDITOR_VIEW (widget)) {
- EHTMLEditorSelection *selection;
-
- e_html_editor_view_force_spell_check_in_viewport (E_HTML_EDITOR_VIEW (widget));
-
- selection = e_html_editor_view_get_selection (
- E_HTML_EDITOR_VIEW (widget));
-
- e_html_editor_selection_restore (selection);
+ if (E_IS_CONTENT_EDITOR (widget)) {
+ EContentEditor *cnt_editor = E_CONTENT_EDITOR (widget);
+ /* FIXME WK2
+ e_html_editor_view_force_spell_check (view);*/
+ e_content_editor_selection_restore (cnt_editor);
}
composer->priv->focused_entry = NULL;
diff --git a/composer/e-msg-composer.h b/composer/e-msg-composer.h
index daaca2b..c0986a5 100644
--- a/composer/e-msg-composer.h
+++ b/composer/e-msg-composer.h
@@ -81,15 +81,20 @@ struct _EMsgComposerClass {
};
GType e_msg_composer_get_type (void);
-EMsgComposer * e_msg_composer_new (EShell *shell);
-EMsgComposer * e_msg_composer_new_with_message (EShell *shell,
+void e_msg_composer_new (EShell *shell,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+EMsgComposer * e_msg_composer_new_finish (GAsyncResult *result,
+ GError **error);
+void e_msg_composer_setup_with_message
+ (EMsgComposer *composer,
CamelMimeMessage *message,
gboolean keep_signature,
const gchar *override_identity_uid,
GCancellable *cancellable);
-EMsgComposer * e_msg_composer_new_from_url (EShell *shell,
+void e_msg_composer_setup_from_url (EMsgComposer *composer,
const gchar *url);
-EMsgComposer * e_msg_composer_new_redirect (EShell *shell,
+void e_msg_composer_setup_redirect (EMsgComposer *composer,
CamelMimeMessage *message,
const gchar *identity_uid,
GCancellable *cancellable);
diff --git a/configure.ac b/configure.ac
index ab0ab28..5439429 100644
--- a/configure.ac
+++ b/configure.ac
@@ -50,7 +50,7 @@ m4_define([gcr_minimum_version], [3.4])
m4_define([enchant_minimum_version], [1.1.7])
m4_define([gnome_desktop_minimum_version], [2.91.3])
m4_define([gsettings_desktop_schemas_minimum_version], [2.91.92])
-m4_define([webkitgtk_minimum_version], [2.2.0])
+m4_define([webkit2gtk_minimum_version], [2.13.0])
m4_define([libxml_minimum_version], [2.7.3])
m4_define([shared_mime_info_minimum_version], [0.22])
m4_define([libpst_minimum_version], [0.6.54])
@@ -287,7 +287,7 @@ PKG_CHECK_MODULES([GNOME_PLATFORM],
libxml-2.0 >= libxml_minimum_version
shared-mime-info >= shared_mime_info_minimum_version
gsettings-desktop-schemas >= gsettings_desktop_schemas_minimum_version
- webkitgtk-3.0 >= webkitgtk_minimum_version
+ webkit2gtk-4.0 >= webkitgtk_minimum_version
$GIO_UNIX_REQUIREMENT])
GNOME_DESKTOP_DEPENDENCY=""
@@ -1269,6 +1269,18 @@ AC_SUBST(viewsdir)
dnl For evolution-alarm-notify.desktop
AS_AC_EXPAND(PRIVLIBEXECDIR, "$privlibexecdir")
+dnl **********************************
+dnl WebKit2 Web Extensions
+dnl **********************************
+webextensionsdir="$privlibdir/web-extensions"
+webextensionswebkiteditordir="$privlibdir/web-extensions/webkit-editor"
+AC_SUBST(webextensionsdir)
+AC_SUBST(webextensionswebkiteditordir)
+
+PKG_CHECK_MODULES(WEB_EXTENSION, [webkit2gtk-4.0 >= webkit2gtk_minimum_version])
+AC_SUBST(WEB_EXTENSIONS_CFLAGS)
+AC_SUBST(WEB_EXTENSIONS_LIBS)
+
dnl ************************
dnl Plugins
dnl ************************
@@ -1592,6 +1604,7 @@ modules/composer-autosave/Makefile
modules/contact-photos/Makefile
modules/gravatar/Makefile
modules/itip-formatter/Makefile
+modules/itip-formatter/web-extension/Makefile
modules/mail-config/Makefile
modules/mail/Makefile
modules/mailto-handler/Makefile
@@ -1607,7 +1620,9 @@ modules/startup-wizard/Makefile
modules/text-highlight/Makefile
modules/tnef-attachment/Makefile
modules/vcard-inline/Makefile
-modules/web-inspector/Makefile
+modules/webkit-editor/Makefile
+modules/webkit-editor/web-extension/Makefile
+modules/webkit-inspector/Makefile
plugins/Makefile
plugins/attachment-reminder/Makefile
plugins/bbdb/Makefile
@@ -1622,6 +1637,7 @@ plugins/pst-import/Makefile
plugins/publish-calendar/Makefile
plugins/save-calendar/Makefile
plugins/templates/Makefile
+web-extensions/Makefile
smime/Makefile
smime/lib/Makefile
smime/gui/Makefile
diff --git a/data/org.gnome.evolution.mail.gschema.xml.in b/data/org.gnome.evolution.mail.gschema.xml.in
index 4c91054..3eca005 100644
--- a/data/org.gnome.evolution.mail.gschema.xml.in
+++ b/data/org.gnome.evolution.mail.gschema.xml.in
@@ -40,6 +40,11 @@
<_summary>Default charset in which to compose messages</_summary>
<_description>Default charset in which to compose messages. Uses UTF-8, if not set.</_description>
</key>
+ <key name="composer-editor" type="s">
+ <default>''</default>
+ <_summary>Name of the editor to prefer in the message composer</_summary>
+ <_description>If the name doesn't correspond to any known editor, then the built-in WebKit editor is
used.</_description>
+ </key>
<key name="composer-gallery-path" type="s">
<default>''</default>
<_summary>Path where picture gallery should search for its content</_summary>
@@ -175,11 +180,6 @@
<_summary>List of localized 'Re'</_summary>
<_description>Comma-separated list of localized 'Re' abbreviations to skip in a subject text when
replying to a message, as an addition to the standard "Re" prefix. An example is 'SV,AV'.</_description>
</key>
- <key name="composer-developer-mode" type="b">
- <default>false</default>
- <_summary>Enable developer mode</_summary>
- <_description>Enables some hidden actions and tools aimed for development and debugging.</_description>
- </key>
<key name="composer-word-wrap-length" type="i">
<default>71</default>
<_summary>Number of characters for wrapping</_summary>
@@ -299,6 +299,11 @@
<_summary>Timeout for marking messages as seen</_summary>
<_description>Timeout in milliseconds for marking messages as seen.</_description>
</key>
+ <key name="show-attachment-bar" type="b">
+ <default>true</default>
+ <_summary>Show Attachment Bar</_summary>
+ <_description>Show Attachment Bar below the message preview pane when the message has
attachments.</_description>
+ </key>
<key name="show-email" type="b">
<default>false</default>
<_summary>Sender email-address column in the message list</_summary>
diff --git a/doc/reference/evolution-util/Makefile.am b/doc/reference/evolution-util/Makefile.am
index 2d1b169..db6074e 100644
--- a/doc/reference/evolution-util/Makefile.am
+++ b/doc/reference/evolution-util/Makefile.am
@@ -18,7 +18,6 @@ CFILE_GLOB = $(top_srcdir)/e-util/*.c
IGNORE_HFILES = \
e-html-editor-actions.h \
e-html-editor-private.h \
- e-html-editor-utils.h \
e-marshal.h \
e-table-col-dnd.h \
e-table-defines.h \
diff --git a/e-util/Makefile.am b/e-util/Makefile.am
index 46a6bea..4c9db7b 100644
--- a/e-util/Makefile.am
+++ b/e-util/Makefile.am
@@ -62,6 +62,7 @@ noinst_PROGRAMS = \
test-contact-store \
test-dateedit \
test-html-editor \
+ test-html-editor-units \
test-mail-signatures \
test-name-selector \
test-preferences-window \
@@ -97,6 +98,7 @@ libevolution_util_la_CPPFLAGS = \
-DEVOLUTION_TOOLSDIR=\""$(privlibexecdir)"\" \
-DEVOLUTION_UIDIR=\""$(uidir)"\" \
-DEVOLUTION_RULEDIR=\"$(ruledir)\" \
+ -DEVOLUTION_WEB_EXTENSIONS_DIR=\""$(webextensionsdir)"\" \
-DG_LOG_DOMAIN=\"evolution-util\" \
$(EVOLUTION_DATA_SERVER_CFLAGS) \
$(GNOME_PLATFORM_CFLAGS) \
@@ -119,7 +121,6 @@ evolution_util_include_HEADERS = \
e-alert-sink.h \
e-alert.h \
e-attachment-bar.h \
- e-attachment-button.h \
e-attachment-dialog.h \
e-attachment-handler-image.h \
e-attachment-handler.h \
@@ -173,6 +174,8 @@ evolution_util_include_HEADERS = \
e-config.h \
e-conflict-search-selector.h \
e-contact-store.h \
+ e-content-editor.h \
+ e-content-request.h \
e-data-capture.h \
e-dateedit.h \
e-datetime-format.h \
@@ -208,12 +211,9 @@ evolution_util_include_HEADERS = \
e-html-editor-page-dialog.h \
e-html-editor-paragraph-dialog.h \
e-html-editor-replace-dialog.h \
- e-html-editor-selection.h \
e-html-editor-spell-check-dialog.h \
e-html-editor-table-dialog.h \
e-html-editor-text-dialog.h \
- e-html-editor-utils.h \
- e-html-editor-view.h \
e-html-editor.h \
e-html-utils.h \
e-icon-factory.h \
@@ -272,6 +272,7 @@ evolution_util_include_HEADERS = \
e-selection-model.h \
e-selection.h \
e-send-options.h \
+ e-simple-async-result.h \
e-sorter-array.h \
e-sorter.h \
e-source-combo-box.h \
@@ -394,7 +395,6 @@ libevolution_util_la_SOURCES = \
e-alert-sink.c \
e-alert.c \
e-attachment-bar.c \
- e-attachment-button.c \
e-attachment-dialog.c \
e-attachment-handler-image.c \
e-attachment-handler.c \
@@ -448,6 +448,8 @@ libevolution_util_la_SOURCES = \
e-config.c \
e-conflict-search-selector.c \
e-contact-store.c \
+ e-content-editor.c \
+ e-content-request.c \
e-data-capture.c \
e-dateedit.c \
e-datetime-format.c \
@@ -484,12 +486,9 @@ libevolution_util_la_SOURCES = \
e-html-editor-paragraph-dialog.c \
e-html-editor-private.h \
e-html-editor-replace-dialog.c \
- e-html-editor-selection.c \
e-html-editor-spell-check-dialog.c \
e-html-editor-table-dialog.c \
e-html-editor-text-dialog.c \
- e-html-editor-utils.c \
- e-html-editor-view.c \
e-html-editor.c \
e-html-utils.c \
e-icon-factory.c \
@@ -548,6 +547,7 @@ libevolution_util_la_SOURCES = \
e-selection-model.c \
e-selection.c \
e-send-options.c \
+ e-simple-async-result.c \
e-sorter-array.c \
e-sorter.c \
e-source-combo-box.c \
@@ -694,6 +694,14 @@ test_html_editor_CPPFLAGS = $(TEST_CPPFLAGS)
test_html_editor_SOURCES = test-html-editor.c
test_html_editor_LDADD = $(TEST_LDADD)
+test_html_editor_units_CPPFLAGS = $(TEST_CPPFLAGS) -DTEST_TOP_SRCDIR=\""$(top_srcdir)"\"
+test_html_editor_units_SOURCES = \
+ test-html-editor-units-utils.h \
+ test-html-editor-units-utils.c \
+ test-html-editor-units.c \
+ $(NULL)
+test_html_editor_units_LDADD = $(TEST_LDADD)
+
test_mail_signatures_CPPFLAGS = $(TEST_CPPFLAGS)
test_mail_signatures_SOURCES = test-mail-signatures.c
test_mail_signatures_LDADD = $(TEST_LDADD)
diff --git a/e-util/e-attachment-bar.c b/e-util/e-attachment-bar.c
index 3916d00..e5da99f 100644
--- a/e-util/e-attachment-bar.c
+++ b/e-util/e-attachment-bar.c
@@ -50,6 +50,8 @@ struct _EAttachmentBarPrivate {
GtkWidget *status_label;
GtkWidget *save_all_button;
GtkWidget *save_one_button;
+ GtkWidget *icon_scrolled_window; /* not referenced */
+ GtkWidget *tree_scrolled_window; /* not referenced */
gint active_view;
guint expanded : 1;
@@ -119,6 +121,43 @@ attachment_bar_update_status (EAttachmentBar *bar)
}
static void
+attachment_bar_notify_vadjustment_upper_cb (GObject *object,
+ GParamSpec *param,
+ gpointer user_data)
+{
+ EAttachmentBar *bar = user_data;
+ GtkAdjustment *adjustment;
+ gint max_upper, max_content_height = -2;
+ gint request_height = -1;
+
+ g_return_if_fail (E_IS_ATTACHMENT_BAR (bar));
+
+ adjustment = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW
(bar->priv->icon_scrolled_window));
+ max_upper = gtk_adjustment_get_upper (adjustment);
+
+ adjustment = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW
(bar->priv->tree_scrolled_window));
+ max_upper = MAX (max_upper, gtk_adjustment_get_upper (adjustment));
+
+ gtk_widget_style_get (GTK_WIDGET (bar), "max-content-height", &max_content_height, NULL);
+
+ if ((max_content_height >= 0 && max_content_height < 50) || max_content_height <= -2)
+ max_content_height = 50;
+
+ if (max_content_height == -1) {
+ request_height = max_upper;
+ } else if (max_content_height < max_upper) {
+ request_height = max_content_height;
+ } else {
+ request_height = max_upper;
+ }
+
+ gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (bar->priv->icon_scrolled_window),
+ request_height);
+ gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (bar->priv->tree_scrolled_window),
+ request_height);
+}
+
+static void
attachment_bar_set_store (EAttachmentBar *bar,
EAttachmentStore *store)
{
@@ -534,6 +573,10 @@ e_attachment_bar_class_init (EAttachmentBarClass *class)
widget_class->button_release_event = attachment_bar_button_release_event;
widget_class->motion_notify_event = attachment_bar_motion_notify_event;
+ #if GTK_CHECK_VERSION (3, 20, 0)
+ gtk_widget_class_set_css_name (widget_class, G_OBJECT_CLASS_NAME (class));
+ #endif
+
g_object_class_install_property (
object_class,
PROP_ACTIVE_VIEW,
@@ -574,6 +617,15 @@ e_attachment_bar_class_init (EAttachmentBarClass *class)
g_object_class_override_property (
object_class, PROP_EDITABLE, "editable");
+
+ gtk_widget_class_install_style_property (
+ widget_class,
+ g_param_spec_int (
+ "max-content-height",
+ "Max Content Height",
+ NULL,
+ -1, G_MAXINT, 150,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
}
static void
@@ -599,6 +651,7 @@ e_attachment_bar_init (EAttachmentBar *bar)
GtkWidget *container;
GtkWidget *widget;
GtkAction *action;
+ GtkAdjustment *adjustment;
bar->priv = E_ATTACHMENT_BAR_GET_PRIVATE (bar);
@@ -627,10 +680,16 @@ e_attachment_bar_init (EAttachmentBar *bar)
container = widget;
+ widget = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (widget), GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
+ gtk_container_add (GTK_CONTAINER (container), widget);
+ bar->priv->icon_scrolled_window = widget;
+ gtk_widget_show (widget);
+
widget = e_attachment_icon_view_new ();
gtk_widget_set_can_focus (widget, TRUE);
gtk_icon_view_set_model (GTK_ICON_VIEW (widget), bar->priv->model);
- gtk_container_add (GTK_CONTAINER (container), widget);
+ gtk_container_add (GTK_CONTAINER (bar->priv->icon_scrolled_window), widget);
bar->priv->icon_view = g_object_ref (widget);
gtk_widget_show (widget);
@@ -644,10 +703,16 @@ e_attachment_bar_init (EAttachmentBar *bar)
container = widget;
+ widget = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (widget), GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
+ gtk_container_add (GTK_CONTAINER (container), widget);
+ bar->priv->tree_scrolled_window = widget;
+ gtk_widget_show (widget);
+
widget = e_attachment_tree_view_new ();
gtk_widget_set_can_focus (widget, TRUE);
gtk_tree_view_set_model (GTK_TREE_VIEW (widget), bar->priv->model);
- gtk_container_add (GTK_CONTAINER (container), widget);
+ gtk_container_add (GTK_CONTAINER (bar->priv->tree_scrolled_window), widget);
bar->priv->tree_view = g_object_ref (widget);
gtk_widget_show (widget);
@@ -727,6 +792,14 @@ e_attachment_bar_init (EAttachmentBar *bar)
gtk_widget_show (widget);
g_object_unref (size_group);
+
+ adjustment = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW
(bar->priv->icon_scrolled_window));
+ e_signal_connect_notify (adjustment, "notify::upper",
+ G_CALLBACK (attachment_bar_notify_vadjustment_upper_cb), bar);
+
+ adjustment = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW
(bar->priv->tree_scrolled_window));
+ e_signal_connect_notify (adjustment, "notify::upper",
+ G_CALLBACK (attachment_bar_notify_vadjustment_upper_cb), bar);
}
GtkWidget *
diff --git a/e-util/e-attachment-store.c b/e-util/e-attachment-store.c
index f0648db..85fa19a 100644
--- a/e-util/e-attachment-store.c
+++ b/e-util/e-attachment-store.c
@@ -53,12 +53,157 @@ enum {
PROP_TOTAL_SIZE
};
+enum {
+ ATTACHMENT_ADDED,
+ ATTACHMENT_REMOVED,
+ LAST_SIGNAL
+};
+
+static gulong signals[LAST_SIGNAL];
+
G_DEFINE_TYPE (
EAttachmentStore,
e_attachment_store,
GTK_TYPE_LIST_STORE)
static void
+attachment_store_update_file_info_cb (EAttachment *attachment,
+ const gchar *caption,
+ const gchar *content_type,
+ const gchar *description,
+ gint64 size,
+ gpointer user_data)
+{
+ EAttachmentStore *store = user_data;
+ GtkTreeIter iter;
+
+ g_return_if_fail (E_IS_ATTACHMENT (attachment));
+ g_return_if_fail (E_IS_ATTACHMENT_STORE (store));
+
+ if (e_attachment_store_find_attachment_iter (store, attachment, &iter)) {
+ gtk_list_store_set (
+ GTK_LIST_STORE (store), &iter,
+ E_ATTACHMENT_STORE_COLUMN_CAPTION, caption,
+ E_ATTACHMENT_STORE_COLUMN_CONTENT_TYPE, content_type,
+ E_ATTACHMENT_STORE_COLUMN_DESCRIPTION, description,
+ E_ATTACHMENT_STORE_COLUMN_SIZE, size,
+ -1);
+ }
+}
+
+static void
+attachment_store_update_icon_cb (EAttachment *attachment,
+ GIcon *icon,
+ gpointer user_data)
+{
+ EAttachmentStore *store = user_data;
+ GtkTreeIter iter;
+
+ g_return_if_fail (E_IS_ATTACHMENT (attachment));
+ g_return_if_fail (E_IS_ATTACHMENT_STORE (store));
+
+ if (e_attachment_store_find_attachment_iter (store, attachment, &iter)) {
+ gtk_list_store_set (
+ GTK_LIST_STORE (store), &iter,
+ E_ATTACHMENT_STORE_COLUMN_ICON, icon,
+ -1);
+ }
+}
+
+static void
+attachment_store_update_progress_cb (EAttachment *attachment,
+ gboolean loading,
+ gboolean saving,
+ gint percent,
+ gpointer user_data)
+{
+ EAttachmentStore *store = user_data;
+ GtkTreeIter iter;
+
+ g_return_if_fail (E_IS_ATTACHMENT (attachment));
+ g_return_if_fail (E_IS_ATTACHMENT_STORE (store));
+
+ if (e_attachment_store_find_attachment_iter (store, attachment, &iter)) {
+ gtk_list_store_set (
+ GTK_LIST_STORE (store), &iter,
+ E_ATTACHMENT_STORE_COLUMN_LOADING, loading,
+ E_ATTACHMENT_STORE_COLUMN_SAVING, saving,
+ E_ATTACHMENT_STORE_COLUMN_PERCENT, percent,
+ -1);
+ }
+}
+
+static void
+attachment_store_load_failed_cb (EAttachment *attachment,
+ gpointer user_data)
+{
+ EAttachmentStore *store = user_data;
+
+ g_return_if_fail (E_IS_ATTACHMENT (attachment));
+ g_return_if_fail (E_IS_ATTACHMENT_STORE (store));
+
+ e_attachment_store_remove_attachment (store, attachment);
+}
+
+static void
+attachment_store_attachment_notify_cb (GObject *attachment,
+ GParamSpec *param,
+ gpointer user_data)
+{
+ EAttachmentStore *store = user_data;
+
+ g_return_if_fail (E_IS_ATTACHMENT (attachment));
+ g_return_if_fail (param != NULL);
+ g_return_if_fail (E_IS_ATTACHMENT_STORE (store));
+
+ if (g_str_equal (param->name, "loading")) {
+ g_object_notify (G_OBJECT (store), "num-loading");
+ } else if (g_str_equal (param->name, "file-info")) {
+ g_object_notify (G_OBJECT (store), "total-size");
+ }
+}
+
+static void
+attachment_store_attachment_added (EAttachmentStore *store,
+ EAttachment *attachment)
+{
+ g_return_if_fail (E_IS_ATTACHMENT_STORE (store));
+ g_return_if_fail (E_IS_ATTACHMENT (attachment));
+
+ g_signal_connect (attachment, "update-file-info",
+ G_CALLBACK (attachment_store_update_file_info_cb), store);
+ g_signal_connect (attachment, "update-icon",
+ G_CALLBACK (attachment_store_update_icon_cb), store);
+ g_signal_connect (attachment, "update-progress",
+ G_CALLBACK (attachment_store_update_progress_cb), store);
+ g_signal_connect (attachment, "load-failed",
+ G_CALLBACK (attachment_store_load_failed_cb), store);
+ g_signal_connect (attachment, "notify",
+ G_CALLBACK (attachment_store_attachment_notify_cb), store);
+
+ e_attachment_update_store_columns (attachment);
+}
+
+static void
+attachment_store_attachment_removed (EAttachmentStore *store,
+ EAttachment *attachment)
+{
+ g_return_if_fail (E_IS_ATTACHMENT_STORE (store));
+ g_return_if_fail (E_IS_ATTACHMENT (attachment));
+
+ g_signal_handlers_disconnect_by_func (attachment,
+ G_CALLBACK (attachment_store_update_file_info_cb), store);
+ g_signal_handlers_disconnect_by_func (attachment,
+ G_CALLBACK (attachment_store_update_icon_cb), store);
+ g_signal_handlers_disconnect_by_func (attachment,
+ G_CALLBACK (attachment_store_update_progress_cb), store);
+ g_signal_handlers_disconnect_by_func (attachment,
+ G_CALLBACK (attachment_store_load_failed_cb), store);
+ g_signal_handlers_disconnect_by_func (attachment,
+ G_CALLBACK (attachment_store_attachment_notify_cb), store);
+}
+
+static void
attachment_store_get_property (GObject *object,
guint property_id,
GValue *value,
@@ -124,6 +269,9 @@ e_attachment_store_class_init (EAttachmentStoreClass *class)
object_class->dispose = attachment_store_dispose;
object_class->finalize = attachment_store_finalize;
+ class->attachment_added = attachment_store_attachment_added;
+ class->attachment_removed = attachment_store_attachment_removed;
+
g_object_class_install_property (
object_class,
PROP_NUM_ATTACHMENTS,
@@ -159,6 +307,22 @@ e_attachment_store_class_init (EAttachmentStoreClass *class)
G_MAXUINT64,
0,
G_PARAM_READABLE));
+
+ signals[ATTACHMENT_ADDED] = g_signal_new (
+ "attachment-added",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EAttachmentStoreClass, attachment_added),
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 1, E_TYPE_ATTACHMENT);
+
+ signals[ATTACHMENT_REMOVED] = g_signal_new (
+ "attachment-removed",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EAttachmentStoreClass, attachment_removed),
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 1, E_TYPE_ATTACHMENT);
}
static void
@@ -225,13 +389,12 @@ e_attachment_store_add_attachment (EAttachmentStore *store,
store->priv->attachment_index,
g_object_ref (attachment), reference);
- /* This lets the attachment tell us when to update. */
- e_attachment_set_reference (attachment, reference);
-
g_object_freeze_notify (G_OBJECT (store));
g_object_notify (G_OBJECT (store), "num-attachments");
g_object_notify (G_OBJECT (store), "total-size");
g_object_thaw_notify (G_OBJECT (store));
+
+ g_signal_emit (store, signals[ATTACHMENT_ADDED], 0, attachment);
}
gboolean
@@ -243,6 +406,7 @@ e_attachment_store_remove_attachment (EAttachmentStore *store,
GtkTreeModel *model;
GtkTreePath *path;
GtkTreeIter iter;
+ gboolean removed;
g_return_val_if_fail (E_IS_ATTACHMENT_STORE (store), FALSE);
g_return_val_if_fail (E_IS_ATTACHMENT (attachment), FALSE);
@@ -254,12 +418,12 @@ e_attachment_store_remove_attachment (EAttachmentStore *store,
return FALSE;
if (!gtk_tree_row_reference_valid (reference)) {
- g_hash_table_remove (hash_table, attachment);
+ if (g_hash_table_remove (hash_table, attachment))
+ g_signal_emit (store, signals[ATTACHMENT_REMOVED], 0, attachment);
return FALSE;
}
e_attachment_cancel (attachment);
- e_attachment_set_reference (attachment, NULL);
model = gtk_tree_row_reference_get_model (reference);
path = gtk_tree_row_reference_get_path (reference);
@@ -267,13 +431,16 @@ e_attachment_store_remove_attachment (EAttachmentStore *store,
gtk_tree_path_free (path);
gtk_list_store_remove (GTK_LIST_STORE (store), &iter);
- g_hash_table_remove (hash_table, attachment);
+ removed = g_hash_table_remove (hash_table, attachment);
g_object_freeze_notify (G_OBJECT (store));
g_object_notify (G_OBJECT (store), "num-attachments");
g_object_notify (G_OBJECT (store), "total-size");
g_object_thaw_notify (G_OBJECT (store));
+ if (removed)
+ g_signal_emit (store, signals[ATTACHMENT_REMOVED], 0, attachment);
+
return TRUE;
}
@@ -304,9 +471,10 @@ e_attachment_store_remove_all (EAttachmentStore *store)
EAttachment *attachment = iter->data;
e_attachment_cancel (attachment);
- e_attachment_set_reference (attachment, NULL);
g_warn_if_fail (g_hash_table_remove (store->priv->attachment_index, attachment));
+
+ g_signal_emit (store, signals[ATTACHMENT_REMOVED], 0, attachment);
}
g_list_foreach (list, (GFunc) g_object_unref, NULL);
@@ -780,6 +948,51 @@ e_attachment_store_run_save_dialog (EAttachmentStore *store,
return destination;
}
+gboolean
+e_attachment_store_transform_num_attachments_to_visible_boolean (GBinding *binding,
+ const GValue *from_value,
+ GValue *to_value,
+ gpointer user_data)
+{
+ g_return_val_if_fail (from_value != NULL, FALSE);
+ g_return_val_if_fail (to_value != NULL, FALSE);
+ g_return_val_if_fail (G_VALUE_HOLDS_UINT (from_value), FALSE);
+ g_return_val_if_fail (G_VALUE_HOLDS_BOOLEAN (to_value), FALSE);
+
+ g_value_set_boolean (to_value, g_value_get_uint (from_value) != 0);
+
+ return TRUE;
+}
+
+gboolean
+e_attachment_store_find_attachment_iter (EAttachmentStore *store,
+ EAttachment *attachment,
+ GtkTreeIter *out_iter)
+{
+ GtkTreeRowReference *reference;
+ GtkTreeModel *model;
+ GtkTreePath *path;
+ gboolean found;
+
+ g_return_val_if_fail (E_IS_ATTACHMENT_STORE (store), FALSE);
+ g_return_val_if_fail (E_IS_ATTACHMENT (attachment), FALSE);
+ g_return_val_if_fail (out_iter != NULL, FALSE);
+
+ reference = g_hash_table_lookup (store->priv->attachment_index, attachment);
+
+ if (!reference || !gtk_tree_row_reference_valid (reference))
+ return FALSE;
+
+ model = gtk_tree_row_reference_get_model (reference);
+ g_return_val_if_fail (model == GTK_TREE_MODEL (store), FALSE);
+
+ path = gtk_tree_row_reference_get_path (reference);
+ found = gtk_tree_model_get_iter (model, out_iter, path);
+ gtk_tree_path_free (path);
+
+ return found;
+}
+
/******************** e_attachment_store_get_uris_async() ********************/
typedef struct _UriContext UriContext;
diff --git a/e-util/e-attachment-store.h b/e-util/e-attachment-store.h
index 584110c..1f15f5d 100644
--- a/e-util/e-attachment-store.h
+++ b/e-util/e-attachment-store.h
@@ -60,6 +60,12 @@ struct _EAttachmentStore {
struct _EAttachmentStoreClass {
GtkListStoreClass parent_class;
+
+ /* Signals */
+ void (* attachment_added) (EAttachmentStore *store,
+ EAttachment *attachment);
+ void (* attachment_removed) (EAttachmentStore *store,
+ EAttachment *attachment);
};
enum {
@@ -104,6 +110,15 @@ GFile * e_attachment_store_run_save_dialog
GList *attachment_list,
GtkWindow *parent);
+gboolean e_attachment_store_transform_num_attachments_to_visible_boolean
+ (GBinding *binding,
+ const GValue *from_value,
+ GValue *to_value,
+ gpointer user_data);
+gboolean e_attachment_store_find_attachment_iter
+ (EAttachmentStore *store,
+ EAttachment *attachment,
+ GtkTreeIter *out_iter);
/* Asynchronous Operations */
void e_attachment_store_get_uris_async
(EAttachmentStore *store,
diff --git a/e-util/e-attachment-view.c b/e-util/e-attachment-view.c
index 7020ab8..00b17df 100644
--- a/e-util/e-attachment-view.c
+++ b/e-util/e-attachment-view.c
@@ -50,15 +50,7 @@ static const gchar *ui =
" <menuitem action='remove'/>"
" <menuitem action='properties'/>"
" <separator/>"
-" <placeholder name='inline-actions'>"
-" <menuitem action='zoom-to-100'/>"
-" <menuitem action='zoom-to-window'/>"
-" <menuitem action='show'/>"
-" <menuitem action='show-all'/>"
-" <separator/>"
-" <menuitem action='hide'/>"
-" <menuitem action='hide-all'/>"
-" </placeholder>"
+" <placeholder name='inline-actions'/>"
" <separator/>"
" <placeholder name='custom-actions'/>"
" <separator/>"
@@ -108,44 +100,6 @@ action_cancel_cb (GtkAction *action,
}
static void
-action_hide_cb (GtkAction *action,
- EAttachmentView *view)
-{
- EAttachment *attachment;
- GList *list;
-
- list = e_attachment_view_get_selected_attachments (view);
- g_return_if_fail (g_list_length (list) == 1);
- attachment = list->data;
-
- e_attachment_set_shown (attachment, FALSE);
-
- g_list_foreach (list, (GFunc) g_object_unref, NULL);
- g_list_free (list);
-}
-
-static void
-action_hide_all_cb (GtkAction *action,
- EAttachmentView *view)
-{
- EAttachmentStore *store;
- GList *list, *iter;
-
- store = e_attachment_view_get_store (view);
- list = e_attachment_store_get_attachments (store);
-
- for (iter = list; iter != NULL; iter = iter->next) {
- EAttachment *attachment;
-
- attachment = E_ATTACHMENT (iter->data);
- e_attachment_set_shown (attachment, FALSE);
- }
-
- g_list_foreach (list, (GFunc) g_object_unref, NULL);
- g_list_free (list);
-}
-
-static void
action_open_with_cb (GtkAction *action,
EAttachmentView *view)
{
@@ -342,78 +296,6 @@ exit:
g_list_free (list);
}
-static void
-action_show_cb (GtkAction *action,
- EAttachmentView *view)
-{
- EAttachment *attachment;
- GList *list;
-
- list = e_attachment_view_get_selected_attachments (view);
- g_return_if_fail (g_list_length (list) == 1);
- attachment = list->data;
-
- e_attachment_set_shown (attachment, TRUE);
-
- g_list_foreach (list, (GFunc) g_object_unref, NULL);
- g_list_free (list);
-}
-
-static void
-action_show_all_cb (GtkAction *action,
- EAttachmentView *view)
-{
- EAttachmentStore *store;
- GList *list, *iter;
-
- store = e_attachment_view_get_store (view);
- list = e_attachment_store_get_attachments (store);
-
- for (iter = list; iter != NULL; iter = iter->next) {
- EAttachment *attachment;
-
- attachment = E_ATTACHMENT (iter->data);
- e_attachment_set_shown (attachment, TRUE);
- }
-
- g_list_foreach (list, (GFunc) g_object_unref, NULL);
- g_list_free (list);
-}
-
-static void
-action_zoom_to_100_cb (GtkAction *action,
- EAttachmentView *view)
-{
- EAttachment *attachment;
- GList *list;
-
- list = e_attachment_view_get_selected_attachments (view);
- g_return_if_fail (g_list_length (list) == 1);
- attachment = list->data;
-
- e_attachment_set_zoom_to_window (attachment, FALSE);
-
- g_list_foreach (list, (GFunc) g_object_unref, NULL);
- g_list_free (list);
-}
-
-static void
-action_zoom_to_window_cb (GtkAction *action,
- EAttachmentView *view)
-{
- EAttachment *attachment;
- GList *list;
-
- list = e_attachment_view_get_selected_attachments (view);
- g_return_if_fail (g_list_length (list) == 1);
- attachment = list->data;
-
- e_attachment_set_zoom_to_window (attachment, TRUE);
-
- g_list_foreach (list, (GFunc) g_object_unref, NULL);
- g_list_free (list);
-}
-
static GtkActionEntry standard_entries[] = {
{ "cancel",
@@ -478,51 +360,6 @@ static GtkActionEntry editable_entries[] = {
G_CALLBACK (action_remove_cb) }
};
-static GtkActionEntry inline_entries[] = {
-
- { "hide",
- NULL,
- N_("_Hide"),
- NULL,
- NULL, /* XXX Add a tooltip! */
- G_CALLBACK (action_hide_cb) },
-
- { "hide-all",
- NULL,
- N_("Hid_e All"),
- NULL,
- NULL, /* XXX Add a tooltip! */
- G_CALLBACK (action_hide_all_cb) },
-
- { "show",
- NULL,
- N_("_View Inline"),
- NULL,
- NULL, /* XXX Add a tooltip! */
- G_CALLBACK (action_show_cb) },
-
- { "show-all",
- NULL,
- N_("Vie_w All Inline"),
- NULL,
- NULL, /* XXX Add a tooltip! */
- G_CALLBACK (action_show_all_cb) },
-
- { "zoom-to-100",
- NULL,
- N_("_Zoom to 100%"),
- NULL,
- N_("Zoom the image to its natural size"),
- G_CALLBACK (action_zoom_to_100_cb) },
-
- { "zoom-to-window",
- NULL,
- N_("_Zoom to window"),
- NULL,
- N_("Zoom large images to not be wider than the window width"),
- G_CALLBACK (action_zoom_to_window_cb) }
-};
-
static void
call_attachment_load_handle_error (GObject *source_object,
GAsyncResult *result,
@@ -745,76 +582,32 @@ attachment_view_update_actions (EAttachmentView *view)
{
EAttachmentViewPrivate *priv;
EAttachment *attachment;
- EAttachmentStore *store;
GtkActionGroup *action_group;
GtkAction *action;
GList *list, *iter;
- guint n_shown = 0;
- guint n_hidden = 0;
guint n_selected;
gboolean busy = FALSE;
- gboolean can_show = FALSE;
- gboolean shown = FALSE;
- gboolean is_image = FALSE;
- gboolean zoom_to_window = FALSE;
- gboolean visible;
g_return_if_fail (E_IS_ATTACHMENT_VIEW (view));
priv = e_attachment_view_get_private (view);
- store = e_attachment_view_get_store (view);
- list = e_attachment_store_get_attachments (store);
-
- for (iter = list; iter != NULL; iter = iter->next) {
- attachment = iter->data;
-
- if (!e_attachment_get_can_show (attachment))
- continue;
-
- if (e_attachment_get_shown (attachment))
- n_shown++;
- else
- n_hidden++;
- }
-
- g_list_foreach (list, (GFunc) g_object_unref, NULL);
- g_list_free (list);
-
list = e_attachment_view_get_selected_attachments (view);
n_selected = g_list_length (list);
if (n_selected == 1) {
- gchar *mime_type;
-
attachment = g_object_ref (list->data);
- mime_type = e_attachment_dup_mime_type (attachment);
+
busy |= e_attachment_get_loading (attachment);
busy |= e_attachment_get_saving (attachment);
- can_show = e_attachment_get_can_show (attachment);
- shown = e_attachment_get_shown (attachment);
- zoom_to_window = e_attachment_get_zoom_to_window (attachment);
- is_image = can_show && mime_type && g_ascii_strncasecmp (mime_type, "image/", 6) == 0;
-
- g_free (mime_type);
} else
attachment = NULL;
- g_list_foreach (list, (GFunc) g_object_unref, NULL);
- g_list_free (list);
+ g_list_free_full (list, g_object_unref);
action = e_attachment_view_get_action (view, "cancel");
gtk_action_set_visible (action, busy);
- action = e_attachment_view_get_action (view, "hide");
- gtk_action_set_visible (action, can_show && shown);
-
- /* Show this action if there are multiple viewable
- * attachments, and at least one of them is shown. */
- visible = (n_shown + n_hidden > 1) && (n_shown > 0);
- action = e_attachment_view_get_action (view, "hide-all");
- gtk_action_set_visible (action, visible);
-
action = e_attachment_view_get_action (view, "open-with");
gtk_action_set_visible (action, !busy && n_selected == 1);
@@ -827,29 +620,16 @@ attachment_view_update_actions (EAttachmentView *view)
action = e_attachment_view_get_action (view, "save-as");
gtk_action_set_visible (action, !busy && n_selected > 0);
- action = e_attachment_view_get_action (view, "show");
- gtk_action_set_visible (action, can_show && !shown);
-
- action = e_attachment_view_get_action (view, "zoom-to-100");
- gtk_action_set_visible (action, can_show && shown && is_image && zoom_to_window);
-
- action = e_attachment_view_get_action (view, "zoom-to-window");
- gtk_action_set_visible (action, can_show && shown && is_image && !zoom_to_window);
-
- /* Show this action if there are multiple viewable
- * attachments, and at least one of them is hidden. */
- visible = (n_shown + n_hidden > 1) && (n_hidden > 0);
- action = e_attachment_view_get_action (view, "show-all");
- gtk_action_set_visible (action, visible);
-
/* Clear out the "openwith" action group. */
gtk_ui_manager_remove_ui (priv->ui_manager, priv->merge_id);
action_group = e_attachment_view_get_action_group (view, "openwith");
e_action_group_remove_all_actions (action_group);
gtk_ui_manager_ensure_update (priv->ui_manager);
- if (attachment == NULL || busy)
+ if (!attachment || busy) {
+ g_clear_object (&attachment);
return;
+ }
list = e_attachment_list_apps (attachment);
@@ -913,9 +693,8 @@ attachment_view_update_actions (EAttachmentView *view)
g_free (action_tooltip);
}
+ g_list_free_full (list, g_object_unref);
g_object_unref (attachment);
- g_list_foreach (list, (GFunc) g_object_unref, NULL);
- g_list_free (list);
}
static void
@@ -1005,13 +784,6 @@ e_attachment_view_init (EAttachmentView *view)
action_group, editable_entries,
G_N_ELEMENTS (editable_entries), view);
- action_group = e_attachment_view_add_action_group (view, "inline");
-
- gtk_action_group_add_actions (
- action_group, inline_entries,
- G_N_ELEMENTS (inline_entries), view);
- gtk_action_group_set_visible (action_group, FALSE);
-
e_attachment_view_add_action_group (view, "openwith");
/* Because we are loading from a hard-coded string, there is
diff --git a/e-util/e-attachment.c b/e-util/e-attachment.c
index f9f8e9b..d451f18 100644
--- a/e-util/e-attachment.c
+++ b/e-util/e-attachment.c
@@ -35,7 +35,6 @@
#include <libedataserver/libedataserver.h>
-#include "e-attachment-store.h"
#include "e-icon-factory.h"
#include "e-mktemp.h"
#include "e-misc-utils.h"
@@ -77,8 +76,7 @@ struct _EAttachmentPrivate {
guint can_show : 1;
guint loading : 1;
guint saving : 1;
- guint shown : 1;
- guint zoom_to_window : 1;
+ guint initially_shown : 1;
guint save_self : 1;
guint save_extracted : 1;
@@ -86,12 +84,6 @@ struct _EAttachmentPrivate {
CamelCipherValidityEncrypt encrypted;
CamelCipherValiditySign signed_;
- /* This is a reference to our row in an EAttachmentStore,
- * serving as a means of broadcasting "row-changed" signals.
- * If we are removed from the store, we lazily free the
- * reference when it is found to be to be invalid. */
- GtkTreeRowReference *reference;
-
/* These are IDs for idle callbacks,
* protected by the idle_lock mutex. */
GMutex idle_lock;
@@ -111,15 +103,23 @@ enum {
PROP_LOADING,
PROP_MIME_PART,
PROP_PERCENT,
- PROP_REFERENCE,
PROP_SAVE_SELF,
PROP_SAVE_EXTRACTED,
PROP_SAVING,
- PROP_SHOWN,
- PROP_SIGNED,
- PROP_ZOOM_TO_WINDOW
+ PROP_INITIALLY_SHOWN,
+ PROP_SIGNED
+};
+
+enum {
+ LOAD_FAILED,
+ UPDATE_FILE_INFO,
+ UPDATE_ICON,
+ UPDATE_PROGRESS,
+ LAST_SIGNAL
};
+static guint signals[LAST_SIGNAL];
+
G_DEFINE_TYPE (
EAttachment,
e_attachment,
@@ -250,10 +250,6 @@ static gboolean
attachment_update_file_info_columns_idle_cb (gpointer weak_ref)
{
EAttachment *attachment;
- GtkTreeRowReference *reference;
- GtkTreeModel *model;
- GtkTreePath *path;
- GtkTreeIter iter;
GFileInfo *file_info;
const gchar *content_type;
const gchar *display_name;
@@ -271,19 +267,10 @@ attachment_update_file_info_columns_idle_cb (gpointer weak_ref)
attachment->priv->update_file_info_columns_idle_id = 0;
g_mutex_unlock (&attachment->priv->idle_lock);
- reference = e_attachment_get_reference (attachment);
- if (!gtk_tree_row_reference_valid (reference))
- goto exit;
-
file_info = e_attachment_ref_file_info (attachment);
if (file_info == NULL)
goto exit;
- model = gtk_tree_row_reference_get_model (reference);
- path = gtk_tree_row_reference_get_path (reference);
- gtk_tree_model_get_iter (model, &iter, path);
- gtk_tree_path_free (path);
-
content_type = g_file_info_get_content_type (file_info);
display_name = g_file_info_get_display_name (file_info);
size = g_file_info_get_size (file_info);
@@ -298,18 +285,11 @@ attachment_update_file_info_columns_idle_cb (gpointer weak_ref)
}
if (size > 0)
- caption = g_strdup_printf (
- "%s\n(%s)", description, display_size);
+ caption = g_strdup_printf ("%s\n(%s)", description, display_size);
else
caption = g_strdup (description);
- gtk_list_store_set (
- GTK_LIST_STORE (model), &iter,
- E_ATTACHMENT_STORE_COLUMN_CAPTION, caption,
- E_ATTACHMENT_STORE_COLUMN_CONTENT_TYPE, content_desc,
- E_ATTACHMENT_STORE_COLUMN_DESCRIPTION, description,
- E_ATTACHMENT_STORE_COLUMN_SIZE, size,
- -1);
+ g_signal_emit (attachment, signals[UPDATE_FILE_INFO], 0, caption, content_desc, description, (gint64)
size);
g_free (content_desc);
g_free (display_size);
@@ -347,10 +327,6 @@ static gboolean
attachment_update_icon_column_idle_cb (gpointer weak_ref)
{
EAttachment *attachment;
- GtkTreeRowReference *reference;
- GtkTreeModel *model;
- GtkTreePath *path;
- GtkTreeIter iter;
GFileInfo *file_info;
GCancellable *cancellable;
GIcon *icon = NULL;
@@ -365,15 +341,6 @@ attachment_update_icon_column_idle_cb (gpointer weak_ref)
attachment->priv->update_icon_column_idle_id = 0;
g_mutex_unlock (&attachment->priv->idle_lock);
- reference = e_attachment_get_reference (attachment);
- if (!gtk_tree_row_reference_valid (reference))
- goto exit;
-
- model = gtk_tree_row_reference_get_model (reference);
- path = gtk_tree_row_reference_get_path (reference);
- gtk_tree_model_get_iter (model, &iter, path);
- gtk_tree_path_free (path);
-
cancellable = attachment->priv->cancellable;
file_info = e_attachment_ref_file_info (attachment);
@@ -475,10 +442,7 @@ attachment_update_icon_column_idle_cb (gpointer weak_ref)
icon = emblemed_icon;
}
- gtk_list_store_set (
- GTK_LIST_STORE (model), &iter,
- E_ATTACHMENT_STORE_COLUMN_ICON, icon,
- -1);
+ g_signal_emit (attachment, signals[UPDATE_ICON], 0, icon);
/* Cache the icon to reuse for things like drag-n-drop. */
if (attachment->priv->icon != NULL)
@@ -517,10 +481,6 @@ static gboolean
attachment_update_progress_columns_idle_cb (gpointer weak_ref)
{
EAttachment *attachment;
- GtkTreeRowReference *reference;
- GtkTreeModel *model;
- GtkTreePath *path;
- GtkTreeIter iter;
gboolean loading;
gboolean saving;
gint percent;
@@ -533,26 +493,12 @@ attachment_update_progress_columns_idle_cb (gpointer weak_ref)
attachment->priv->update_progress_columns_idle_id = 0;
g_mutex_unlock (&attachment->priv->idle_lock);
- reference = e_attachment_get_reference (attachment);
- if (!gtk_tree_row_reference_valid (reference))
- goto exit;
-
- model = gtk_tree_row_reference_get_model (reference);
- path = gtk_tree_row_reference_get_path (reference);
- gtk_tree_model_get_iter (model, &iter, path);
- gtk_tree_path_free (path);
-
/* Don't show progress bars until we have progress to report. */
percent = e_attachment_get_percent (attachment);
loading = e_attachment_get_loading (attachment) && (percent > 0);
saving = e_attachment_get_saving (attachment) && (percent > 0);
- gtk_list_store_set (
- GTK_LIST_STORE (model), &iter,
- E_ATTACHMENT_STORE_COLUMN_LOADING, loading,
- E_ATTACHMENT_STORE_COLUMN_PERCENT, percent,
- E_ATTACHMENT_STORE_COLUMN_SAVING, saving,
- -1);
+ g_signal_emit (attachment, signals[UPDATE_PROGRESS], 0, loading, saving, percent);
exit:
g_clear_object (&attachment);
@@ -583,10 +529,6 @@ static void
attachment_set_loading (EAttachment *attachment,
gboolean loading)
{
- GtkTreeRowReference *reference;
-
- reference = e_attachment_get_reference (attachment);
-
attachment->priv->percent = 0;
attachment->priv->loading = loading;
attachment->priv->last_percent_notify = 0;
@@ -595,12 +537,6 @@ attachment_set_loading (EAttachment *attachment,
g_object_notify (G_OBJECT (attachment), "percent");
g_object_notify (G_OBJECT (attachment), "loading");
g_object_thaw_notify (G_OBJECT (attachment));
-
- if (gtk_tree_row_reference_valid (reference)) {
- GtkTreeModel *model;
- model = gtk_tree_row_reference_get_model (reference);
- g_object_notify (G_OBJECT (model), "num-loading");
- }
}
static void
@@ -696,8 +632,8 @@ attachment_set_property (GObject *object,
g_value_get_object (value));
return;
- case PROP_SHOWN:
- e_attachment_set_shown (
+ case PROP_INITIALLY_SHOWN:
+ e_attachment_set_initially_shown (
E_ATTACHMENT (object),
g_value_get_boolean (value));
return;
@@ -708,12 +644,6 @@ attachment_set_property (GObject *object,
g_value_get_object (value));
return;
- case PROP_REFERENCE:
- e_attachment_set_reference (
- E_ATTACHMENT (object),
- g_value_get_boxed (value));
- return;
-
case PROP_SIGNED:
e_attachment_set_signed (
E_ATTACHMENT (object),
@@ -731,12 +661,6 @@ attachment_set_property (GObject *object,
E_ATTACHMENT (object),
g_value_get_boolean (value));
return;
-
- case PROP_ZOOM_TO_WINDOW:
- e_attachment_set_zoom_to_window (
- E_ATTACHMENT (object),
- g_value_get_boolean (value));
- return;
}
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -791,10 +715,10 @@ attachment_get_property (GObject *object,
E_ATTACHMENT (object)));
return;
- case PROP_SHOWN:
+ case PROP_INITIALLY_SHOWN:
g_value_set_boolean (
value,
- e_attachment_get_shown (
+ e_attachment_get_initially_shown (
E_ATTACHMENT (object)));
return;
@@ -819,13 +743,6 @@ attachment_get_property (GObject *object,
E_ATTACHMENT (object)));
return;
- case PROP_REFERENCE:
- g_value_set_boxed (
- value,
- e_attachment_get_reference (
- E_ATTACHMENT (object)));
- return;
-
case PROP_SAVE_SELF:
g_value_set_boolean (
value,
@@ -853,13 +770,6 @@ attachment_get_property (GObject *object,
e_attachment_get_signed (
E_ATTACHMENT (object)));
return;
-
- case PROP_ZOOM_TO_WINDOW:
- g_value_set_boolean (
- value,
- e_attachment_get_zoom_to_window (
- E_ATTACHMENT (object)));
- return;
}
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -883,10 +793,6 @@ attachment_dispose (GObject *object)
priv->emblem_timeout_id = 0;
}
- /* This accepts NULL arguments. */
- gtk_tree_row_reference_free (priv->reference);
- priv->reference = NULL;
-
/* Chain up to parent's dispose() method. */
G_OBJECT_CLASS (e_attachment_parent_class)->dispose (object);
}
@@ -1030,16 +936,6 @@ e_attachment_class_init (EAttachmentClass *class)
g_object_class_install_property (
object_class,
- PROP_REFERENCE,
- g_param_spec_boxed (
- "reference",
- "Reference",
- NULL,
- GTK_TYPE_TREE_ROW_REFERENCE,
- G_PARAM_READWRITE));
-
- g_object_class_install_property (
- object_class,
PROP_SAVE_SELF,
g_param_spec_boolean (
"save-self",
@@ -1070,10 +966,10 @@ e_attachment_class_init (EAttachmentClass *class)
g_object_class_install_property (
object_class,
- PROP_SHOWN,
+ PROP_INITIALLY_SHOWN,
g_param_spec_boolean (
- "shown",
- "Shown",
+ "initially-shown",
+ "Initially Shown",
NULL,
FALSE,
G_PARAM_READWRITE |
@@ -1093,16 +989,46 @@ e_attachment_class_init (EAttachmentClass *class)
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
- g_object_class_install_property (
- object_class,
- PROP_ZOOM_TO_WINDOW,
- g_param_spec_boolean (
- "zoom-to-window",
- "Zoom to window",
- NULL,
- TRUE,
- G_PARAM_READWRITE |
- G_PARAM_CONSTRUCT));
+ signals[UPDATE_FILE_INFO] = g_signal_new (
+ "update-file-info",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EAttachmentClass, update_file_info),
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 4,
+ G_TYPE_STRING,
+ G_TYPE_STRING,
+ G_TYPE_STRING,
+ G_TYPE_INT64);
+
+ signals[UPDATE_ICON] = g_signal_new (
+ "update-icon",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EAttachmentClass, update_icon),
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 1,
+ G_TYPE_ICON);
+
+ signals[UPDATE_PROGRESS] = g_signal_new (
+ "update-progress",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EAttachmentClass, update_progress),
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 3,
+ G_TYPE_BOOLEAN,
+ G_TYPE_BOOLEAN,
+ G_TYPE_INT);
+
+ signals[LOAD_FAILED] = g_signal_new (
+ "load-failed",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EAttachmentClass, load_failed),
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 0,
+ G_TYPE_NONE);
}
static void
@@ -1140,18 +1066,6 @@ e_attachment_init (EAttachment *attachment)
attachment, "notify::percent",
G_CALLBACK (attachment_update_progress_columns), NULL);
- g_signal_connect (
- attachment, "notify::reference",
- G_CALLBACK (attachment_update_file_info_columns), NULL);
-
- g_signal_connect (
- attachment, "notify::reference",
- G_CALLBACK (attachment_update_icon_column), NULL);
-
- g_signal_connect (
- attachment, "notify::reference",
- G_CALLBACK (attachment_update_progress_columns), NULL);
-
e_signal_connect_notify (
attachment, "notify::saving",
G_CALLBACK (attachment_update_icon_column), NULL);
@@ -1476,7 +1390,6 @@ void
e_attachment_set_file_info (EAttachment *attachment,
GFileInfo *file_info)
{
- GtkTreeRowReference *reference;
GIcon *icon;
g_return_if_fail (E_IS_ATTACHMENT (attachment));
@@ -1501,14 +1414,6 @@ e_attachment_set_file_info (EAttachment *attachment,
g_mutex_unlock (&attachment->priv->property_lock);
g_object_notify (G_OBJECT (attachment), "file-info");
-
- /* Tell the EAttachmentStore its total size changed. */
- reference = e_attachment_get_reference (attachment);
- if (gtk_tree_row_reference_valid (reference)) {
- GtkTreeModel *model;
- model = gtk_tree_row_reference_get_model (reference);
- g_object_notify (G_OBJECT (model), "total-size");
- }
}
/**
@@ -1616,29 +1521,6 @@ e_attachment_get_percent (EAttachment *attachment)
return attachment->priv->percent;
}
-GtkTreeRowReference *
-e_attachment_get_reference (EAttachment *attachment)
-{
- g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL);
-
- return attachment->priv->reference;
-}
-
-void
-e_attachment_set_reference (EAttachment *attachment,
- GtkTreeRowReference *reference)
-{
- g_return_if_fail (E_IS_ATTACHMENT (attachment));
-
- if (reference != NULL)
- reference = gtk_tree_row_reference_copy (reference);
-
- gtk_tree_row_reference_free (attachment->priv->reference);
- attachment->priv->reference = reference;
-
- g_object_notify (G_OBJECT (attachment), "reference");
-}
-
gboolean
e_attachment_get_saving (EAttachment *attachment)
{
@@ -1648,44 +1530,22 @@ e_attachment_get_saving (EAttachment *attachment)
}
gboolean
-e_attachment_get_shown (EAttachment *attachment)
-{
- g_return_val_if_fail (E_IS_ATTACHMENT (attachment), FALSE);
-
- return attachment->priv->shown;
-}
-
-void
-e_attachment_set_shown (EAttachment *attachment,
- gboolean shown)
-{
- g_return_if_fail (E_IS_ATTACHMENT (attachment));
-
- attachment->priv->shown = shown;
-
- g_object_notify (G_OBJECT (attachment), "shown");
-}
-
-gboolean
-e_attachment_get_zoom_to_window (EAttachment *attachment)
+e_attachment_get_initially_shown (EAttachment *attachment)
{
g_return_val_if_fail (E_IS_ATTACHMENT (attachment), FALSE);
- return attachment->priv->zoom_to_window;
+ return attachment->priv->initially_shown;
}
void
-e_attachment_set_zoom_to_window (EAttachment *attachment,
- gboolean zoom_to_window)
+e_attachment_set_initially_shown (EAttachment *attachment,
+ gboolean initially_shown)
{
g_return_if_fail (E_IS_ATTACHMENT (attachment));
- if ((attachment->priv->zoom_to_window ? 1 : 0) == (zoom_to_window ? 1 : 0))
- return;
-
- attachment->priv->zoom_to_window = zoom_to_window;
+ attachment->priv->initially_shown = initially_shown;
- g_object_notify (G_OBJECT (attachment), "zoom-to-window");
+ g_object_notify (G_OBJECT (attachment), "initially-shown");
}
gboolean
@@ -1868,6 +1728,16 @@ exit:
return app_info_list;
}
+void
+e_attachment_update_store_columns (EAttachment *attachment)
+{
+ g_return_if_fail (E_IS_ATTACHMENT (attachment));
+
+ attachment_update_file_info_columns (attachment);
+ attachment_update_icon_column (attachment);
+ attachment_update_progress_columns (attachment);
+}
+
/************************* e_attachment_load_async() *************************/
typedef struct _LoadContext LoadContext;
@@ -2500,7 +2370,6 @@ e_attachment_load_handle_error (EAttachment *attachment,
{
GtkWidget *dialog;
GFileInfo *file_info;
- GtkTreeRowReference *reference;
const gchar *display_name;
const gchar *primary_text;
GError *error = NULL;
@@ -2512,17 +2381,7 @@ e_attachment_load_handle_error (EAttachment *attachment,
if (e_attachment_load_finish (attachment, result, &error))
return;
- /* XXX Calling EAttachmentStore functions from here violates
- * the abstraction, but for now it's not hurting anything. */
- reference = e_attachment_get_reference (attachment);
- if (gtk_tree_row_reference_valid (reference)) {
- GtkTreeModel *model;
-
- model = gtk_tree_row_reference_get_model (reference);
-
- e_attachment_store_remove_attachment (
- E_ATTACHMENT_STORE (model), attachment);
- }
+ g_signal_emit (attachment, signals[LOAD_FAILED], 0, NULL);
/* Ignore cancellations. */
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
diff --git a/e-util/e-attachment.h b/e-util/e-attachment.h
index d371008..5fa662e 100644
--- a/e-util/e-attachment.h
+++ b/e-util/e-attachment.h
@@ -60,6 +60,20 @@ struct _EAttachment {
struct _EAttachmentClass {
GObjectClass parent_class;
+
+ /* Signals */
+ void (*update_file_info) (EAttachment *attachment,
+ const gchar *caption,
+ const gchar *content_type,
+ const gchar *description,
+ gint64 size);
+ void (*update_icon) (EAttachment *attachment,
+ GIcon *icon);
+ void (*update_progress) (EAttachment *attachment,
+ gboolean loading,
+ gboolean saving,
+ gint percent);
+ void (*load_failed) (EAttachment *attachment);
};
GType e_attachment_get_type (void) G_GNUC_CONST;
@@ -92,17 +106,10 @@ CamelMimePart * e_attachment_ref_mime_part (EAttachment *attachment);
void e_attachment_set_mime_part (EAttachment *attachment,
CamelMimePart *mime_part);
gint e_attachment_get_percent (EAttachment *attachment);
-GtkTreeRowReference *
- e_attachment_get_reference (EAttachment *attachment);
-void e_attachment_set_reference (EAttachment *attachment,
- GtkTreeRowReference *reference);
gboolean e_attachment_get_saving (EAttachment *attachment);
-gboolean e_attachment_get_shown (EAttachment *attachment);
-void e_attachment_set_shown (EAttachment *attachment,
- gboolean shown);
-gboolean e_attachment_get_zoom_to_window (EAttachment *attachment);
-void e_attachment_set_zoom_to_window (EAttachment *attachment,
- gboolean zoom_to_window);
+gboolean e_attachment_get_initially_shown(EAttachment *attachment);
+void e_attachment_set_initially_shown(EAttachment *attachment,
+ gboolean initially_shown);
gboolean e_attachment_get_save_self (EAttachment *attachment);
void e_attachment_set_save_self (EAttachment *attachment,
gboolean save_self);
@@ -121,6 +128,8 @@ gchar * e_attachment_dup_description (EAttachment *attachment);
gchar * e_attachment_dup_thumbnail_path (EAttachment *attachment);
gboolean e_attachment_is_rfc822 (EAttachment *attachment);
GList * e_attachment_list_apps (EAttachment *attachment);
+void e_attachment_update_store_columns
+ (EAttachment *attachment);
/* Asynchronous Operations */
void e_attachment_load_async (EAttachment *attachment,
diff --git a/e-util/e-content-editor.c b/e-util/e-content-editor.c
new file mode 100644
index 0000000..2224af0
--- /dev/null
+++ b/e-util/e-content-editor.c
@@ -0,0 +1,3583 @@
+/*
+ * Copyright (C) 2016 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library 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.
+ *
+ * This library 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 this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <libedataserver/libedataserver.h>
+
+#include "e-html-editor.h"
+#include "e-util-enumtypes.h"
+#include "e-content-editor.h"
+
+G_DEFINE_INTERFACE (EContentEditor, e_content_editor, GTK_TYPE_WIDGET);
+
+enum {
+ LOAD_FINISHED,
+ PASTE_CLIPBOARD,
+ PASTE_PRIMARY_CLIPBOARD,
+ CONTEXT_MENU_REQUESTED,
+ FIND_DONE,
+ REPLACE_ALL_DONE,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+static void
+e_content_editor_default_init (EContentEditorInterface *iface)
+{
+ /**
+ * EContentEditor:can-copy
+ *
+ * Determines whether it's possible to copy to clipboard. The action
+ * is usually disabled when there is no selection to copy.
+ */
+ g_object_interface_install_property (
+ iface,
+ g_param_spec_boolean (
+ "can-copy",
+ "Can Copy",
+ NULL,
+ FALSE,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * EContentEditor:can-cut
+ *
+ * Determines whether it's possible to cut to clipboard. The action
+ * is usually disabled when there is no selection to cut.
+ */
+ g_object_interface_install_property (
+ iface,
+ g_param_spec_boolean (
+ "can-cut",
+ "Can Cut",
+ NULL,
+ FALSE,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * EContentEditor:can-paste
+ *
+ * Determines whether it's possible to paste from clipboard. The action
+ * is usually disabled when there is no valid content in clipboard to
+ * paste.
+ */
+ g_object_interface_install_property (
+ iface,
+ g_param_spec_boolean (
+ "can-paste",
+ "Can Paste",
+ NULL,
+ FALSE,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * EContentEditor:can-redo
+ *
+ * Determines whether it's possible to redo previous action. The action
+ * is usually disabled when there is no action to redo.
+ */
+ g_object_interface_install_property (
+ iface,
+ g_param_spec_boolean (
+ "can-redo",
+ "Can Redo",
+ NULL,
+ FALSE,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * EContentEditor:can-undo
+ *
+ * Determines whether it's possible to undo last action. The action
+ * is usually disabled when there is no previous action to undo.
+ */
+ g_object_interface_install_property (
+ iface,
+ g_param_spec_boolean (
+ "can-undo",
+ "Can Undo",
+ NULL,
+ FALSE,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * EContentEditor:editable
+ *
+ * Determines whether the editor is editable or read-only.
+ **/
+ g_object_interface_install_property (
+ iface,
+ g_param_spec_boolean (
+ "editable",
+ "Editable",
+ "Wheter editor is editable",
+ TRUE,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * EContentEditor:changed
+ *
+ * Determines whether document has been modified
+ */
+ g_object_interface_install_property (
+ iface,
+ g_param_spec_boolean (
+ "changed",
+ "Changed property",
+ "Whether editor changed",
+ FALSE,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * EContentEditor:html-mode
+ *
+ * Determines whether HTML or plain text mode is enabled.
+ **/
+ g_object_interface_install_property (
+ iface,
+ g_param_spec_boolean (
+ "html-mode",
+ "HTML Mode",
+ "Edit HTML or plain text",
+ TRUE,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * EContentEditor:alignment
+ *
+ * Holds alignment of current paragraph.
+ */
+ g_object_interface_install_property (
+ iface,
+ g_param_spec_enum (
+ "alignment",
+ NULL,
+ NULL,
+ E_TYPE_CONTENT_EDITOR_ALIGNMENT,
+ E_CONTENT_EDITOR_ALIGNMENT_LEFT,
+ G_PARAM_READWRITE));
+
+ /**
+ * EContentEditor:background-color
+ *
+ * Holds background color of current selection or at current cursor
+ * position.
+ */
+ g_object_interface_install_property (
+ iface,
+ g_param_spec_boxed (
+ "background-color",
+ NULL,
+ NULL,
+ GDK_TYPE_RGBA,
+ G_PARAM_READWRITE));
+
+ /**
+ * EContentEditor:block-format
+ *
+ * Holds block format of current paragraph. See
+ * #EContentEditorBlockFormat for valid values.
+ */
+ g_object_interface_install_property (
+ iface,
+ g_param_spec_enum (
+ "block-format",
+ NULL,
+ NULL,
+ E_TYPE_CONTENT_EDITOR_BLOCK_FORMAT,
+ E_CONTENT_EDITOR_BLOCK_FORMAT_NONE,
+ G_PARAM_READWRITE));
+
+ /**
+ * EContentEditor:bold
+ *
+ * Holds whether current selection or text at current cursor position
+ * is bold.
+ */
+ g_object_interface_install_property (
+ iface,
+ g_param_spec_boolean (
+ "bold",
+ NULL,
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * EContentEditor:font-color
+ *
+ * Holds font color of current selection or at current cursor position.
+ */
+ g_object_interface_install_property (
+ iface,
+ g_param_spec_boxed (
+ "font-color",
+ NULL,
+ NULL,
+ GDK_TYPE_RGBA,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * EContentEditor:font-name
+ *
+ * Holds name of font in current selection or at current cursor
+ * position.
+ */
+ g_object_interface_install_property (
+ iface,
+ g_param_spec_string (
+ "font-name",
+ NULL,
+ NULL,
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * EContentEditor:font-size
+ *
+ * Holds point size of current selection or at current cursor position.
+ */
+ g_object_interface_install_property (
+ iface,
+ g_param_spec_int (
+ "font-size",
+ NULL,
+ NULL,
+ 1,
+ 7,
+ 3,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * EContentEditor:indented
+ *
+ * Holds whether current paragraph is indented. This does not include
+ * citations.
+ */
+ g_object_interface_install_property (
+ iface,
+ g_param_spec_boolean (
+ "indented",
+ NULL,
+ NULL,
+ FALSE,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * EContentEditor:italic
+ *
+ * Holds whether current selection or letter at current cursor position
+ * is italic.
+ */
+ g_object_interface_install_property (
+ iface,
+ g_param_spec_boolean (
+ "italic",
+ NULL,
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * EContentEditor:monospaced
+ *
+ * Holds whether current selection or letter at current cursor position
+ * is monospaced.
+ */
+ g_object_interface_install_property (
+ iface,
+ g_param_spec_boolean (
+ "monospaced",
+ NULL,
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * EContentEditor:strikethrough
+ *
+ * Holds whether current selection or letter at current cursor position
+ * is strikethrough.
+ */
+ g_object_interface_install_property (
+ iface,
+ g_param_spec_boolean (
+ "strikethrough",
+ NULL,
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * EContentEditor:superscript
+ *
+ * Holds whether current selection or letter at current cursor position
+ * is in superscript.
+ */
+ g_object_interface_install_property (
+ iface,
+ g_param_spec_boolean (
+ "superscript",
+ NULL,
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * EContentEditor:subscript
+ *
+ * Holds whether current selection or letter at current cursor position
+ * is in subscript.
+ */
+ g_object_interface_install_property (
+ iface,
+ g_param_spec_boolean (
+ "subscript",
+ NULL,
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * EContentEditor:underline
+ *
+ * Holds whether current selection or letter at current cursor position
+ * is underlined.
+ */
+ g_object_interface_install_property (
+ iface,
+ g_param_spec_boolean (
+ "underline",
+ NULL,
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * EContentEditor:spell-check-enabled
+ *
+ * Holds whether the spell checking is enabled.
+ */
+ g_object_interface_install_property (
+ iface,
+ g_param_spec_boolean (
+ "spell-check-enabled",
+ NULL,
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * EContentEditor:spell-checker:
+ *
+ * The #ESpellChecker used for spell checking.
+ **/
+ g_object_interface_install_property (
+ iface,
+ g_param_spec_object (
+ "spell-checker",
+ "Spell Checker",
+ "The spell checker",
+ E_TYPE_SPELL_CHECKER,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * EContentEditor:paste-clipboard
+ *
+ * Emitted when user presses middle button on EContentEditor.
+ */
+ signals[PASTE_CLIPBOARD] = g_signal_new (
+ "paste-clipboard",
+ E_TYPE_CONTENT_EDITOR,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EContentEditorInterface, paste_clipboard),
+ g_signal_accumulator_true_handled, NULL,
+ NULL,
+ G_TYPE_BOOLEAN, 0);
+
+ /**
+ * EContentEditor:paste-primary-clipboard
+ *
+ * Emitted when user presses middle button on EWebKitContentEditor.
+ */
+ signals[PASTE_PRIMARY_CLIPBOARD] = g_signal_new (
+ "paste-primary-clipboard",
+ E_TYPE_CONTENT_EDITOR,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EContentEditorInterface, paste_primary_clipboard),
+ g_signal_accumulator_true_handled, NULL,
+ NULL,
+ G_TYPE_BOOLEAN, 0);
+
+ /**
+ * EContentEditor:load-finished
+ *
+ * Emitted when the content editor has finished loading.
+ */
+ signals[LOAD_FINISHED] = g_signal_new (
+ "load-finished",
+ E_TYPE_CONTENT_EDITOR,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EContentEditorInterface, load_finished),
+ NULL, NULL,
+ NULL,
+ G_TYPE_NONE, 0);
+
+ /**
+ * EContentEditor:context-menu-requested
+ *
+ * Emitted whenever a context menu is requested.
+ */
+ signals[CONTEXT_MENU_REQUESTED] = g_signal_new (
+ "context-menu-requested",
+ E_TYPE_CONTENT_EDITOR,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EContentEditorInterface, context_menu_requested),
+ g_signal_accumulator_true_handled, NULL,
+ NULL,
+ G_TYPE_BOOLEAN, 2,
+ G_TYPE_INT,
+ GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
+
+ /**
+ * EContentEditor::find-done
+ *
+ * Emitted when the call to e_content_editor_find() is done.
+ **/
+ signals[FIND_DONE] = g_signal_new (
+ "find-done",
+ E_TYPE_CONTENT_EDITOR,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EContentEditorInterface, find_done),
+ NULL, NULL,
+ NULL,
+ G_TYPE_NONE, 1,
+ G_TYPE_UINT);
+
+ /**
+ * EContentEditor::replace-all-done
+ *
+ * Emitted when the call to e_content_editor_replace_all() is done.
+ **/
+ signals[REPLACE_ALL_DONE] = g_signal_new (
+ "replace-all-done",
+ E_TYPE_CONTENT_EDITOR,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EContentEditorInterface, replace_all_done),
+ NULL, NULL,
+ NULL,
+ G_TYPE_NONE, 1,
+ G_TYPE_UINT);
+}
+
+ESpellChecker *
+e_content_editor_ref_spell_checker (EContentEditor *editor)
+{
+ ESpellChecker *spell_checker = NULL;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), NULL);
+
+ g_object_get (G_OBJECT (editor), "spell-checker", &spell_checker, NULL);
+
+ return spell_checker;
+}
+
+gboolean
+e_content_editor_can_cut (EContentEditor *editor)
+{
+ gboolean value = FALSE;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), FALSE);
+
+ g_object_get (G_OBJECT (editor), "can-cut", &value, NULL);
+
+ return value;
+}
+
+gboolean
+e_content_editor_can_copy (EContentEditor *editor)
+{
+ gboolean value = FALSE;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), FALSE);
+
+ g_object_get (G_OBJECT (editor), "can-copy", &value, NULL);
+
+ return value;
+}
+
+gboolean
+e_content_editor_can_paste (EContentEditor *editor)
+{
+ gboolean value = FALSE;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), FALSE);
+
+ g_object_get (G_OBJECT (editor), "can-paste", &value, NULL);
+
+ return value;
+}
+
+gboolean
+e_content_editor_can_undo (EContentEditor *editor)
+{
+ gboolean value = FALSE;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), FALSE);
+
+ g_object_get (G_OBJECT (editor), "can-undo", &value, NULL);
+
+ return value;
+}
+
+gboolean
+e_content_editor_can_redo (EContentEditor *editor)
+{
+ gboolean value = FALSE;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), FALSE);
+
+ g_object_get (G_OBJECT (editor), "can-redo", &value, NULL);
+
+ return value;
+}
+
+/**
+ * e_content_editor_is_indented:
+ * @editor: an #EContentEditor
+ *
+ * Returns whether the current paragraph is indented. This does not include
+ * citations.
+ *
+ * Returns: %TRUE when current paragraph is indented, %FALSE otherwise.
+ *
+ * Since: 3.22
+ **/
+gboolean
+e_content_editor_is_indented (EContentEditor *editor)
+{
+ gboolean value = FALSE;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), FALSE);
+
+ g_object_get (G_OBJECT (editor), "indented", &value, NULL);
+
+ return value;
+}
+
+gboolean
+e_content_editor_get_spell_check_enabled (EContentEditor *editor)
+{
+ gboolean value = FALSE;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), FALSE);
+
+ g_object_get (G_OBJECT (editor), "spell-check-enabled", &value, NULL);
+
+ return value;
+}
+
+void
+e_content_editor_set_spell_check_enabled (EContentEditor *editor,
+ gboolean enable)
+{
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ g_object_set (G_OBJECT (editor), "spell-check-enabled", enable, NULL);
+}
+
+gboolean
+e_content_editor_is_editable (EContentEditor *editor)
+{
+ gboolean value = FALSE;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), FALSE);
+
+ g_object_get (G_OBJECT (editor), "editable", &value, NULL);
+
+ return value;
+}
+
+void
+e_content_editor_set_editable (EContentEditor *editor,
+ gboolean editable)
+{
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ g_object_set (G_OBJECT (editor), "editable", editable, NULL);
+}
+
+gboolean
+e_content_editor_get_changed (EContentEditor *editor)
+{
+ gboolean value = FALSE;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), FALSE);
+
+ g_object_get (G_OBJECT (editor), "changed", &value, NULL);
+
+ return value;
+}
+
+void
+e_content_editor_set_changed (EContentEditor *editor,
+ gboolean changed)
+{
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ g_object_set (G_OBJECT (editor), "changed", changed, NULL);
+}
+
+gboolean
+e_content_editor_get_html_mode (EContentEditor *editor)
+{
+ gboolean value = FALSE;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), FALSE);
+
+ g_object_get (G_OBJECT (editor), "html-mode", &value, NULL);
+
+ return value;
+}
+
+void
+e_content_editor_set_html_mode (EContentEditor *editor,
+ gboolean html_mode)
+{
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ g_object_set (G_OBJECT (editor), "html-mode", html_mode, NULL);
+}
+
+/**
+ * e_content_editor_set_alignment:
+ * @editor: an #EContentEditor
+ * @value: an #EContentEditorAlignment value to apply
+ *
+ * Sets alignment of current paragraph to @value.
+ *
+ * Since: 3.22
+ **/
+void
+e_content_editor_set_alignment (EContentEditor *editor,
+ EContentEditorAlignment value)
+{
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ g_object_set (G_OBJECT (editor), "alignment", value, NULL);
+}
+
+/**
+ * e_content_editor_get_alignment:
+ * @editor: #an EContentEditor
+ *
+ * Returns alignment of the current paragraph.
+ *
+ * Returns: #EContentEditorAlignment
+ *
+ * Since: 3.22
+ **/
+EContentEditorAlignment
+e_content_editor_get_alignment (EContentEditor *editor)
+{
+ EContentEditorAlignment value = E_CONTENT_EDITOR_ALIGNMENT_LEFT;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), E_CONTENT_EDITOR_ALIGNMENT_LEFT);
+
+ g_object_get (G_OBJECT (editor), "alignment", &value, NULL);
+
+ return value;
+}
+
+/**
+ * e_content_editor_set_background_color:
+ * @editor: an #EContentEditor
+ * @value: a #GdkRGBA
+ *
+ * Sets the background color of the current selection or letter at the current cursor position to
+ * a color defined by @value.
+ *
+ * Since: 3.22
+ **/
+void
+e_content_editor_set_background_color (EContentEditor *editor,
+ const GdkRGBA *value)
+{
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+ g_return_if_fail (value != NULL);
+
+ g_object_set (G_OBJECT (editor), "background-color", value, NULL);
+}
+
+/**
+ * e_content_editor_dup_background_color:
+ * @editor: an #EContentEditor
+ *
+ * Returns the background color used in the current selection or at letter
+ * at the current cursor position.
+ *
+ * Returns: (transfer-full): A newly allocated #GdkRGBA structure with
+ * the current background color. Free the returned value with gdk_rgba_free()
+ * when done with it.
+ *
+ * Since: 3.22
+ **/
+GdkRGBA *
+e_content_editor_dup_background_color (EContentEditor *editor)
+{
+ GdkRGBA *value = NULL;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), NULL);
+
+ g_object_get (G_OBJECT (editor), "background-color", &value, NULL);
+
+ return value;
+}
+
+/**
+ * e_content_editor_set_font_color:
+ * @editor: an #EContentEditor
+ * @value: a #GdkRGBA
+ *
+ * Sets the font color of the current selection or letter at the current cursor position to
+ * a color defined by @value.
+ *
+ * Since: 3.22
+ **/
+void
+e_content_editor_set_font_color (EContentEditor *editor,
+ const GdkRGBA *value)
+{
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+ g_return_if_fail (value != NULL);
+
+ g_object_set (G_OBJECT (editor), "font-color", value, NULL);
+}
+
+/**
+ * e_content_editor_dup_font_color:
+ * @editor: an #EContentEditor
+ *
+ * Returns the font color used in the current selection or at letter
+ * at the current cursor position.
+ *
+ * Returns: (transfer-full): A newly allocated #GdkRGBA structure with
+ * the current font color. Free the returned value with gdk_rgba_free()
+ * when done with it.
+ *
+ * Since: 3.22
+ **/
+GdkRGBA *
+e_content_editor_dup_font_color (EContentEditor *editor)
+{
+ GdkRGBA *value = NULL;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), NULL);
+
+ g_object_get (G_OBJECT (editor), "font-color", &value, NULL);
+
+ return value;
+}
+
+/**
+ * e_content_editor_set_font_name:
+ * @editor: an #EContentEditor
+ * @value: a font name to apply
+ *
+ * Sets font name of current selection or of letter at current cursor position
+ * to @value.
+ *
+ * Since: 3.22
+ **/
+void
+e_content_editor_set_font_name (EContentEditor *editor,
+ const gchar *value)
+{
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+ g_return_if_fail (value != NULL);
+
+ g_object_set (G_OBJECT (editor), "font-name", value, NULL);
+}
+
+/**
+ * e_content_editor_dup_font_name:
+ * @editor: an #EContentEditor
+ *
+ * Returns a name of the font used in the current selection or at letter
+ * at the current cursor position.
+ *
+ * Returns: (transfer-full): A newly allocated string with the font name.
+ * Free it with g_free() when done with it.
+ *
+ * Since: 3.22
+ **/
+gchar *
+e_content_editor_dup_font_name (EContentEditor *editor)
+{
+ gchar *value = NULL;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), NULL);
+
+ g_object_get (G_OBJECT (editor), "font-name", &value, NULL);
+
+ return value;
+}
+
+/**
+ * e_content_editor_set_font_size:
+ * @editor: an #EContentEditor
+ * @value: font size to apply
+ *
+ * Sets font size of current selection or of letter at current cursor position
+ * to @value.
+ *
+ * Since: 3.22
+ **/
+void
+e_content_editor_set_font_size (EContentEditor *editor,
+ gint value)
+{
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ g_object_set (G_OBJECT (editor), "font-size", value, NULL);
+}
+
+/**
+ * e_content_editor_get_font_size:
+ * @editor: an #EContentEditor
+ *
+ * Returns fotn size of the current selection or letter at the current
+ * cursor position.
+ *
+ * Returns: Current font size.
+ *
+ * Since: 3.22
+ **/
+gint
+e_content_editor_get_font_size (EContentEditor *editor)
+{
+ gint value = -1;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), -1);
+
+ g_object_get (G_OBJECT (editor), "font-size", &value, NULL);
+
+ return value;
+}
+
+/**
+ * e_content_editor_set_block_format:
+ * @editor: an #EContentEditor
+ * @value: an #EContentEditorBlockFormat value
+ *
+ * Changes block format of the current paragraph to @value.
+ *
+ * Since: 3.22
+ **/
+void
+e_content_editor_set_block_format (EContentEditor *editor,
+ EContentEditorBlockFormat value)
+{
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ g_object_set (G_OBJECT (editor), "block-format", value, NULL);
+}
+
+/**
+ * e_content_editor_get_block_format:
+ * @editor: an #EContentEditor
+ *
+ * Returns block format of the current paragraph.
+ *
+ * Returns: #EContentEditorBlockFormat
+ *
+ * Since: 3.22
+ **/
+EContentEditorBlockFormat
+e_content_editor_get_block_format (EContentEditor *editor)
+{
+ EContentEditorBlockFormat value = E_CONTENT_EDITOR_BLOCK_FORMAT_NONE;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), E_CONTENT_EDITOR_BLOCK_FORMAT_NONE);
+
+ g_object_get (G_OBJECT (editor), "block-format", &value, NULL);
+
+ return value;
+}
+
+/**
+ * e_content_editor_set_bold:
+ * @editor: an #EContentEditor
+ * @bold: %TRUE to enable bold, %FALSE to disable
+ *
+ * Changes bold formatting of current selection or letter at current
+ * cursor position.
+ *
+ * Since: 3.22
+ **/
+void
+e_content_editor_set_bold (EContentEditor *editor,
+ gboolean bold)
+{
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ g_object_set (G_OBJECT (editor), "bold", bold, NULL);
+}
+
+/**
+ * e_content_editor_is_bold:
+ * @editor: an #EContentEditor
+ *
+ * Returns whether current selection or letter at current cursor position is bold.
+ *
+ * Returns: %TRUE when selection is bold, %FALSE otherwise.
+ *
+ * Since: 3.22
+ **/
+gboolean
+e_content_editor_is_bold (EContentEditor *editor)
+{
+ gboolean value = FALSE;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), FALSE);
+
+ g_object_get (G_OBJECT (editor), "bold", &value, NULL);
+
+ return value;
+}
+
+/**
+ * e_content_editor_set_italic:
+ * @editor: an #EContentEditor
+ * @italic: %TRUE to enable italic, %FALSE to disable
+ *
+ * Changes italic formatting of current selection or letter at current
+ * cursor position.
+ *
+ * Since: 3.22
+ **/
+void
+e_content_editor_set_italic (EContentEditor *editor,
+ gboolean italic)
+{
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ g_object_set (G_OBJECT (editor), "italic", italic, NULL);
+}
+
+/**
+ * e_content_editor_is_italic:
+ * @editor: an #EContentEditor
+ *
+ * Returns whether current selection or letter at current cursor position
+ * is italic.
+ *
+ * Returns: %TRUE when selection is italic, %FALSE otherwise.
+ *
+ * Since: 3.22
+ **/
+gboolean
+e_content_editor_is_italic (EContentEditor *editor)
+{
+ gboolean value = FALSE;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), FALSE);
+
+ g_object_get (G_OBJECT (editor), "italic", &value, NULL);
+
+ return value;
+}
+
+/**
+ * e_content_editor_set_monospaced:
+ * @editor: an #EContentEditor
+ * @monospaced: %TRUE to enable monospaced, %FALSE to disable
+ *
+ * Changes monospaced formatting of current selection or letter
+ * at current cursor position.
+ *
+ * Since: 3.22
+ **/
+void
+e_content_editor_set_monospaced (EContentEditor *editor,
+ gboolean monospaced)
+{
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ g_object_set (G_OBJECT (editor), "monospaced", monospaced, NULL);
+}
+
+/**
+ * e_content_editor_is_monospaced:
+ * @editor: an #EContentEditor
+ *
+ * Returns whether current selection or letter at current cursor position
+ * is monospaced.
+ *
+ * Returns: %TRUE when selection is monospaced, %FALSE otherwise.
+ *
+ * Since: 3.22
+ **/
+gboolean
+e_content_editor_is_monospaced (EContentEditor *editor)
+{
+ gboolean value = FALSE;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), FALSE);
+
+ g_object_get (G_OBJECT (editor), "monospaced", &value, NULL);
+
+ return value;
+}
+
+/**
+ * e_content_editor_set_strikethrough:
+ * @editor: an #EContentEditor
+ * @strikethrough: %TRUE to enable strikethrough, %FALSE to disable
+ *
+ * Changes strike through formatting of current selection or letter at current
+ * cursor position.
+ *
+ * Since: 3.22
+ **/
+void
+e_content_editor_set_strikethrough (EContentEditor *editor,
+ gboolean strikethrough)
+{
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ g_object_set (G_OBJECT (editor), "strikethrough", strikethrough, NULL);
+}
+
+/**
+ * e_content_editor_is_strikethrough:
+ * @editor: an #EContentEditor
+ *
+ * Returns whether current selection or letter at current cursor position
+ * is striked through.
+ *
+ * Returns: %TRUE when selection is striked through, %FALSE otherwise.
+ *
+ * Since: 3.22
+ **/
+gboolean
+e_content_editor_is_strikethrough (EContentEditor *editor)
+{
+ gboolean value = FALSE;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), FALSE);
+
+ g_object_get (G_OBJECT (editor), "strikethrough", &value, NULL);
+
+ return value;
+}
+
+/**
+ * e_content_editor_set_subscript:
+ * @editor: an #EContentEditor
+ * @subscript: %TRUE to enable subscript, %FALSE to disable
+ *
+ * Changes subscript of current selection or letter at current
+ * cursor position.
+ *
+ * Since: 3.22
+ **/
+void
+e_content_editor_set_subscript (EContentEditor *editor,
+ gboolean subscript)
+{
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ g_object_set (G_OBJECT (editor), "subscript", subscript, NULL);
+}
+
+/**
+ * e_content_editor_is_subscript:
+ * @editor: an #EContentEditor
+ *
+ * Returns whether current selection or letter at current cursor position
+ * is in subscript.
+ *
+ * Returns: %TRUE when selection is in subscript, %FALSE otherwise.
+ *
+ * Since: 3.22
+ **/
+gboolean
+e_content_editor_is_subscript (EContentEditor *editor)
+{
+ gboolean value = FALSE;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), FALSE);
+
+ g_object_get (G_OBJECT (editor), "subscript", &value, NULL);
+
+ return value;
+}
+
+/**
+ * e_content_editor_set_superscript:
+ * @editor: an #EContentEditor
+ * @superscript: %TRUE to enable superscript, %FALSE to disable
+ *
+ * Changes superscript of the current selection or letter at current
+ * cursor position.
+ *
+ * Since: 3.22
+ **/
+void
+e_content_editor_set_superscript (EContentEditor *editor,
+ gboolean superscript)
+{
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ g_object_set (G_OBJECT (editor), "superscript", superscript, NULL);
+}
+
+/**
+ * e_content_editor_is_superscript:
+ * @editor: an #EContentEditor
+ *
+ * Returns whether current selection or letter at current cursor position
+ * is in superscript.
+ *
+ * Returns: %TRUE when selection is in superscript, %FALSE otherwise.
+ *
+ * Since: 3.22
+ **/
+gboolean
+e_content_editor_is_superscript (EContentEditor *editor)
+{
+ gboolean value = FALSE;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), FALSE);
+
+ g_object_get (G_OBJECT (editor), "superscript", &value, NULL);
+
+ return value;
+}
+
+/**
+ * e_content_editor_set_underline:
+ * @editor: an #EContentEditor
+ * @underline: %TRUE to enable underline, %FALSE to disable
+ *
+ * Changes underline formatting of current selection or letter
+ * at current cursor position.
+ *
+ * Since: 3.22
+ **/
+void
+e_content_editor_set_underline (EContentEditor *editor,
+ gboolean underline)
+{
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ g_object_set (G_OBJECT (editor), "underline", underline, NULL);
+}
+
+/**
+ * e_content_editor_is_underline:
+ * @editor: an #EContentEditor
+ *
+ * Returns whether current selection or letter at current cursor position
+ * is underlined.
+ *
+ * Returns: %TRUE when selection is underlined, %FALSE otherwise.
+ *
+ * Since: 3.22
+ **/
+gboolean
+e_content_editor_is_underline (EContentEditor *editor)
+{
+ gboolean value = FALSE;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), FALSE);
+
+ g_object_get (G_OBJECT (editor), "underline", &value, NULL);
+
+ return value;
+}
+
+/**
+ * e_content_editor_setup_editor:
+ * @content_editor: an #EContentEditor
+ * @callback: an #EContentEditorInitializedCallback function
+ * @user_data: data to pass to @callback
+ *
+ * Initilizes the @content_editor. Once the initialization is done,
+ * the @callback is called with the passed @user_data.
+ *
+ * Since: 3.22
+ **/
+void
+e_content_editor_initialize (EContentEditor *content_editor,
+ EContentEditorInitializedCallback callback,
+ gpointer user_data)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (content_editor));
+ g_return_if_fail (callback != NULL);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (content_editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->initialize != NULL);
+
+ iface->initialize (content_editor, callback, user_data);
+}
+
+/**
+ * e_content_editor_setup_editor:
+ * @content_editor: an #EContentEditor
+ * @html_editor: an #EHTMLEditor
+ *
+ * Called the first time the @content_editor is picked to be used within
+ * the @html_editor. This is typically used to modify the UI
+ * of the @html_editor. This method implementation is optional.
+ *
+ * Since: 3.22
+ **/
+void
+e_content_editor_setup_editor (EContentEditor *content_editor,
+ EHTMLEditor *html_editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (content_editor));
+ g_return_if_fail (E_IS_HTML_EDITOR (html_editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (content_editor);
+ g_return_if_fail (iface != NULL);
+
+ if (iface->setup_editor)
+ iface->setup_editor (content_editor, html_editor);
+}
+
+void
+e_content_editor_update_styles (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->update_styles != NULL);
+
+ iface->update_styles (editor);
+}
+
+void
+e_content_editor_insert_content (EContentEditor *editor,
+ const gchar *content,
+ EContentEditorInsertContentFlags flags)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+ g_return_if_fail (content != NULL);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->insert_content != NULL);
+
+ iface->insert_content (editor, content, flags);
+}
+
+gchar *
+e_content_editor_get_content (EContentEditor *editor,
+ EContentEditorGetContentFlags flags,
+ const gchar *inline_images_from_domain,
+ GSList **inline_images_parts /* newly created CamelMimePart * */)
+{
+ EContentEditorInterface *iface;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), NULL);
+ if ((flags & E_CONTENT_EDITOR_GET_INLINE_IMAGES)) {
+ g_return_val_if_fail (inline_images_from_domain != NULL, NULL);
+ g_return_val_if_fail (inline_images_parts != NULL, NULL);
+ }
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_val_if_fail (iface != NULL, NULL);
+ g_return_val_if_fail (iface->get_content != NULL, NULL);
+
+ return iface->get_content (editor, flags, inline_images_from_domain, inline_images_parts);
+}
+
+void
+e_content_editor_insert_image_from_mime_part (EContentEditor *editor,
+ CamelMimePart *part)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+ g_return_if_fail (part != NULL);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->insert_image_from_mime_part != NULL);
+
+ iface->insert_image_from_mime_part (editor, part);
+}
+
+/**
+ * e_content_editor_insert_image:
+ * @editor: an #EContentEditor
+ * @uri: an URI of the source image
+ *
+ * Inserts image at current cursor position using @uri as source. When a
+ * text range is selected, it will be replaced by the image.
+ *
+ * Since: 3.22
+ **/
+void
+e_content_editor_insert_image (EContentEditor *editor,
+ const gchar *uri)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+ g_return_if_fail (uri != NULL);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->insert_image != NULL);
+
+ iface->insert_image (editor, uri);
+}
+
+void
+e_content_editor_insert_emoticon (EContentEditor *editor,
+ EEmoticon *emoticon)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+ g_return_if_fail (emoticon != NULL);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->insert_emoticon != NULL);
+
+ iface->insert_emoticon (editor, emoticon);
+}
+
+void
+e_content_editor_move_caret_on_coordinates (EContentEditor *editor,
+ gint x,
+ gint y,
+ gboolean cancel_if_not_collapsed)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+ g_return_if_fail (x > 0);
+ g_return_if_fail (y > 0);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->move_caret_on_coordinates != NULL);
+
+ iface->move_caret_on_coordinates (editor, x, y, cancel_if_not_collapsed);
+}
+
+void
+e_content_editor_cut (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->cut != NULL);
+
+ iface->cut (editor);
+}
+
+void
+e_content_editor_copy (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->copy != NULL);
+
+ iface->copy (editor);
+}
+
+void
+e_content_editor_paste (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->paste != NULL);
+
+ iface->paste (editor);
+}
+
+void
+e_content_editor_paste_primary (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->paste_primary != NULL);
+
+ iface->paste_primary (editor);
+}
+
+void
+e_content_editor_undo (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->undo != NULL);
+
+ iface->undo (editor);
+}
+
+void
+e_content_editor_redo (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->redo != NULL);
+
+ iface->redo (editor);
+}
+
+void
+e_content_editor_clear_undo_redo_history (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->clear_undo_redo_history != NULL);
+
+ iface->clear_undo_redo_history (editor);
+}
+
+void
+e_content_editor_set_spell_checking_languages (EContentEditor *editor,
+ const gchar **languages)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->set_spell_checking_languages != NULL);
+
+ iface->set_spell_checking_languages (editor, languages);
+}
+
+void
+e_content_editor_select_all (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->select_all != NULL);
+
+ iface->select_all (editor);
+}
+
+/**
+ * e_content_editor_get_selected_text:
+ * @editor: an #EContentEditor
+ *
+ * Returns currently selected string.
+ *
+ * Returns: (transfer-full): A newly allocated string with the content of current selection.
+ *
+ * Since: 3.22
+ **/
+gchar *
+e_content_editor_get_selected_text (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), NULL);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_val_if_fail (iface != NULL, NULL);
+ g_return_val_if_fail (iface->get_selected_text != NULL, NULL);
+
+ return iface->get_selected_text (editor);
+}
+
+/**
+ * e_content_editor_get_caret_word:
+ * @editor: an #EContentEditor
+ *
+ * Returns word under cursor.
+ *
+ * Returns: (transfer-full): A newly allocated string with current caret word or %NULL
+ * when there is no text under cursor or when selection is active.
+ *
+ * Since: 3.22
+ **/
+gchar *
+e_content_editor_get_caret_word (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), NULL);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_val_if_fail (iface != NULL, NULL);
+ g_return_val_if_fail (iface->get_caret_word != NULL, NULL);
+
+ return iface->get_caret_word (editor);
+}
+
+/**
+ * e_content_editor_replace_caret_word:
+ * @editor: an #EContentEditor
+ * @replacement: a string to replace current caret word with
+ *
+ * Replaces current word under cursor with @replacement.
+ *
+ * Since: 3.22
+ **/
+void
+e_content_editor_replace_caret_word (EContentEditor *editor,
+ const gchar *replacement)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+ g_return_if_fail (replacement != NULL);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->replace_caret_word != NULL);
+
+ iface->replace_caret_word (editor, replacement);
+}
+
+void
+e_content_editor_selection_indent (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->selection_indent != NULL);
+
+ iface->selection_indent (editor);
+}
+
+void
+e_content_editor_selection_unindent (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->selection_unindent != NULL);
+
+ iface->selection_unindent (editor);
+}
+
+/**
+ * e_content_editor_selection_create_link:
+ * @editor: an #EContentEditor
+ * @uri: destination of the new link
+ *
+ * Converts current selection into a link pointing to @url.
+ *
+ * Since: 3.22
+ **/
+void
+e_content_editor_selection_create_link (EContentEditor *editor,
+ const gchar *uri)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+ g_return_if_fail (uri != NULL);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->selection_create_link != NULL);
+
+ iface->selection_create_link (editor, uri);
+}
+
+/**
+ * e_content_editor_selection_unlink:
+ * @editor: an #EContentEditor
+ *
+ * Removes any links (<A> elements) from current selection or at current
+ * cursor position.
+ *
+ * Since: 3.22
+ **/
+void
+e_content_editor_selection_unlink (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->selection_unlink != NULL);
+
+ iface->selection_unlink (editor);
+}
+
+/**
+ * e_content_editor_find:
+ * @editor: an #EContentEditor
+ * @flags: a bit-OR of #EContentEditorFindFlags flags
+ * @text: a text to find
+ *
+ * Searches the content of the @editor for the occurrence of the @text.
+ * The @flags modify the behaviour of the search. The found text,
+ * if any, is supposed to be selected.
+ *
+ * Once the search is done, the "find-done" signal should be
+ * emitted, by using e_content_editor_emit_find_done().
+ *
+ * Since: 3.22
+ **/
+void
+e_content_editor_find (EContentEditor *editor,
+ guint32 flags,
+ const gchar *text)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+ g_return_if_fail (text != NULL);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->find != NULL);
+
+ iface->find (editor, flags, text);
+}
+
+/**
+ * e_content_editor_replace:
+ * @editor: an #EContentEditor
+ * @replacement: a string to replace current selection with
+ *
+ * Replaces currently selected text with @replacement.
+ *
+ * Since: 3.22
+ **/
+void
+e_content_editor_replace (EContentEditor *editor,
+ const gchar *replacement)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+ g_return_if_fail (replacement != NULL);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->replace != NULL);
+
+ iface->replace (editor, replacement);
+}
+
+/**
+ * e_content_editor_replace_all:
+ * @editor: an #EContentEditor
+ * @flags: a bit-OR of #EContentEditorFindFlags flags
+ * @find_text: a text to find
+ * @replace_with: a text to replace the found text with
+ *
+ * Searches the content of the @editor for all the occurrences of
+ * the @find_text and replaces them with the @replace_with.
+ * The @flags modify the behaviour of the search.
+ *
+ * Once the replace is done, the "replace-all-done" signal should be
+ * emitted, by using e_content_editor_emit_replace_all_done().
+ *
+ * Since: 3.22
+ **/
+void
+e_content_editor_replace_all (EContentEditor *editor,
+ guint32 flags,
+ const gchar *find_text,
+ const gchar *replace_with)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+ g_return_if_fail (find_text != NULL);
+ g_return_if_fail (replace_with != NULL);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->replace_all != NULL);
+
+ iface->replace_all (editor, flags, find_text, replace_with);
+}
+
+/**
+ * e_content_editor_selection_save:
+ * @editor: an #EContentEditor
+ *
+ * Saves current cursor position or current selection range. The selection can
+ * be later restored by calling e_content_editor_selection_restore().
+ *
+ * Note that calling e_content_editor_selection_save() overwrites previously saved
+ * position.
+ *
+ * Note that this method inserts special markings into the HTML code that are
+ * used to later restore the selection. It can happen that by deleting some
+ * segments of the document some of the markings are deleted too. In that case
+ * restoring the selection by e_content_editor_selection_restore() can fail. Also by
+ * moving text segments (Cut & Paste) can result in moving the markings
+ * elsewhere, thus e_content_editor_selection_restore() will restore the selection
+ * incorrectly.
+ *
+ * It is recommended to use this method only when you are not planning to make
+ * bigger changes to content or structure of the document (formatting changes
+ * are usually OK).
+ *
+ * Since: 3.22
+ **/
+void
+e_content_editor_selection_save (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->selection_save != NULL);
+
+ iface->selection_save (editor);
+}
+
+/**
+ * e_content_editor_selection_restore:
+ * @editor: an #EContentEditor
+ *
+ * Restores cursor position or selection range that was saved by
+ * e_content_editor_selection_save().
+ *
+ * Note that calling this function without calling e_content_editor_selection_save()
+ * before is a programming error and the behavior is undefined.
+ *
+ * Since: 3.22
+ **/
+void
+e_content_editor_selection_restore (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->selection_restore != NULL);
+
+ iface->selection_restore (editor);
+}
+
+void
+e_content_editor_selection_wrap (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->selection_wrap != NULL);
+
+ iface->selection_wrap (editor);
+}
+
+guint
+e_content_editor_get_caret_position (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), 0);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_val_if_fail (iface != NULL, 0);
+ g_return_val_if_fail (iface->get_caret_position != NULL, 0);
+
+ return iface->get_caret_position (editor);
+}
+
+guint
+e_content_editor_get_caret_offset (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), 0);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_val_if_fail (iface != NULL, 0);
+ g_return_val_if_fail (iface->get_caret_offset != NULL, 0);
+
+ return iface->get_caret_offset (editor);
+}
+
+gchar *
+e_content_editor_get_current_signature_uid (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), NULL);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_val_if_fail (iface != NULL, NULL);
+ g_return_val_if_fail (iface->get_current_signature_uid != NULL, NULL);
+
+ return iface->get_current_signature_uid (editor);
+}
+
+gboolean
+e_content_editor_is_ready (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), FALSE);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_val_if_fail (iface != NULL, FALSE);
+ g_return_val_if_fail (iface->is_ready != NULL, FALSE);
+
+ return iface->is_ready (editor);
+}
+
+gchar *
+e_content_editor_insert_signature (EContentEditor *editor,
+ const gchar *content,
+ gboolean is_html,
+ const gchar *signature_id,
+ gboolean *set_signature_from_message,
+ gboolean *check_if_signature_is_changed,
+ gboolean *ignore_next_signature_change)
+{
+ EContentEditorInterface *iface;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), FALSE);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_val_if_fail (iface != NULL, FALSE);
+ g_return_val_if_fail (iface->insert_signature != NULL, FALSE);
+
+ return iface->insert_signature (
+ editor,
+ content,
+ is_html,
+ signature_id,
+ set_signature_from_message,
+ check_if_signature_is_changed,
+ ignore_next_signature_change);
+}
+
+void
+e_content_editor_delete_cell_contents (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->delete_cell_contents != NULL);
+
+ iface->delete_cell_contents (editor);
+}
+
+void
+e_content_editor_delete_column (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->delete_column != NULL);
+
+ iface->delete_column (editor);
+}
+
+void
+e_content_editor_delete_row (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->delete_row != NULL);
+
+ iface->delete_row (editor);
+}
+
+void
+e_content_editor_delete_table (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->delete_table != NULL);
+
+ iface->delete_table (editor);
+}
+
+void
+e_content_editor_insert_column_after (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->insert_column_after != NULL);
+
+ iface->insert_column_after (editor);
+}
+
+void
+e_content_editor_insert_column_before (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->insert_column_before != NULL);
+
+ iface->insert_column_before (editor);
+}
+
+void
+e_content_editor_insert_row_above (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->insert_row_above != NULL);
+
+ iface->insert_row_above (editor);
+}
+
+void
+e_content_editor_insert_row_below (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->insert_row_below != NULL);
+
+ iface->insert_row_below (editor);
+}
+
+gboolean
+e_content_editor_on_h_rule_dialog_open (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), FALSE);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_val_if_fail (iface != NULL, FALSE);
+ g_return_val_if_fail (iface->on_h_rule_dialog_open != NULL, FALSE);
+
+ return iface->on_h_rule_dialog_open (editor);
+}
+
+void
+e_content_editor_on_h_rule_dialog_close (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->on_h_rule_dialog_close != NULL);
+
+ iface->on_h_rule_dialog_close (editor);
+}
+
+void
+e_content_editor_h_rule_set_align (EContentEditor *editor,
+ const gchar *value)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->h_rule_set_align != NULL);
+
+ iface->h_rule_set_align (editor, value);
+}
+
+gchar *
+e_content_editor_h_rule_get_align (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), NULL);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_val_if_fail (iface != NULL, NULL);
+ g_return_val_if_fail (iface->h_rule_get_align != NULL, NULL);
+
+ return iface->h_rule_get_align (editor);
+}
+
+void
+e_content_editor_h_rule_set_size (EContentEditor *editor,
+ gint value)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->h_rule_set_size != NULL);
+
+ iface->h_rule_set_size (editor, value);
+}
+
+gint
+e_content_editor_h_rule_get_size (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), 0);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_val_if_fail (iface != NULL, 0);
+ g_return_val_if_fail (iface->h_rule_get_size != NULL, 0);
+
+ return iface->h_rule_get_size (editor);
+}
+
+void
+e_content_editor_h_rule_set_width (EContentEditor *editor,
+ gint value,
+ EContentEditorUnit unit)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->h_rule_set_width != NULL);
+
+ iface->h_rule_set_width (editor, value, unit);
+}
+
+gint
+e_content_editor_h_rule_get_width (EContentEditor *editor,
+ EContentEditorUnit *unit)
+{
+ EContentEditorInterface *iface;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), 0);
+ g_return_val_if_fail (unit != NULL, 0);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_val_if_fail (iface != NULL, 0);
+ g_return_val_if_fail (iface->h_rule_get_width != NULL, 0);
+
+ return iface->h_rule_get_width (editor, unit);
+}
+
+void
+e_content_editor_h_rule_set_no_shade (EContentEditor *editor,
+ gboolean value)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->h_rule_set_no_shade != NULL);
+
+ iface->h_rule_set_no_shade (editor, value);
+}
+
+gboolean
+e_content_editor_h_rule_get_no_shade (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), FALSE);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_val_if_fail (iface != NULL, FALSE);
+ g_return_val_if_fail (iface->h_rule_get_no_shade != NULL, FALSE);
+
+ return iface->h_rule_get_no_shade (editor);
+}
+
+void
+e_content_editor_on_image_dialog_open (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->on_image_dialog_open != NULL);
+
+ iface->on_image_dialog_open (editor);
+}
+
+void
+e_content_editor_on_image_dialog_close (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->on_image_dialog_close != NULL);
+
+ iface->on_image_dialog_close (editor);
+}
+
+void
+e_content_editor_image_set_width_follow (EContentEditor *editor,
+ gboolean value)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->image_set_width_follow != NULL);
+
+ iface->image_set_width_follow (editor, value);
+}
+
+void
+e_content_editor_image_set_src (EContentEditor *editor,
+ const gchar *value)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->image_set_src != NULL);
+
+ iface->image_set_src (editor, value);
+}
+
+gchar *
+e_content_editor_image_get_src (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), FALSE);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_val_if_fail (iface != NULL, FALSE);
+ g_return_val_if_fail (iface->image_get_src != NULL, FALSE);
+
+ return iface->image_get_src (editor);
+}
+
+void
+e_content_editor_image_set_alt (EContentEditor *editor,
+ const gchar *value)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->image_set_alt != NULL);
+
+ iface->image_set_alt (editor, value);
+}
+
+gchar *
+e_content_editor_image_get_alt (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), FALSE);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_val_if_fail (iface != NULL, FALSE);
+ g_return_val_if_fail (iface->image_get_alt != NULL, FALSE);
+
+ return iface->image_get_alt (editor);
+}
+
+void
+e_content_editor_image_set_url (EContentEditor *editor,
+ const gchar *value)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->image_set_url != NULL);
+
+ iface->image_set_url (editor, value);
+}
+
+gchar *
+e_content_editor_image_get_url (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), FALSE);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_val_if_fail (iface != NULL, FALSE);
+ g_return_val_if_fail (iface->image_get_url != NULL, FALSE);
+
+ return iface->image_get_url (editor);
+}
+
+void
+e_content_editor_image_set_vspace (EContentEditor *editor,
+ gint value)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->image_set_vspace != NULL);
+
+ iface->image_set_vspace (editor, value);
+}
+
+gint
+e_content_editor_image_get_vspace (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), 0);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_val_if_fail (iface != NULL, 0);
+ g_return_val_if_fail (iface->image_get_vspace != NULL, 0);
+
+ return iface->image_get_vspace (editor);
+}
+
+
+void
+e_content_editor_image_set_hspace (EContentEditor *editor,
+ gint value)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->image_set_hspace != NULL);
+
+ iface->image_set_hspace (editor, value);
+}
+
+gint
+e_content_editor_image_get_hspace (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), 0);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_val_if_fail (iface != NULL, 0);
+ g_return_val_if_fail (iface->image_get_hspace != NULL, 0);
+
+ return iface->image_get_hspace (editor);
+}
+
+void
+e_content_editor_image_set_border (EContentEditor *editor,
+ gint value)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->image_set_border != NULL);
+
+ iface->image_set_border (editor, value);
+}
+
+gint
+e_content_editor_image_get_border (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), FALSE);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_val_if_fail (iface != NULL, FALSE);
+ g_return_val_if_fail (iface->image_get_border != NULL, FALSE);
+
+ return iface->image_get_border (editor);
+}
+
+void
+e_content_editor_image_set_align (EContentEditor *editor,
+ const gchar *value)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->image_set_align != NULL);
+
+ iface->image_set_align (editor, value);
+}
+
+gchar *
+e_content_editor_image_get_align (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), FALSE);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_val_if_fail (iface != NULL, FALSE);
+ g_return_val_if_fail (iface->image_get_align != NULL, FALSE);
+
+ return iface->image_get_align (editor);
+}
+
+gint32
+e_content_editor_image_get_natural_width (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), 0);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_val_if_fail (iface != NULL, 0);
+ g_return_val_if_fail (iface->image_get_natural_width != NULL, 0);
+
+ return iface->image_get_natural_width (editor);
+}
+
+gint32
+e_content_editor_image_get_natural_height (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), 0);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_val_if_fail (iface != NULL, 0);
+ g_return_val_if_fail (iface->image_get_natural_height != NULL, 0);
+
+ return iface->image_get_natural_height (editor);
+}
+
+void
+e_content_editor_image_set_width (EContentEditor *editor,
+ gint value)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->image_set_width != NULL);
+
+ iface->image_set_width (editor, value);
+}
+
+gint32
+e_content_editor_image_get_width (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), 0);
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), 0);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_val_if_fail (iface != NULL, 0);
+ g_return_val_if_fail (iface->image_get_width != NULL, 0);
+
+ return iface->image_get_width (editor);
+}
+
+void
+e_content_editor_image_set_height (EContentEditor *editor,
+ gint value)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->image_set_height != NULL);
+
+ iface->image_set_height (editor, value);
+}
+
+gint32
+e_content_editor_image_get_height (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), 0);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_val_if_fail (iface != NULL, 0);
+ g_return_val_if_fail (iface->image_get_height != NULL, 0);
+
+ return iface->image_get_height (editor);
+}
+
+void
+e_content_editor_image_set_height_follow (EContentEditor *editor,
+ gboolean value)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->image_set_height_follow != NULL);
+
+ iface->image_set_height_follow (editor, value);
+}
+
+void
+e_content_editor_on_link_dialog_open (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->on_link_dialog_open != NULL);
+
+ iface->on_link_dialog_open (editor);
+}
+
+void
+e_content_editor_on_link_dialog_close (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->on_link_dialog_close != NULL);
+
+ iface->on_link_dialog_close (editor);
+}
+
+void
+e_content_editor_link_get_values (EContentEditor *editor,
+ gchar **href,
+ gchar **text)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->link_get_values != NULL);
+
+ return iface->link_get_values (editor, href, text);
+}
+
+void
+e_content_editor_link_set_values (EContentEditor *editor,
+ const gchar *href,
+ const gchar *text)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->link_set_values != NULL);
+
+ iface->link_set_values (editor, href, text);
+}
+
+void
+e_content_editor_on_page_dialog_open (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->on_page_dialog_open != NULL);
+
+ iface->on_page_dialog_open (editor);
+}
+
+void
+e_content_editor_on_page_dialog_close (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->on_page_dialog_close != NULL);
+
+ iface->on_page_dialog_close (editor);
+}
+
+void
+e_content_editor_page_set_text_color (EContentEditor *editor,
+ const GdkRGBA *value)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+ g_return_if_fail (value != NULL);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->page_set_text_color != NULL);
+
+ iface->page_set_text_color (editor, value);
+}
+
+void
+e_content_editor_page_get_text_color (EContentEditor *editor,
+ GdkRGBA *value)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+ g_return_if_fail (value != NULL);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->page_get_text_color != NULL);
+
+ return iface->page_get_text_color (editor, value);
+}
+
+void
+e_content_editor_page_set_background_color (EContentEditor *editor,
+ const GdkRGBA *value)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+ g_return_if_fail (value != NULL);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->page_set_background_color != NULL);
+
+ iface->page_set_background_color (editor, value);
+}
+
+void
+e_content_editor_page_get_background_color (EContentEditor *editor,
+ GdkRGBA *value)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+ g_return_if_fail (value != NULL);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->page_get_background_color != NULL);
+
+ return iface->page_get_background_color (editor, value);
+}
+
+void
+e_content_editor_page_set_link_color (EContentEditor *editor,
+ const GdkRGBA *value)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+ g_return_if_fail (value != NULL);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->page_set_link_color != NULL);
+
+ iface->page_set_link_color (editor, value);
+}
+
+void
+e_content_editor_page_get_link_color (EContentEditor *editor,
+ GdkRGBA *value)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+ g_return_if_fail (value != NULL);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->page_get_link_color != NULL);
+
+ return iface->page_get_link_color (editor, value);
+}
+
+void
+e_content_editor_page_set_visited_link_color (EContentEditor *editor,
+ const GdkRGBA *value)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+ g_return_if_fail (value != NULL);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->page_set_visited_link_color != NULL);
+
+ iface->page_set_visited_link_color (editor, value);
+}
+
+void
+e_content_editor_page_get_visited_link_color (EContentEditor *editor,
+ GdkRGBA *value)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+ g_return_if_fail (value != NULL);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->page_get_visited_link_color != NULL);
+
+ return iface->page_get_visited_link_color (editor, value);
+}
+
+/* uri could be NULL -> removes the current image */
+void
+e_content_editor_page_set_background_image_uri (EContentEditor *editor,
+ const gchar *uri)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->page_set_background_image_uri != NULL);
+
+ iface->page_set_background_image_uri (editor, uri);
+}
+
+gchar *
+e_content_editor_page_get_background_image_uri (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), NULL);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_val_if_fail (iface != NULL, NULL);
+ g_return_val_if_fail (iface->page_get_background_image_uri != NULL, NULL);
+
+ return iface->page_get_background_image_uri (editor);
+}
+
+void
+e_content_editor_on_cell_dialog_open (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->on_cell_dialog_open != NULL);
+
+ iface->on_cell_dialog_open (editor);
+}
+
+void
+e_content_editor_on_cell_dialog_close (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->on_cell_dialog_close != NULL);
+
+ iface->on_cell_dialog_close (editor);
+}
+
+void
+e_content_editor_cell_set_v_align (EContentEditor *editor,
+ const gchar *value,
+ EContentEditorScope scope)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+ g_return_if_fail (value != NULL);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->cell_set_v_align != NULL);
+
+ iface->cell_set_v_align (editor, value, scope);
+}
+
+gchar *
+e_content_editor_cell_get_v_align (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), NULL);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_val_if_fail (iface != NULL, NULL);
+ g_return_val_if_fail (iface->cell_get_v_align != NULL, NULL);
+
+ return iface->cell_get_v_align (editor);
+}
+
+void
+e_content_editor_cell_set_align (EContentEditor *editor,
+ const gchar *value,
+ EContentEditorScope scope)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+ g_return_if_fail (value != NULL);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->cell_set_align != NULL);
+
+ iface->cell_set_align (editor, value, scope);
+}
+
+gchar *
+e_content_editor_cell_get_align (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), NULL);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_val_if_fail (iface != NULL, NULL);
+ g_return_val_if_fail (iface->cell_get_align != NULL, NULL);
+
+ return iface->cell_get_align (editor);
+}
+
+void
+e_content_editor_cell_set_wrap (EContentEditor *editor,
+ gboolean value,
+ EContentEditorScope scope)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->cell_set_wrap != NULL);
+
+ iface->cell_set_wrap (editor, value, scope);
+}
+
+gboolean
+e_content_editor_cell_get_wrap (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), FALSE);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_val_if_fail (iface != NULL, FALSE);
+ g_return_val_if_fail (iface->cell_get_wrap != NULL, FALSE);
+
+ return iface->cell_get_wrap (editor);
+}
+
+void
+e_content_editor_cell_set_header_style (EContentEditor *editor,
+ gboolean value,
+ EContentEditorScope scope)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->cell_set_header_style != NULL);
+
+ iface->cell_set_header_style (editor, value, scope);
+}
+
+gboolean
+e_content_editor_cell_is_header (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), FALSE);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_val_if_fail (iface != NULL, FALSE);
+ g_return_val_if_fail (iface->cell_is_header != NULL, FALSE);
+
+ return iface->cell_is_header (editor);
+}
+
+void
+e_content_editor_cell_set_width (EContentEditor *editor,
+ gint value,
+ EContentEditorUnit unit,
+ EContentEditorScope scope)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->cell_set_width != NULL);
+
+ iface->cell_set_width (editor, value, unit, scope);
+}
+
+gint
+e_content_editor_cell_get_width (EContentEditor *editor,
+ EContentEditorUnit *unit)
+{
+ EContentEditorInterface *iface;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), 0);
+ g_return_val_if_fail (unit != NULL, 0);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_val_if_fail (iface != NULL, 0);
+ g_return_val_if_fail (iface->cell_get_width != NULL, 0);
+
+ return iface->cell_get_width (editor, unit);
+}
+
+void
+e_content_editor_cell_set_row_span (EContentEditor *editor,
+ gint value,
+ EContentEditorScope scope)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->cell_set_row_span != NULL);
+
+ iface->cell_set_row_span (editor, value, scope);
+}
+
+gint
+e_content_editor_cell_get_row_span (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), 0);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_val_if_fail (iface != NULL, 0);
+ g_return_val_if_fail (iface->cell_get_row_span != NULL, 0);
+
+ return iface->cell_get_row_span (editor);
+}
+
+void
+e_content_editor_cell_set_col_span (EContentEditor *editor,
+ gint value,
+ EContentEditorScope scope)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->cell_set_col_span != NULL);
+
+ iface->cell_set_col_span (editor, value, scope);
+}
+
+gint
+e_content_editor_cell_get_col_span (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), 0);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_val_if_fail (iface != NULL, 0);
+ g_return_val_if_fail (iface->cell_get_col_span != NULL, 0);
+
+ return iface->cell_get_col_span (editor);
+}
+
+/* uri could be NULL -> removes the current image */
+void
+e_content_editor_cell_set_background_image_uri (EContentEditor *editor,
+ const gchar *uri)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->cell_set_background_image_uri != NULL);
+
+ iface->cell_set_background_image_uri (editor, uri);
+}
+
+gchar *
+e_content_editor_cell_get_background_image_uri (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), NULL);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_val_if_fail (iface != NULL, NULL);
+ g_return_val_if_fail (iface->cell_get_background_image_uri != NULL, NULL);
+
+ return iface->cell_get_background_image_uri (editor);
+}
+
+void
+e_content_editor_cell_set_background_color (EContentEditor *editor,
+ const GdkRGBA *value,
+ EContentEditorScope scope)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+ g_return_if_fail (value != NULL);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->cell_set_background_color != NULL);
+
+ iface->cell_set_background_color (editor, value, scope);
+}
+
+void
+e_content_editor_cell_get_background_color (EContentEditor *editor,
+ GdkRGBA *value)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->cell_get_background_color != NULL);
+
+ iface->cell_get_background_color (editor, value);
+}
+
+void
+e_content_editor_table_set_row_count (EContentEditor *editor,
+ guint value)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->table_set_row_count != NULL);
+
+ iface->table_set_row_count (editor, value);
+}
+
+guint
+e_content_editor_table_get_row_count (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), 0);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_val_if_fail (iface != NULL, 0);
+ g_return_val_if_fail (iface->table_get_row_count != NULL, 0);
+
+ return iface->table_get_row_count (editor);
+}
+
+void
+e_content_editor_table_set_column_count (EContentEditor *editor,
+ guint value)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->table_set_column_count != NULL);
+
+ iface->table_set_column_count (editor, value);
+}
+
+guint
+e_content_editor_table_get_column_count (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), 0);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_val_if_fail (iface != NULL, 0);
+ g_return_val_if_fail (iface->table_get_column_count != NULL, 0);
+
+ return iface->table_get_column_count (editor);
+}
+
+void
+e_content_editor_table_set_width (EContentEditor *editor,
+ gint value,
+ EContentEditorUnit unit)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->table_set_width != NULL);
+
+ iface->table_set_width (editor, value, unit);
+}
+
+guint
+e_content_editor_table_get_width (EContentEditor *editor,
+ EContentEditorUnit *unit)
+{
+ EContentEditorInterface *iface;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), 0);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_val_if_fail (iface != NULL, 0);
+ g_return_val_if_fail (iface->table_get_width != NULL, 0);
+
+ return iface->table_get_width (editor, unit);
+}
+
+void
+e_content_editor_table_set_align (EContentEditor *editor,
+ const gchar *value)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->table_set_align != NULL);
+
+ iface->table_set_align (editor, value);
+}
+
+gchar *
+e_content_editor_table_get_align (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), NULL);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_val_if_fail (iface != NULL, NULL);
+ g_return_val_if_fail (iface->table_get_align != NULL, NULL);
+
+ return iface->table_get_align (editor);
+}
+
+void
+e_content_editor_table_set_padding (EContentEditor *editor,
+ gint value)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->table_set_padding != NULL);
+
+ iface->table_set_padding (editor, value);
+}
+
+gint
+e_content_editor_table_get_padding (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), 0);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_val_if_fail (iface != NULL, 0);
+ g_return_val_if_fail (iface->table_get_padding != NULL, 0);
+
+ return iface->table_get_padding (editor);
+}
+
+void
+e_content_editor_table_set_spacing (EContentEditor *editor,
+ gint value)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->table_set_spacing != NULL);
+
+ iface->table_set_spacing (editor, value);
+}
+
+gint
+e_content_editor_table_get_spacing (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), 0);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_val_if_fail (iface != NULL, 0);
+ g_return_val_if_fail (iface->table_get_spacing != NULL, 0);
+
+ return iface->table_get_spacing (editor);
+}
+
+void
+e_content_editor_table_set_border (EContentEditor *editor,
+ gint value)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->table_set_border != NULL);
+
+ iface->table_set_border (editor, value);
+}
+
+gint
+e_content_editor_table_get_border (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), 0);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_val_if_fail (iface != NULL, 0);
+ g_return_val_if_fail (iface->table_get_border != NULL, 0);
+
+ return iface->table_get_border (editor);
+}
+
+gchar *
+e_content_editor_table_get_background_image_uri (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), NULL);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_val_if_fail (iface != NULL, NULL);
+ g_return_val_if_fail (iface->table_get_background_image_uri != NULL, NULL);
+
+ return iface->table_get_background_image_uri (editor);
+}
+
+void
+e_content_editor_table_set_background_image_uri (EContentEditor *editor,
+ const gchar *uri)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->table_set_background_image_uri != NULL);
+
+ iface->table_set_background_image_uri (editor, uri);
+}
+
+void
+e_content_editor_table_get_background_color (EContentEditor *editor,
+ GdkRGBA *value)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->table_get_background_color != NULL);
+
+ iface->table_get_background_color (editor, value);
+}
+
+void
+e_content_editor_table_set_background_color (EContentEditor *editor,
+ const GdkRGBA *value)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->table_set_background_color != NULL);
+
+ iface->table_set_background_color (editor, value);
+}
+
+gboolean
+e_content_editor_on_table_dialog_open (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), FALSE);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_val_if_fail (iface != NULL, FALSE);
+ g_return_val_if_fail (iface->on_table_dialog_open != NULL, FALSE);
+
+ return iface->on_table_dialog_open (editor);
+}
+
+void
+e_content_editor_on_table_dialog_close (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->on_table_dialog_close != NULL);
+
+ iface->on_table_dialog_close (editor);
+}
+
+void
+e_content_editor_on_spell_check_dialog_open (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->on_spell_check_dialog_close != NULL);
+
+ iface->on_spell_check_dialog_close (editor);
+}
+
+void
+e_content_editor_on_spell_check_dialog_close (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->on_spell_check_dialog_close != NULL);
+
+ iface->on_spell_check_dialog_close (editor);
+}
+
+gchar *
+e_content_editor_spell_check_next_word (EContentEditor *editor,
+ const gchar *word)
+{
+ EContentEditorInterface *iface;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), NULL);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_val_if_fail (iface != NULL, NULL);
+ g_return_val_if_fail (iface->spell_check_next_word != NULL, NULL);
+
+ return iface->spell_check_next_word (editor, word);
+}
+
+gchar *
+e_content_editor_spell_check_prev_word (EContentEditor *editor,
+ const gchar *word)
+{
+ EContentEditorInterface *iface;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), NULL);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_val_if_fail (iface != NULL, NULL);
+ g_return_val_if_fail (iface->spell_check_prev_word != NULL, NULL);
+
+ return iface->spell_check_prev_word (editor, word);
+}
+
+void
+e_content_editor_on_replace_dialog_open (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->on_replace_dialog_open != NULL);
+
+ iface->on_replace_dialog_open (editor);
+}
+
+void
+e_content_editor_on_replace_dialog_close (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->on_replace_dialog_close != NULL);
+
+ iface->on_replace_dialog_close (editor);
+}
+
+void
+e_content_editor_on_find_dialog_open (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->on_find_dialog_open != NULL);
+
+ iface->on_find_dialog_open (editor);
+}
+
+void
+e_content_editor_on_find_dialog_close (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_if_fail (iface != NULL);
+ g_return_if_fail (iface->on_find_dialog_close != NULL);
+
+ iface->on_find_dialog_close (editor);
+}
+
+void
+e_content_editor_emit_load_finished (EContentEditor *editor)
+{
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ g_signal_emit (editor, signals[LOAD_FINISHED], 0);
+}
+
+gboolean
+e_content_editor_emit_paste_clipboard (EContentEditor *editor)
+{
+ gboolean handled = FALSE;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), FALSE);
+
+ g_signal_emit (editor, signals[PASTE_CLIPBOARD], 0, &handled);
+
+ return handled;
+}
+
+gboolean
+e_content_editor_emit_paste_primary_clipboard (EContentEditor *editor)
+{
+ gboolean handled = FALSE;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), FALSE);
+
+ g_signal_emit (editor, signals[PASTE_PRIMARY_CLIPBOARD], 0, &handled);
+
+ return handled;
+}
+
+gboolean
+e_content_editor_emit_context_menu_requested (EContentEditor *editor,
+ EContentEditorNodeFlags flags,
+ GdkEvent *event)
+{
+ gboolean handled = FALSE;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), FALSE);
+
+ g_signal_emit (editor, signals[CONTEXT_MENU_REQUESTED], 0, flags, event, &handled);
+
+ return handled;
+}
+
+void
+e_content_editor_emit_find_done (EContentEditor *editor,
+ guint match_count)
+{
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ g_signal_emit (editor, signals[FIND_DONE], 0, match_count);
+}
+
+void
+e_content_editor_emit_replace_all_done (EContentEditor *editor,
+ guint replaced_count)
+{
+ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
+
+ g_signal_emit (editor, signals[REPLACE_ALL_DONE], 0, replaced_count);
+}
diff --git a/e-util/e-content-editor.h b/e-util/e-content-editor.h
new file mode 100644
index 0000000..8d3d64e
--- /dev/null
+++ b/e-util/e-content-editor.h
@@ -0,0 +1,1021 @@
+/*
+ * Copyright (C) 2016 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library 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.
+ *
+ * This library 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 this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#if !defined (__E_UTIL_H_INSIDE__) && !defined (LIBEUTIL_COMPILATION)
+#error "Only <e-util/e-util.h> should be included directly."
+#endif
+
+#ifndef E_CONTENT_EDITOR_H
+#define E_CONTENT_EDITOR_H
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+#include <camel/camel.h>
+
+#include <e-util/e-emoticon.h>
+#include <e-util/e-spell-checker.h>
+#include <e-util/e-util-enums.h>
+
+#define DEFAULT_CONTENT_EDITOR_NAME "WebKit"
+
+G_BEGIN_DECLS
+
+struct _EHTMLEditor;
+
+#define E_TYPE_CONTENT_EDITOR e_content_editor_get_type ()
+G_DECLARE_INTERFACE (EContentEditor, e_content_editor, E, CONTENT_EDITOR, GtkWidget)
+
+typedef void (*EContentEditorInitializedCallback) (EContentEditor *content_editor,
+ gpointer user_data);
+
+struct _EContentEditorInterface {
+ GTypeInterface parent_interface;
+
+ void (*initialize) (EContentEditor *content_editor,
+ EContentEditorInitializedCallback callback,
+ gpointer user_data);
+ void (*setup_editor) (EContentEditor *content_editor,
+ struct _EHTMLEditor *html_editor);
+ void (*update_styles) (EContentEditor *editor);
+ void (*insert_content) (EContentEditor *editor,
+ const gchar *content,
+ EContentEditorInsertContentFlags flags);
+
+ gchar * (*get_content) (EContentEditor *editor,
+ EContentEditorGetContentFlags flags,
+ const gchar *inline_images_from_domain,
+ GSList **inline_images_parts /* newly created
CamelMimePart * */);
+
+ void (*insert_image) (EContentEditor *editor,
+ const gchar *uri);
+
+ void (*insert_image_from_mime_part)
+ (EContentEditor *editor,
+ CamelMimePart *part);
+
+ void (*insert_emoticon) (EContentEditor *editor,
+ EEmoticon *emoticon);
+
+ void (*move_caret_on_coordinates) (EContentEditor *editor,
+ gint x,
+ gint y,
+ gboolean cancel_if_not_collapsed);
+
+ void (*cut) (EContentEditor *editor);
+
+ void (*copy) (EContentEditor *editor);
+
+ void (*paste) (EContentEditor *editor);
+
+ void (*paste_primary) (EContentEditor *editor);
+
+ void (*undo) (EContentEditor *editor);
+
+ void (*redo) (EContentEditor *editor);
+
+ void (*clear_undo_redo_history) (EContentEditor *editor);
+
+ void (*set_spell_checking_languages) (EContentEditor *editor,
+ const gchar **languages);
+
+ gchar * (*get_selected_text) (EContentEditor *editor);
+
+ gchar * (*get_caret_word) (EContentEditor *editor);
+
+ void (*replace_caret_word) (EContentEditor *editor,
+ const gchar *replacement);
+
+ void (*select_all) (EContentEditor *editor);
+
+ void (*selection_indent) (EContentEditor *editor);
+
+ void (*selection_unindent) (EContentEditor *editor);
+
+ void (*selection_create_link) (EContentEditor *editor,
+ const gchar *uri);
+
+ void (*selection_unlink) (EContentEditor *editor);
+
+ void (*find) (EContentEditor *editor,
+ guint32 flags,
+ const gchar *text);
+
+ void (*replace) (EContentEditor *editor,
+ const gchar *replacement);
+
+ void (*replace_all) (EContentEditor *editor,
+ guint32 flags,
+ const gchar *find_text,
+ const gchar *replace_with);
+
+ void (*selection_save) (EContentEditor *editor);
+
+ void (*selection_restore) (EContentEditor *editor);
+
+ void (*selection_wrap) (EContentEditor *editor);
+
+ guint (*get_caret_position) (EContentEditor *editor);
+
+ guint (*get_caret_offset) (EContentEditor *editor);
+
+ gchar * (*get_current_signature_uid) (EContentEditor *editor);
+
+ gboolean (*is_ready) (EContentEditor *editor);
+
+ gchar * (*insert_signature) (EContentEditor *editor,
+ const gchar *content,
+ gboolean is_html,
+ const gchar *signature_id,
+ gboolean *set_signature_from_message,
+ gboolean *check_if_signature_is_changed,
+ gboolean *ignore_next_signature_change);
+
+ void (*delete_cell_contents) (EContentEditor *editor);
+
+ void (*delete_column) (EContentEditor *editor);
+
+ void (*delete_row) (EContentEditor *editor);
+
+ void (*delete_table) (EContentEditor *editor);
+
+ void (*insert_column_after) (EContentEditor *editor);
+
+ void (*insert_column_before) (EContentEditor *editor);
+
+ void (*insert_row_above) (EContentEditor *editor);
+
+ void (*insert_row_below) (EContentEditor *editor);
+
+ gboolean (*on_h_rule_dialog_open) (EContentEditor *editor);
+
+ void (*on_h_rule_dialog_close) (EContentEditor *editor);
+
+ void (*h_rule_set_align) (EContentEditor *editor,
+ const gchar *value);
+
+ gchar * (*h_rule_get_align) (EContentEditor *editor);
+
+ void (*h_rule_set_size) (EContentEditor *editor,
+ gint value);
+
+ gint (*h_rule_get_size) (EContentEditor *editor);
+
+ void (*h_rule_set_width) (EContentEditor *editor,
+ gint value,
+ EContentEditorUnit unit);
+
+ gint (*h_rule_get_width) (EContentEditor *editor,
+ EContentEditorUnit *unit);
+
+ void (*h_rule_set_no_shade) (EContentEditor *editor,
+ gboolean value);
+
+ gboolean (*h_rule_get_no_shade) (EContentEditor *editor);
+
+ void (*on_image_dialog_open) (EContentEditor *editor);
+
+ void (*on_image_dialog_close) (EContentEditor *editor);
+
+ void (*image_set_src) (EContentEditor *editor,
+ const gchar *value);
+
+ gchar * (*image_get_src) (EContentEditor *editor);
+
+ void (*image_set_alt) (EContentEditor *editor,
+ const gchar *value);
+
+ gchar * (*image_get_alt) (EContentEditor *editor);
+
+ gint32 (*image_get_natural_width) (EContentEditor *editor);
+
+ gint32 (*image_get_width) (EContentEditor *editor);
+
+ void (*image_set_width) (EContentEditor *editor,
+ gint value);
+
+ void (*image_set_width_follow) (EContentEditor *editor,
+ gboolean value);
+
+ gint32 (*image_get_natural_height) (EContentEditor *editor);
+
+ gint32 (*image_get_height) (EContentEditor *editor);
+
+ void (*image_set_height) (EContentEditor *editor,
+ gint value);
+
+ void (*image_set_height_follow) (EContentEditor *editor,
+ gboolean value);
+
+ void (*image_set_url) (EContentEditor *editor,
+ const gchar *value);
+
+ gchar * (*image_get_url) (EContentEditor *editor);
+
+ void (*image_set_vspace) (EContentEditor *editor,
+ gint value);
+
+ gint (*image_get_vspace) (EContentEditor *editor);
+
+ void (*image_set_hspace) (EContentEditor *editor,
+ gint value);
+
+ gint (*image_get_hspace) (EContentEditor *editor);
+
+ void (*image_set_border) (EContentEditor *editor,
+ gint border);
+
+ gint (*image_get_border) (EContentEditor *editor);
+
+ void (*image_set_align) (EContentEditor *editor,
+ const gchar *value);
+
+ gchar * (*image_get_align) (EContentEditor *editor);
+
+ void (*on_link_dialog_open) (EContentEditor *editor);
+
+ void (*on_link_dialog_close) (EContentEditor *editor);
+
+ void (*link_get_values) (EContentEditor *editor,
+ gchar **href,
+ gchar **text);
+
+ void (*link_set_values) (EContentEditor *editor,
+ const gchar *href,
+ const gchar *text);
+
+ void (*on_page_dialog_open) (EContentEditor *editor);
+
+ void (*on_page_dialog_close) (EContentEditor *editor);
+
+ void (*page_set_text_color) (EContentEditor *editor,
+ const GdkRGBA *value);
+
+ void (*page_get_text_color) (EContentEditor *editor,
+ GdkRGBA *value);
+
+ void (*page_set_background_color) (EContentEditor *editor,
+ const GdkRGBA *value);
+
+ void (*page_get_background_color) (EContentEditor *editor,
+ GdkRGBA *value);
+
+ void (*page_set_link_color) (EContentEditor *editor,
+ const GdkRGBA *value);
+
+ void (*page_get_link_color) (EContentEditor *editor,
+ GdkRGBA *value);
+
+ void (*page_set_visited_link_color) (EContentEditor *editor,
+ const GdkRGBA *value);
+
+ void (*page_get_visited_link_color) (EContentEditor *editor,
+ GdkRGBA *value);
+
+ void (*page_set_background_image_uri)
+ (EContentEditor *editor,
+ const gchar *uri);
+
+ gchar * (*page_get_background_image_uri)
+ (EContentEditor *editor);
+
+ void (*on_cell_dialog_open) (EContentEditor *editor);
+
+ void (*on_cell_dialog_close) (EContentEditor *editor);
+
+ void (*cell_set_v_align) (EContentEditor *editor,
+ const gchar *value,
+ EContentEditorScope scope);
+
+ gchar * (*cell_get_v_align) (EContentEditor *editor);
+
+ void (*cell_set_align) (EContentEditor *editor,
+ const gchar *value,
+ EContentEditorScope scope);
+
+ gchar * (*cell_get_align) (EContentEditor *editor);
+
+ void (*cell_set_wrap) (EContentEditor *editor,
+ gboolean value,
+ EContentEditorScope scope);
+
+ gboolean (*cell_get_wrap) (EContentEditor *editor);
+
+ void (*cell_set_header_style) (EContentEditor *editor,
+ gboolean value,
+ EContentEditorScope scope);
+
+ gboolean (*cell_is_header) (EContentEditor *editor);
+
+ void (*cell_set_width) (EContentEditor *editor,
+ gint value,
+ EContentEditorUnit unit,
+ EContentEditorScope scope);
+
+ gint (*cell_get_width) (EContentEditor *editor,
+ EContentEditorUnit *unit);
+
+ void (*cell_set_row_span) (EContentEditor *editor,
+ gint value,
+ EContentEditorScope scope);
+
+ gint (*cell_get_row_span) (EContentEditor *editor);
+
+ void (*cell_set_col_span) (EContentEditor *editor,
+ gint value,
+ EContentEditorScope scope);
+
+ gint (*cell_get_col_span) (EContentEditor *editor);
+
+ gchar * (*cell_get_background_image_uri)
+ (EContentEditor *editor);
+
+ void (*cell_set_background_image_uri)
+ (EContentEditor *editor,
+ const gchar *uri);
+
+ void (*cell_get_background_color) (EContentEditor *editor,
+ GdkRGBA *value);
+
+ void (*cell_set_background_color) (EContentEditor *editor,
+ const GdkRGBA *value,
+ EContentEditorScope scope);
+
+ void (*table_set_row_count) (EContentEditor *editor,
+ guint value);
+
+ guint (*table_get_row_count) (EContentEditor *editor);
+
+ void (*table_set_column_count) (EContentEditor *editor,
+ guint value);
+
+ guint (*table_get_column_count) (EContentEditor *editor);
+
+ void (*table_set_width) (EContentEditor *editor,
+ gint value,
+ EContentEditorUnit unit);
+
+ guint (*table_get_width) (EContentEditor *editor,
+ EContentEditorUnit *unit);
+
+ void (*table_set_align) (EContentEditor *editor,
+ const gchar *value);
+
+ gchar * (*table_get_align) (EContentEditor *editor);
+
+ void (*table_set_padding) (EContentEditor *editor,
+ gint value);
+
+ gint (*table_get_padding) (EContentEditor *editor);
+
+ void (*table_set_spacing) (EContentEditor *editor,
+ gint value);
+
+ gint (*table_get_spacing) (EContentEditor *editor);
+
+ void (*table_set_border) (EContentEditor *editor,
+ gint value);
+
+ gint (*table_get_border) (EContentEditor *editor);
+
+ gchar * (*table_get_background_image_uri)
+ (EContentEditor *editor);
+
+ void (*table_set_background_image_uri)
+ (EContentEditor *editor,
+ const gchar *uri);
+
+ void (*table_get_background_color) (EContentEditor *editor,
+ GdkRGBA *value);
+
+ void (*table_set_background_color) (EContentEditor *editor,
+ const GdkRGBA *value);
+
+ gboolean (*on_table_dialog_open) (EContentEditor *editor);
+
+ void (*on_table_dialog_close) (EContentEditor *editor);
+
+ void (*on_spell_check_dialog_open) (EContentEditor *editor);
+
+ void (*on_spell_check_dialog_close) (EContentEditor *editor);
+
+ gchar * (*spell_check_next_word) (EContentEditor *editor,
+ const gchar *word);
+
+ gchar * (*spell_check_prev_word) (EContentEditor *editor,
+ const gchar *word);
+
+ void (*on_replace_dialog_open) (EContentEditor *editor);
+
+ void (*on_replace_dialog_close) (EContentEditor *editor);
+
+ void (*on_find_dialog_open) (EContentEditor *editor);
+
+ void (*on_find_dialog_close) (EContentEditor *editor);
+
+ /* Signals */
+ void (*load_finished) (EContentEditor *editor);
+ gboolean (*paste_clipboard) (EContentEditor *editor);
+ gboolean (*paste_primary_clipboard) (EContentEditor *editor);
+ gboolean (*context_menu_requested) (EContentEditor *editor,
+ EContentEditorNodeFlags flags,
+ GdkEvent *event);
+ void (*find_done) (EContentEditor *editor,
+ guint match_count);
+ void (*replace_all_done) (EContentEditor *editor,
+ guint replaced_count);
+};
+
+/* Properties */
+
+ESpellChecker * e_content_editor_ref_spell_checker
+ (EContentEditor *editor);
+gboolean e_content_editor_can_cut (EContentEditor *editor);
+gboolean e_content_editor_can_copy (EContentEditor *editor);
+gboolean e_content_editor_can_paste (EContentEditor *editor);
+gboolean e_content_editor_can_undo (EContentEditor *editor);
+gboolean e_content_editor_can_redo (EContentEditor *editor);
+gboolean e_content_editor_is_indented (EContentEditor *editor);
+gboolean e_content_editor_get_spell_check_enabled
+ (EContentEditor *editor);
+void e_content_editor_set_spell_check_enabled
+ (EContentEditor *editor,
+ gboolean enable);
+gboolean e_content_editor_is_editable (EContentEditor *editor);
+void e_content_editor_set_editable (EContentEditor *editor,
+ gboolean editable);
+gboolean e_content_editor_get_changed (EContentEditor *editor);
+void e_content_editor_set_changed (EContentEditor *editor,
+ gboolean changed);
+gboolean e_content_editor_get_html_mode (EContentEditor *editor);
+void e_content_editor_set_html_mode (EContentEditor *editor,
+ gboolean html_mode);
+void e_content_editor_set_alignment (EContentEditor *editor,
+ EContentEditorAlignment value);
+EContentEditorAlignment
+ e_content_editor_get_alignment (EContentEditor *editor);
+void e_content_editor_set_background_color
+ (EContentEditor *editor,
+ const GdkRGBA *value);
+GdkRGBA * e_content_editor_dup_background_color
+ (EContentEditor *editor);
+void e_content_editor_set_font_color (EContentEditor *editor,
+ const GdkRGBA *value);
+GdkRGBA * e_content_editor_dup_font_color (EContentEditor *editor);
+void e_content_editor_set_font_name (EContentEditor *editor,
+ const gchar *value);
+gchar * e_content_editor_dup_font_name (EContentEditor *editor);
+void e_content_editor_set_font_size (EContentEditor *editor,
+ gint value);
+gint e_content_editor_get_font_size (EContentEditor *editor);
+void e_content_editor_set_block_format
+ (EContentEditor *editor,
+ EContentEditorBlockFormat value);
+EContentEditorBlockFormat
+ e_content_editor_get_block_format
+ (EContentEditor *editor);
+void e_content_editor_set_bold (EContentEditor *editor,
+ gboolean bold);
+gboolean e_content_editor_is_bold (EContentEditor *editor);
+void e_content_editor_set_italic (EContentEditor *editor,
+ gboolean italic);
+gboolean e_content_editor_is_italic (EContentEditor *editor);
+void e_content_editor_set_monospaced (EContentEditor *editor,
+ gboolean monospaced);
+gboolean e_content_editor_is_monospaced (EContentEditor *editor);
+void e_content_editor_set_strikethrough
+ (EContentEditor *editor,
+ gboolean strikethrough);
+gboolean e_content_editor_is_strikethrough
+ (EContentEditor *editor);
+void e_content_editor_set_subscript (EContentEditor *editor,
+ gboolean subscript);
+gboolean e_content_editor_is_subscript (EContentEditor *editor);
+void e_content_editor_set_superscript
+ (EContentEditor *editor,
+ gboolean superscript);
+gboolean e_content_editor_is_superscript
+ (EContentEditor *editor);
+void e_content_editor_set_underline (EContentEditor *editor,
+ gboolean underline);
+gboolean e_content_editor_is_underline (EContentEditor *editor);
+
+/* Methods */
+void e_content_editor_initialize (EContentEditor *content_editor,
+ EContentEditorInitializedCallback callback,
+ gpointer user_data);
+void e_content_editor_setup_editor (EContentEditor *content_editor,
+ struct _EHTMLEditor *html_editor);
+void e_content_editor_update_styles (EContentEditor *editor);
+void e_content_editor_insert_content (EContentEditor *editor,
+ const gchar *content,
+ EContentEditorInsertContentFlags flags);
+
+gchar * e_content_editor_get_content (EContentEditor *editor,
+ EContentEditorGetContentFlags flags,
+ const gchar *inline_images_from_domain,
+ GSList **inline_images_parts /* newly created CamelMimePart
* */);
+
+void e_content_editor_insert_image_from_mime_part
+ (EContentEditor *editor,
+ CamelMimePart *part);
+
+void e_content_editor_insert_image (EContentEditor *editor,
+ const gchar *uri);
+
+void e_content_editor_insert_emoticon
+ (EContentEditor *editor,
+ EEmoticon *emoticon);
+
+void e_content_editor_move_caret_on_coordinates
+ (EContentEditor *editor,
+ gint x,
+ gint y,
+ gboolean cancel_if_not_collapsed);
+
+void e_content_editor_cut (EContentEditor *editor);
+
+void e_content_editor_copy (EContentEditor *editor);
+
+void e_content_editor_paste (EContentEditor *editor);
+
+void e_content_editor_paste_primary (EContentEditor *editor);
+
+void e_content_editor_undo (EContentEditor *editor);
+
+void e_content_editor_redo (EContentEditor *editor);
+
+void e_content_editor_clear_undo_redo_history
+ (EContentEditor *editor);
+
+void e_content_editor_set_spell_checking_languages
+ (EContentEditor *editor,
+ const gchar **languages);
+
+void e_content_editor_select_all (EContentEditor *editor);
+
+gchar * e_content_editor_get_selected_text
+ (EContentEditor *editor);
+
+gchar * e_content_editor_get_caret_word (EContentEditor *editor);
+
+void e_content_editor_replace_caret_word
+ (EContentEditor *editor,
+ const gchar *replacement);
+
+void e_content_editor_selection_indent
+ (EContentEditor *editor);
+
+void e_content_editor_selection_unindent
+ (EContentEditor *editor);
+
+void e_content_editor_selection_create_link
+ (EContentEditor *editor,
+ const gchar *uri);
+
+void e_content_editor_selection_unlink
+ (EContentEditor *editor);
+
+void e_content_editor_find (EContentEditor *editor,
+ guint32 flags,
+ const gchar *text);
+
+void e_content_editor_replace (EContentEditor *editor,
+ const gchar *replacement);
+
+void e_content_editor_replace_all (EContentEditor *editor,
+ guint32 flags,
+ const gchar *find_text,
+ const gchar *replace_with);
+
+void e_content_editor_selection_save (EContentEditor *editor);
+
+void e_content_editor_selection_restore
+ (EContentEditor *editor);
+
+void e_content_editor_selection_wrap (EContentEditor *editor);
+
+guint e_content_editor_get_caret_position
+ (EContentEditor *editor);
+
+guint e_content_editor_get_caret_offset
+ (EContentEditor *editor);
+
+gchar * e_content_editor_get_current_signature_uid
+ (EContentEditor *editor);
+
+gboolean e_content_editor_is_ready (EContentEditor *editor);
+
+gchar * e_content_editor_insert_signature
+ (EContentEditor *editor,
+ const gchar *content,
+ gboolean is_html,
+ const gchar *signature_id,
+ gboolean *set_signature_from_message,
+ gboolean *check_if_signature_is_changed,
+ gboolean *ignore_next_signature_change);
+
+void e_content_editor_delete_cell_contents
+ (EContentEditor *editor);
+void
+ e_content_editor_delete_column (EContentEditor *editor);
+
+void e_content_editor_delete_row (EContentEditor *editor);
+
+void e_content_editor_delete_table (EContentEditor *editor);
+
+void e_content_editor_insert_column_after
+ (EContentEditor *editor);
+
+void e_content_editor_insert_column_before
+ (EContentEditor *editor);
+
+void e_content_editor_insert_row_above
+ (EContentEditor *editor);
+
+void e_content_editor_insert_row_below
+ (EContentEditor *editor);
+
+gboolean e_content_editor_on_h_rule_dialog_open
+ (EContentEditor *editor);
+
+void e_content_editor_on_h_rule_dialog_close
+ (EContentEditor *editor);
+
+void e_content_editor_h_rule_set_align
+ (EContentEditor *editor,
+ const gchar *value);
+
+gchar * e_content_editor_h_rule_get_align
+ (EContentEditor *editor);
+
+void e_content_editor_h_rule_set_size
+ (EContentEditor *editor,
+ gint value);
+
+gint e_content_editor_h_rule_get_size
+ (EContentEditor *editor);
+
+void e_content_editor_h_rule_set_width
+ (EContentEditor *editor,
+ gint value,
+ EContentEditorUnit unit);
+
+gint e_content_editor_h_rule_get_width
+ (EContentEditor *editor,
+ EContentEditorUnit *unit);
+
+void e_content_editor_h_rule_set_no_shade
+ (EContentEditor *editor,
+ gboolean value);
+
+gboolean e_content_editor_h_rule_get_no_shade
+ (EContentEditor *editor);
+
+void e_content_editor_on_image_dialog_open
+ (EContentEditor *editor);
+
+void e_content_editor_on_image_dialog_close
+ (EContentEditor *editor);
+
+void e_content_editor_image_set_src (EContentEditor *editor,
+ const gchar *value);
+
+gchar * e_content_editor_image_get_src (EContentEditor *editor);
+
+void e_content_editor_image_set_alt (EContentEditor *editor,
+ const gchar *value);
+
+gchar * e_content_editor_image_get_alt (EContentEditor *editor);
+
+void e_content_editor_image_set_url (EContentEditor *editor,
+ const gchar *value);
+
+gchar * e_content_editor_image_get_url (EContentEditor *editor);
+
+void e_content_editor_image_set_vspace
+ (EContentEditor *editor,
+ gint value);
+
+gint e_content_editor_image_get_vspace
+ (EContentEditor *editor);
+
+void e_content_editor_image_set_hspace
+ (EContentEditor *editor,
+ gint value);
+
+gint e_content_editor_image_get_hspace
+ (EContentEditor *editor);
+
+void e_content_editor_image_set_border
+ (EContentEditor *editor,
+ gint value);
+
+gint e_content_editor_image_get_border
+ (EContentEditor *editor);
+
+void e_content_editor_image_set_align
+ (EContentEditor *editor,
+ const gchar *value);
+
+gchar * e_content_editor_image_get_align
+ (EContentEditor *editor);
+
+void e_content_editor_image_set_width
+ (EContentEditor *editor,
+ gint value);
+
+gint32 e_content_editor_image_get_width
+ (EContentEditor *editor);
+
+gint32 e_content_editor_image_get_natural_width
+ (EContentEditor *editor);
+
+void e_content_editor_image_set_width_follow
+ (EContentEditor *editor,
+ gboolean value);
+void e_content_editor_image_set_height
+ (EContentEditor *editor,
+ gint value);
+
+gint32 e_content_editor_image_get_height
+ (EContentEditor *editor);
+
+gint32 e_content_editor_image_get_natural_height
+ (EContentEditor *editor);
+
+void e_content_editor_image_set_height_follow
+ (EContentEditor *editor,
+ gboolean value);
+
+void e_content_editor_on_link_dialog_open
+ (EContentEditor *editor);
+
+void e_content_editor_on_link_dialog_close
+ (EContentEditor *editor);
+
+void e_content_editor_link_get_values
+ (EContentEditor *editor,
+ gchar **href,
+ gchar **text);
+
+void e_content_editor_link_set_values
+ (EContentEditor *editor,
+ const gchar *href,
+ const gchar *text);
+
+void e_content_editor_page_set_text_color
+ (EContentEditor *editor,
+ const GdkRGBA *value);
+
+void e_content_editor_on_page_dialog_open
+ (EContentEditor *editor);
+
+void e_content_editor_on_page_dialog_close
+ (EContentEditor *editor);
+
+void e_content_editor_page_get_text_color
+ (EContentEditor *editor,
+ GdkRGBA *value);
+
+void e_content_editor_page_set_background_color
+ (EContentEditor *editor,
+ const GdkRGBA *value);
+
+void e_content_editor_page_get_background_color
+ (EContentEditor *editor,
+ GdkRGBA *value);
+
+void e_content_editor_page_set_link_color
+ (EContentEditor *editor,
+ const GdkRGBA *value);
+
+void e_content_editor_page_get_link_color
+ (EContentEditor *editor,
+ GdkRGBA *value);
+
+void e_content_editor_page_set_visited_link_color
+ (EContentEditor *editor,
+ const GdkRGBA *value);
+
+void e_content_editor_page_get_visited_link_color
+ (EContentEditor *editor,
+ GdkRGBA *value);
+
+void e_content_editor_page_set_background_image_uri
+ (EContentEditor *editor,
+ const gchar *uri);
+
+gchar * e_content_editor_page_get_background_image_uri
+ (EContentEditor *editor);
+
+void e_content_editor_on_cell_dialog_open
+ (EContentEditor *editor);
+
+void e_content_editor_on_cell_dialog_close
+ (EContentEditor *editor);
+
+void e_content_editor_cell_set_v_align
+ (EContentEditor *editor,
+ const gchar *value,
+ EContentEditorScope scope);
+
+gchar * e_content_editor_cell_get_v_align
+ (EContentEditor *editor);
+
+void e_content_editor_cell_set_align (EContentEditor *editor,
+ const gchar *value,
+ EContentEditorScope scope);
+
+gchar * e_content_editor_cell_get_align (EContentEditor *editor);
+
+void e_content_editor_cell_set_wrap (EContentEditor *editor,
+ gboolean value,
+ EContentEditorScope scope);
+
+gboolean e_content_editor_cell_get_wrap (EContentEditor *editor);
+
+void e_content_editor_cell_set_header_style
+ (EContentEditor *editor,
+ gboolean value,
+ EContentEditorScope scope);
+
+gboolean e_content_editor_cell_is_header (EContentEditor *editor);
+
+void e_content_editor_cell_set_width (EContentEditor *editor,
+ gint value,
+ EContentEditorUnit unit,
+ EContentEditorScope scope);
+
+gint e_content_editor_cell_get_width (EContentEditor *editor,
+ EContentEditorUnit *unit);
+
+void e_content_editor_cell_set_row_span
+ (EContentEditor *editor,
+ gint value,
+ EContentEditorScope scope);
+
+gint e_content_editor_cell_get_row_span
+ (EContentEditor *editor);
+
+void e_content_editor_cell_set_col_span
+ (EContentEditor *editor,
+ gint value,
+ EContentEditorScope scope);
+
+gint e_content_editor_cell_get_col_span
+ (EContentEditor *editor);
+
+void e_content_editor_cell_set_background_image_uri
+ (EContentEditor *editor,
+ const gchar *uri);
+
+gchar * e_content_editor_cell_get_background_image_uri
+ (EContentEditor *editor);
+
+void e_content_editor_cell_set_background_color
+ (EContentEditor *editor,
+ const GdkRGBA *value,
+ EContentEditorScope scope);
+
+void e_content_editor_cell_get_background_color
+ (EContentEditor *editor,
+ GdkRGBA *value);
+
+void e_content_editor_table_set_row_count
+ (EContentEditor *editor,
+ guint value);
+
+guint e_content_editor_table_get_row_count
+ (EContentEditor *editor);
+
+void e_content_editor_table_set_column_count
+ (EContentEditor *editor,
+ guint value);
+
+guint e_content_editor_table_get_column_count
+ (EContentEditor *editor);
+
+void e_content_editor_table_set_width
+ (EContentEditor *editor,
+ gint value,
+ EContentEditorUnit unit);
+
+guint e_content_editor_table_get_width
+ (EContentEditor *editor,
+ EContentEditorUnit *unit);
+
+void e_content_editor_table_set_align
+ (EContentEditor *editor,
+ const gchar *value);
+
+gchar * e_content_editor_table_get_align
+ (EContentEditor *editor);
+
+void e_content_editor_table_set_padding
+ (EContentEditor *editor,
+ gint value);
+
+gint e_content_editor_table_get_padding
+ (EContentEditor *editor);
+
+void e_content_editor_table_set_spacing
+ (EContentEditor *editor,
+ gint value);
+
+gint e_content_editor_table_get_spacing
+ (EContentEditor *editor);
+
+void e_content_editor_table_set_border
+ (EContentEditor *editor,
+ gint value);
+
+gint e_content_editor_table_get_border
+ (EContentEditor *editor);
+
+gchar * e_content_editor_table_get_background_image_uri
+ (EContentEditor *editor);
+
+void e_content_editor_table_set_background_image_uri
+ (EContentEditor *editor,
+ const gchar *uri);
+
+void e_content_editor_table_get_background_color
+ (EContentEditor *editor,
+ GdkRGBA *value);
+
+void e_content_editor_table_set_background_color
+ (EContentEditor *editor,
+ const GdkRGBA *value);
+
+gboolean e_content_editor_on_table_dialog_open
+ (EContentEditor *editor);
+
+void e_content_editor_on_table_dialog_close
+ (EContentEditor *editor);
+
+void e_content_editor_on_spell_check_dialog_open
+ (EContentEditor *editor);
+
+void e_content_editor_on_spell_check_dialog_close
+ (EContentEditor *editor);
+
+gchar * e_content_editor_spell_check_next_word
+ (EContentEditor *editor,
+ const gchar *word);
+
+gchar * e_content_editor_spell_check_prev_word
+ (EContentEditor *editor,
+ const gchar *word);
+
+void e_content_editor_spell_check_replace_all
+ (EContentEditor *editor,
+ const gchar *word,
+ const gchar *replacement);
+
+void e_content_editor_on_replace_dialog_open
+ (EContentEditor *editor);
+
+void e_content_editor_on_replace_dialog_close
+ (EContentEditor *editor);
+
+void e_content_editor_on_find_dialog_open
+ (EContentEditor *editor);
+
+void e_content_editor_on_find_dialog_close
+ (EContentEditor *editor);
+
+/* Signal helpers */
+
+void e_content_editor_emit_load_finished
+ (EContentEditor *editor);
+gboolean e_content_editor_emit_paste_clipboard
+ (EContentEditor *editor);
+gboolean e_content_editor_emit_paste_primary_clipboard
+ (EContentEditor *editor);
+gboolean e_content_editor_emit_context_menu_requested
+ (EContentEditor *editor,
+ EContentEditorNodeFlags flags,
+ GdkEvent *event);
+void e_content_editor_emit_find_done (EContentEditor *editor,
+ guint match_count);
+void e_content_editor_emit_replace_all_done
+ (EContentEditor *editor,
+ guint replaced_count);
+
+G_END_DECLS
+
+#endif /* E_CONTENT_EDITOR_H */
diff --git a/e-util/e-content-request.c b/e-util/e-content-request.c
new file mode 100644
index 0000000..9448d44
--- /dev/null
+++ b/e-util/e-content-request.c
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2016 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library 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.
+ *
+ * This library 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 this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gio/gio.h>
+
+#include "e-content-request.h"
+
+G_DEFINE_INTERFACE (EContentRequest, e_content_request, G_TYPE_OBJECT)
+
+static void
+e_content_request_default_init (EContentRequestInterface *iface)
+{
+}
+
+gboolean
+e_content_request_can_process_uri (EContentRequest *request,
+ const gchar *uri)
+{
+ EContentRequestInterface *iface;
+
+ g_return_val_if_fail (E_IS_CONTENT_REQUEST (request), FALSE);
+ g_return_val_if_fail (uri != NULL, FALSE);
+
+ iface = E_CONTENT_REQUEST_GET_INTERFACE (request);
+ g_return_val_if_fail (iface != NULL, FALSE);
+ g_return_val_if_fail (iface->can_process_uri != NULL, FALSE);
+
+ return iface->can_process_uri (request, uri);
+}
+
+gboolean
+e_content_request_process_sync (EContentRequest *request,
+ const gchar *uri,
+ GObject *requester,
+ GInputStream **out_stream,
+ gint64 *out_stream_length,
+ gchar **out_mime_type,
+ GCancellable *cancellable,
+ GError **error)
+{
+ EContentRequestInterface *iface;
+ GError *local_error = NULL;
+
+ g_return_val_if_fail (E_IS_CONTENT_REQUEST (request), FALSE);
+ g_return_val_if_fail (uri != NULL, FALSE);
+ g_return_val_if_fail (G_IS_OBJECT (requester), FALSE);
+ g_return_val_if_fail (out_stream != NULL, FALSE);
+ g_return_val_if_fail (out_stream_length != NULL, FALSE);
+ g_return_val_if_fail (out_mime_type != NULL, FALSE);
+
+ iface = E_CONTENT_REQUEST_GET_INTERFACE (request);
+ g_return_val_if_fail (iface != NULL, FALSE);
+ g_return_val_if_fail (iface->process_sync != NULL, FALSE);
+
+ if (!iface->process_sync (request, uri, requester, out_stream, out_stream_length, out_mime_type,
cancellable, &local_error)) {
+ if (!local_error)
+ local_error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_FAILED, g_strerror
(ENOENT));
+
+ g_propagate_error (error, local_error);
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+typedef struct _ThreadData
+{
+ gchar *uri;
+ GObject *requester;
+ GInputStream *out_stream;
+ gint64 out_stream_length;
+ gchar *out_mime_type;
+} ThreadData;
+
+static void
+thread_data_free (gpointer ptr)
+{
+ ThreadData *td = ptr;
+
+ if (td) {
+ g_clear_object (&td->out_stream);
+ g_clear_object (&td->requester);
+ g_free (td->uri);
+ g_free (td->out_mime_type);
+ g_free (td);
+ }
+}
+
+static void
+content_request_process_thread (GTask *task,
+ gpointer source_object,
+ gpointer task_data,
+ GCancellable *cancellable)
+{
+ ThreadData *td = task_data;
+ GError *local_error = NULL;
+
+ g_return_if_fail (E_IS_CONTENT_REQUEST (source_object));
+ g_return_if_fail (td != NULL);
+
+ if (!e_content_request_process_sync (E_CONTENT_REQUEST (source_object),
+ td->uri, td->requester, &td->out_stream, &td->out_stream_length, &td->out_mime_type,
+ cancellable, &local_error)) {
+ g_task_return_error (task, local_error);
+ } else {
+ g_task_return_boolean (task, TRUE);
+ }
+}
+
+void
+e_content_request_process (EContentRequest *request,
+ const gchar *uri,
+ GObject *requester,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask *task;
+ ThreadData *td;
+
+ g_return_if_fail (E_IS_CONTENT_REQUEST (request));
+ g_return_if_fail (uri != NULL);
+ g_return_if_fail (G_IS_OBJECT (requester));
+
+ td = g_new0 (ThreadData, 1);
+ td->uri = g_strdup (uri);
+ td->requester = g_object_ref (requester);
+
+ task = g_task_new (request, cancellable, callback, user_data);
+ g_task_set_task_data (task, td, thread_data_free);
+ g_task_run_in_thread (task, content_request_process_thread);
+ g_object_unref (task);
+}
+
+gboolean
+e_content_request_process_finish (EContentRequest *request,
+ GAsyncResult *result,
+ GInputStream **out_stream,
+ gint64 *out_stream_length,
+ gchar **out_mime_type,
+ GError **error)
+{
+ ThreadData *td;
+
+ g_return_val_if_fail (g_task_is_valid (result, request), FALSE);
+ g_return_val_if_fail (E_IS_CONTENT_REQUEST (request), FALSE);
+ g_return_val_if_fail (G_IS_TASK (result), FALSE);
+ g_return_val_if_fail (out_stream != NULL, FALSE);
+ g_return_val_if_fail (out_stream_length != NULL, FALSE);
+ g_return_val_if_fail (out_mime_type != NULL, FALSE);
+
+ td = g_task_get_task_data (G_TASK (result));
+ g_return_val_if_fail (td != NULL, FALSE);
+
+ if (!g_task_propagate_boolean (G_TASK (result), error))
+ return FALSE;
+
+ *out_stream = td->out_stream;
+ *out_stream_length = td->out_stream_length;
+ *out_mime_type = td->out_mime_type;
+
+ td->out_stream = NULL;
+ td->out_mime_type = NULL;
+
+ return TRUE;
+}
diff --git a/e-util/e-content-request.h b/e-util/e-content-request.h
new file mode 100644
index 0000000..7df94c4
--- /dev/null
+++ b/e-util/e-content-request.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2016 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library 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.
+ *
+ * This library 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 this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#if !defined (__E_UTIL_H_INSIDE__) && !defined (LIBEUTIL_COMPILATION)
+#error "Only <e-util/e-util.h> should be included directly."
+#endif
+
+#ifndef E_CONTENT_REQUEST_H
+#define E_CONTENT_REQUEST_H
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gio/gio.h>
+
+/* Standard GObject macros */
+#define E_TYPE_CONTENT_REQUEST \
+ (e_content_request_get_type ())
+#define E_CONTENT_REQUEST(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_CONTENT_REQUEST, EContentRequest))
+#define E_CONTENT_REQUEST_INTERFACE(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_CONTENT_REQUEST, EContentRequestInterface))
+#define E_IS_CONTENT_REQUEST(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_CONTENT_REQUEST))
+#define E_IS_CONTENT_REQUEST_INTERFACE(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_CONTENT_REQUEST))
+#define E_CONTENT_REQUEST_GET_INTERFACE(obj) \
+ (G_TYPE_INSTANCE_GET_INTERFACE \
+ ((obj), E_TYPE_CONTENT_REQUEST, EContentRequestInterface))
+
+G_BEGIN_DECLS
+
+typedef struct _EContentRequest EContentRequest;
+typedef struct _EContentRequestInterface EContentRequestInterface;
+
+struct _EContentRequestInterface {
+ GTypeInterface parent_interface;
+
+ gboolean (* can_process_uri) (EContentRequest *request,
+ const gchar *uri);
+ gboolean (* process_sync) (EContentRequest *request,
+ const gchar *uri,
+ GObject *requester,
+ GInputStream **out_stream,
+ gint64 *out_stream_length,
+ gchar **out_mime_type,
+ GCancellable *cancellable,
+ GError **error);
+};
+
+GType e_content_request_get_type (void);
+gboolean e_content_request_can_process_uri (EContentRequest *request,
+ const gchar *uri);
+gboolean e_content_request_process_sync (EContentRequest *request,
+ const gchar *uri,
+ GObject *requester,
+ GInputStream **out_stream,
+ gint64 *out_stream_length,
+ gchar **out_mime_type,
+ GCancellable *cancellable,
+ GError **error);
+void e_content_request_process (EContentRequest *request,
+ const gchar *uri,
+ GObject *requester,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean e_content_request_process_finish (EContentRequest *request,
+ GAsyncResult *result,
+ GInputStream **out_stream,
+ gint64 *out_stream_length,
+ gchar **out_mime_type,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* E_CONTENT_REQUEST_H */
diff --git a/e-util/e-emoticon.c b/e-util/e-emoticon.c
index cc2fd41..53a9f49 100644
--- a/e-util/e-emoticon.c
+++ b/e-util/e-emoticon.c
@@ -121,3 +121,9 @@ e_emoticon_get_uri (EEmoticon *emoticon)
return uri;
}
+
+const gchar *
+e_emoticon_get_name (EEmoticon *emoticon)
+{
+ return emoticon->icon_name;
+}
diff --git a/e-util/e-emoticon.h b/e-util/e-emoticon.h
index e77806f..3b9e8c0 100644
--- a/e-util/e-emoticon.h
+++ b/e-util/e-emoticon.h
@@ -48,6 +48,7 @@ gboolean e_emoticon_equal (EEmoticon *emoticon_a,
EEmoticon * e_emoticon_copy (EEmoticon *emoticon);
void e_emoticon_free (EEmoticon *emoticon);
gchar * e_emoticon_get_uri (EEmoticon *emoticon);
+const gchar * e_emoticon_get_name (EEmoticon *emoticon);
G_END_DECLS
diff --git a/e-util/e-file-request.c b/e-util/e-file-request.c
index f6b4ac2..8cdb18a 100644
--- a/e-util/e-file-request.c
+++ b/e-util/e-file-request.c
@@ -15,178 +15,124 @@
*
*/
-#define LIBSOUP_USE_UNSTABLE_REQUEST_API
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
-#include "e-file-request.h"
+#include <stdio.h>
+#include <string.h>
#include <libsoup/soup.h>
-#include <stdio.h>
-#include <string.h>
+#include "e-file-request.h"
#define d(x)
-#define E_FILE_REQUEST_GET_PRIVATE(obj) \
- (G_TYPE_INSTANCE_GET_PRIVATE \
- ((obj), E_TYPE_FILE_REQUEST, EFileRequestPrivate))
-
struct _EFileRequestPrivate {
- gchar *content_type;
- gint content_length;
+ gint dummy;
};
-G_DEFINE_TYPE (EFileRequest, e_file_request, SOUP_TYPE_REQUEST)
-
-static void
-handle_file_request (GSimpleAsyncResult *res,
- GObject *object,
- GCancellable *cancellable)
-{
- EFileRequest *request = E_FILE_REQUEST (object);
- SoupURI *uri;
- GInputStream *stream;
- gchar *contents;
- gsize length;
-
- if (g_cancellable_is_cancelled (cancellable))
- return;
-
- uri = soup_request_get_uri (SOUP_REQUEST (request));
-
- if (g_file_get_contents (uri->path, &contents, &length, NULL)) {
+static void e_file_request_content_request_init (EContentRequestInterface *iface);
- request->priv->content_type =
- g_content_type_guess (uri->path, NULL, 0, NULL);
- request->priv->content_length = length;
-
- stream = g_memory_input_stream_new_from_data (
- contents, length, (GDestroyNotify) g_free);
- g_simple_async_result_set_op_res_gpointer (res, stream, g_object_unref);
- }
-}
-
-static void
-file_request_finalize (GObject *object)
-{
- EFileRequest *request = E_FILE_REQUEST (object);
-
- if (request->priv->content_type) {
- g_free (request->priv->content_type);
- request->priv->content_type = NULL;
- }
-
- G_OBJECT_CLASS (e_file_request_parent_class)->finalize (object);
-}
+G_DEFINE_TYPE_WITH_CODE (EFileRequest, e_file_request, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (E_TYPE_CONTENT_REQUEST, e_file_request_content_request_init))
static gboolean
-file_request_check_uri (SoupRequest *request,
- SoupURI *uri,
- GError **error)
-{
- return (strcmp (uri->scheme, "evo-file") == 0);
-}
-
-static void
-file_request_send_async (SoupRequest *request,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
+e_file_request_can_process_uri (EContentRequest *request,
+ const gchar *uri)
{
- GSimpleAsyncResult *simple;
-
- d (
- SoupURI *soup_uri = soup_request_get_uri (request);
- gchar *uri = soup_uri_to_string (soup_uri, FALSE);
- printf ("received request for %s\n", uri);
- g_free (uri);
- );
-
- /* WebKit won't allow us to load data through local file:// protocol
- * when using "remote" mail:// protocol, so we have evo-file://
- * which WebKit thinks it's remote, but in fact it behaves like
- * oridnary file:// */
-
- simple = g_simple_async_result_new (
- G_OBJECT (request), callback, user_data,
- file_request_send_async);
-
- g_simple_async_result_set_check_cancellable (simple, cancellable);
-
- g_simple_async_result_run_in_thread (
- simple, handle_file_request,
- G_PRIORITY_DEFAULT, cancellable);
+ g_return_val_if_fail (E_IS_FILE_REQUEST (request), FALSE);
+ g_return_val_if_fail (uri != NULL, FALSE);
- g_object_unref (simple);
+ return g_ascii_strncasecmp (uri, "evo-file:", 9) == 0;
}
-static GInputStream *
-file_request_send_finish (SoupRequest *request,
- GAsyncResult *result,
- GError **error)
+static gboolean
+e_file_request_process_sync (EContentRequest *request,
+ const gchar *uri,
+ GObject *requester,
+ GInputStream **out_stream,
+ gint64 *out_stream_length,
+ gchar **out_mime_type,
+ GCancellable *cancellable,
+ GError **error)
{
- GSimpleAsyncResult *simple;
- GInputStream *stream;
-
- simple = G_SIMPLE_ASYNC_RESULT (result);
- stream = g_simple_async_result_get_op_res_gpointer (simple);
-
- /* Reset the stream before passing it back to webkit */
- if (stream && G_IS_SEEKABLE (stream))
- g_seekable_seek (G_SEEKABLE (stream), 0, G_SEEK_SET, NULL, NULL);
-
- if (!stream) /* We must always return something */
- stream = g_memory_input_stream_new ();
- else
- g_object_ref (stream);
-
- return stream;
-}
+ GFile *file;
+ GFileInputStream *file_input_stream;
+ GFileInfo *info;
+ goffset total_size;
+ SoupURI *suri;
+
+ g_return_val_if_fail (E_IS_FILE_REQUEST (request), FALSE);
+ g_return_val_if_fail (uri != NULL, FALSE);
+
+ if (g_cancellable_set_error_if_cancelled (cancellable, error))
+ return FALSE;
+
+ suri = soup_uri_new (uri);
+ g_return_val_if_fail (suri != NULL, FALSE);
+
+ file = g_file_new_for_path (suri->path);
+ file_input_stream = g_file_read (file, cancellable, error);
+
+ if (file_input_stream) {
+ total_size = -1;
+ info = g_file_input_stream_query_info (file_input_stream, G_FILE_ATTRIBUTE_STANDARD_SIZE,
cancellable, NULL);
+ if (info) {
+ if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_STANDARD_SIZE))
+ total_size = g_file_info_get_size (info);
+ g_object_unref (info);
+ }
+
+ if (total_size == -1) {
+ info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_SIZE,
G_FILE_QUERY_INFO_NONE, cancellable, NULL);
+ if (info) {
+ if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_STANDARD_SIZE))
+ total_size = g_file_info_get_size (info);
+ g_object_unref (info);
+ }
+ }
+ } else {
+ total_size = -1;
+ }
-static goffset
-file_request_get_content_length (SoupRequest *request)
-{
- EFileRequest *efr = E_FILE_REQUEST (request);
+ if (file_input_stream) {
+ *out_stream = G_INPUT_STREAM (file_input_stream);
+ *out_stream_length = (gint64) total_size;
+ *out_mime_type = g_content_type_guess (suri->path, NULL, 0, NULL);
+ } else {
+ *out_stream = NULL;
+ *out_stream_length = (gint64) total_size;
+ *out_mime_type = NULL;
+ }
- d (printf ("Content-Length: %d bytes\n", efr->priv->content_length));
+ g_object_unref (file);
+ soup_uri_free (suri);
- return efr->priv->content_length;
+ return file_input_stream != NULL;
}
-static const gchar *
-file_request_get_content_type (SoupRequest *request)
+static void
+e_file_request_content_request_init (EContentRequestInterface *iface)
{
- EFileRequest *efr = E_FILE_REQUEST (request);
-
- d (printf ("Content-Type: %s\n", efr->priv->content_type));
-
- return efr->priv->content_type;
+ iface->can_process_uri = e_file_request_can_process_uri;
+ iface->process_sync = e_file_request_process_sync;
}
-static const gchar *data_schemes[] = { "evo-file", NULL };
-
static void
e_file_request_class_init (EFileRequestClass *class)
{
- GObjectClass *object_class;
- SoupRequestClass *request_class;
-
g_type_class_add_private (class, sizeof (EFileRequestPrivate));
-
- object_class = G_OBJECT_CLASS (class);
- object_class->finalize = file_request_finalize;
-
- request_class = SOUP_REQUEST_CLASS (class);
- request_class->schemes = data_schemes;
- request_class->send_async = file_request_send_async;
- request_class->send_finish = file_request_send_finish;
- request_class->get_content_type = file_request_get_content_type;
- request_class->get_content_length = file_request_get_content_length;
- request_class->check_uri = file_request_check_uri;
}
static void
e_file_request_init (EFileRequest *request)
{
- request->priv = E_FILE_REQUEST_GET_PRIVATE (request);
+ request->priv = G_TYPE_INSTANCE_GET_PRIVATE (request, E_TYPE_FILE_REQUEST, EFileRequestPrivate);
}
+EContentRequest *
+e_file_request_new (void)
+{
+ return g_object_new (E_TYPE_FILE_REQUEST, NULL);
+}
diff --git a/e-util/e-file-request.h b/e-util/e-file-request.h
index ab46c9a..706309d 100644
--- a/e-util/e-file-request.h
+++ b/e-util/e-file-request.h
@@ -22,10 +22,7 @@
#ifndef E_FILE_REQUEST_H
#define E_FILE_REQUEST_H
-#define LIBSOUP_USE_UNSTABLE_REQUEST_API
-
-#include <libsoup/soup.h>
-#include <libsoup/soup-request.h>
+#include <e-util/e-content-request.h>
/* Standard GObject macros */
#define E_TYPE_FILE_REQUEST \
@@ -53,15 +50,17 @@ typedef struct _EFileRequestClass EFileRequestClass;
typedef struct _EFileRequestPrivate EFileRequestPrivate;
struct _EFileRequest {
- SoupRequest parent;
+ GObject parent;
EFileRequestPrivate *priv;
};
struct _EFileRequestClass {
- SoupRequestClass parent;
+ GObjectClass parent;
};
GType e_file_request_get_type (void) G_GNUC_CONST;
+EContentRequest *
+ e_file_request_new (void);
G_END_DECLS
diff --git a/e-util/e-focus-tracker.c b/e-util/e-focus-tracker.c
index 7a9477a..794e56d 100644
--- a/e-util/e-focus-tracker.c
+++ b/e-util/e-focus-tracker.c
@@ -28,7 +28,7 @@
#include "e-selectable.h"
#include "e-widget-undo.h"
-#include "e-html-editor-view.h"
+#include "e-content-editor.h"
#define E_FOCUS_TRACKER_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE \
@@ -257,7 +257,7 @@ focus_tracker_text_view_update_actions (EFocusTracker *focus_tracker,
static void
focus_tracker_editor_update_actions (EFocusTracker *focus_tracker,
- EHTMLEditorView *view,
+ EContentEditor *cnt_editor,
GdkAtom *targets,
gint n_targets)
{
@@ -266,7 +266,7 @@ focus_tracker_editor_update_actions (EFocusTracker *focus_tracker,
gboolean can_cut;
gboolean can_paste;
- g_object_get (view,
+ g_object_get (cnt_editor,
"can-copy", &can_copy,
"can-cut", &can_cut,
"can-paste", &can_paste,
@@ -368,9 +368,9 @@ focus_tracker_targets_received_cb (GtkClipboard *clipboard,
focus_tracker, GTK_TEXT_VIEW (focus),
targets, n_targets);
- else if (E_IS_HTML_EDITOR_VIEW (focus))
+ else if (E_IS_CONTENT_EDITOR (focus))
focus_tracker_editor_update_actions (
- focus_tracker, E_HTML_EDITOR_VIEW (focus),
+ focus_tracker, E_CONTENT_EDITOR (focus),
targets, n_targets);
g_object_unref (focus_tracker);
@@ -391,7 +391,7 @@ focus_tracker_set_focus_cb (GtkWindow *window,
if (GTK_IS_TEXT_VIEW (focus))
break;
- if (E_IS_HTML_EDITOR_VIEW (focus))
+ if (E_IS_CONTENT_EDITOR (focus))
break;
focus = gtk_widget_get_parent (focus);
diff --git a/e-util/e-html-editor-actions.c b/e-util/e-html-editor-actions.c
index 638b05c..aaf9dd7 100644
--- a/e-util/e-html-editor-actions.c
+++ b/e-util/e-html-editor-actions.c
@@ -29,20 +29,20 @@
#include "e-html-editor.h"
#include "e-html-editor-private.h"
#include "e-html-editor-actions.h"
-#include "e-html-editor-utils.h"
#include "e-emoticon-action.h"
#include "e-emoticon-chooser.h"
#include "e-image-chooser-dialog.h"
#include "e-spell-checker.h"
#include "e-misc-utils.h"
-#include "e-web-view.h"
+#include "e-selection.h"
+#include "e-content-editor.h"
static void
insert_html_file_ready_cb (GFile *file,
GAsyncResult *result,
EHTMLEditor *editor)
{
- EHTMLEditorSelection *selection;
+ EContentEditor *cnt_editor;
gchar *contents = NULL;
gsize length;
GError *error = NULL;
@@ -66,9 +66,10 @@ insert_html_file_ready_cb (GFile *file,
return;
}
- selection = e_html_editor_view_get_selection (
- e_html_editor_get_view (editor));
- e_html_editor_selection_insert_html (selection, contents);
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ e_content_editor_insert_content (
+ cnt_editor, contents, E_CONTENT_EDITOR_INSERT_TEXT_HTML);
+
g_free (contents);
g_object_unref (editor);
@@ -79,7 +80,7 @@ insert_text_file_ready_cb (GFile *file,
GAsyncResult *result,
EHTMLEditor *editor)
{
- EHTMLEditorSelection *selection;
+ EContentEditor *cnt_editor;
gchar *contents;
gsize length;
GError *error = NULL;
@@ -103,9 +104,10 @@ insert_text_file_ready_cb (GFile *file,
return;
}
- selection = e_html_editor_view_get_selection (
- e_html_editor_get_view (editor));
- e_html_editor_selection_insert_text (selection, contents);
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ e_content_editor_insert_content (
+ cnt_editor, contents, E_CONTENT_EDITOR_INSERT_TEXT_PLAIN);
+
g_free (contents);
g_object_unref (editor);
@@ -116,464 +118,172 @@ insert_text_file_ready_cb (GFile *file,
*****************************************************************************/
static void
-prepare_history_for_table (EHTMLEditor *editor,
- WebKitDOMElement *table,
- EHTMLEditorViewHistoryEvent *ev)
-{
- EHTMLEditorSelection *selection;
- EHTMLEditorView *view;
-
- view = e_html_editor_get_view (editor);
- selection = e_html_editor_view_get_selection (view);
-
- ev->type = HISTORY_TABLE_DIALOG;
-
- e_html_editor_selection_get_selection_coordinates (
- selection, &ev->before.start.x, &ev->before.start.y, &ev->before.end.x, &ev->before.end.y);
- ev->data.dom.from = webkit_dom_node_clone_node (
- WEBKIT_DOM_NODE (table), TRUE);
-}
-
-static void
-save_history_for_table (EHTMLEditor *editor,
- WebKitDOMElement *table,
- EHTMLEditorViewHistoryEvent *ev)
-{
- EHTMLEditorSelection *selection;
- EHTMLEditorView *view;
-
- view = e_html_editor_get_view (editor);
- selection = e_html_editor_view_get_selection (view);
-
- if (table)
- ev->data.dom.to = webkit_dom_node_clone_node (
- WEBKIT_DOM_NODE (table), TRUE);
- else
- ev->data.dom.to = NULL;
- e_html_editor_selection_get_selection_coordinates (
- selection, &ev->after.start.x, &ev->after.start.y, &ev->after.end.x, &ev->after.end.y);
- e_html_editor_view_insert_new_history_event (view, ev);
-}
-
-static void
action_context_delete_cell_contents_cb (GtkAction *action,
- EHTMLEditor *editor)
+ EHTMLEditor *editor)
{
- EHTMLEditorViewHistoryEvent *ev = NULL;
- WebKitDOMNode *node;
- WebKitDOMElement *cell, *table;
-
- g_return_if_fail (editor->priv->table_cell != NULL);
+ EContentEditor *cnt_editor;
- cell = e_html_editor_dom_node_find_parent_element (editor->priv->table_cell, "TD");
- if (!cell) {
- cell = e_html_editor_dom_node_find_parent_element (
- editor->priv->table_cell, "TH");
- }
- g_return_if_fail (cell != NULL);
-
- table = e_html_editor_dom_node_find_parent_element (WEBKIT_DOM_NODE (cell), "TABLE");
- g_return_if_fail (table != NULL);
-
- ev = g_new0 (EHTMLEditorViewHistoryEvent, 1);
- prepare_history_for_table (editor, table, ev);
-
- while ((node = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (cell))))
- remove_node (node);
-
- save_history_for_table (editor, table, ev);
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ e_content_editor_delete_cell_contents (cnt_editor);
}
static void
action_context_delete_column_cb (GtkAction *action,
EHTMLEditor *editor)
{
- EHTMLEditorViewHistoryEvent *ev = NULL;
- WebKitDOMElement *cell, *table;
- WebKitDOMHTMLCollection *rows;
- gulong index, length, ii;
-
- g_return_if_fail (editor->priv->table_cell != NULL);
-
- /* Find TD in which the selection starts */
- cell = e_html_editor_dom_node_find_parent_element (editor->priv->table_cell, "TD");
- if (!cell) {
- cell = e_html_editor_dom_node_find_parent_element (
- editor->priv->table_cell, "TH");
- }
- g_return_if_fail (cell != NULL);
+ EContentEditor *cnt_editor;
- table = e_html_editor_dom_node_find_parent_element (WEBKIT_DOM_NODE (cell), "TABLE");
- g_return_if_fail (table != NULL);
-
- ev = g_new0 (EHTMLEditorViewHistoryEvent, 1);
- prepare_history_for_table (editor, table, ev);
-
- rows = webkit_dom_html_table_element_get_rows (
- WEBKIT_DOM_HTML_TABLE_ELEMENT (table));
- length = webkit_dom_html_collection_get_length (rows);
-
- index = webkit_dom_html_table_cell_element_get_cell_index (
- WEBKIT_DOM_HTML_TABLE_CELL_ELEMENT (cell));
-
- for (ii = 0; ii < length; ii++) {
- WebKitDOMNode *row;
-
- row = webkit_dom_html_collection_item (rows, ii);
-
- webkit_dom_html_table_row_element_delete_cell (
- WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (row), index, NULL);
- g_object_unref (row);
- }
- g_object_unref (rows);
-
- save_history_for_table (editor, table, ev);
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ e_content_editor_delete_column (cnt_editor);
}
static void
action_context_delete_row_cb (GtkAction *action,
EHTMLEditor *editor)
{
- EHTMLEditorViewHistoryEvent *ev = NULL;
- WebKitDOMElement *row, *table;
-
- g_return_if_fail (editor->priv->table_cell != NULL);
-
- row = e_html_editor_dom_node_find_parent_element (editor->priv->table_cell, "TR");
- g_return_if_fail (row != NULL);
-
- table = e_html_editor_dom_node_find_parent_element (editor->priv->table_cell, "TABLE");
- g_return_if_fail (table != NULL);
+ EContentEditor *cnt_editor;
- ev = g_new0 (EHTMLEditorViewHistoryEvent, 1);
- prepare_history_for_table (editor, table, ev);
-
- remove_node (WEBKIT_DOM_NODE (row));
-
- save_history_for_table (editor, table, ev);
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ e_content_editor_delete_row (cnt_editor);
}
static void
action_context_delete_table_cb (GtkAction *action,
EHTMLEditor *editor)
{
- WebKitDOMElement *table;
- EHTMLEditorViewHistoryEvent *ev = NULL;
-
- g_return_if_fail (editor->priv->table_cell != NULL);
-
- table = e_html_editor_dom_node_find_parent_element (editor->priv->table_cell, "TABLE");
- g_return_if_fail (table != NULL);
-
- ev = g_new0 (EHTMLEditorViewHistoryEvent, 1);
- prepare_history_for_table (editor, table, ev);
-
- remove_node (WEBKIT_DOM_NODE (table));
+ EContentEditor *cnt_editor;
- save_history_for_table (editor, NULL, ev);
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ e_content_editor_delete_table (cnt_editor);
}
static void
action_context_insert_column_after_cb (GtkAction *action,
EHTMLEditor *editor)
{
- EHTMLEditorViewHistoryEvent *ev = NULL;
- WebKitDOMElement *cell, *row, *table;
- gulong index;
-
- g_return_if_fail (editor->priv->table_cell != NULL);
-
- cell = e_html_editor_dom_node_find_parent_element (editor->priv->table_cell, "TD");
- if (!cell) {
- cell = e_html_editor_dom_node_find_parent_element (
- editor->priv->table_cell, "TH");
- }
- g_return_if_fail (cell != NULL);
-
- row = e_html_editor_dom_node_find_parent_element (WEBKIT_DOM_NODE (cell), "TR");
- g_return_if_fail (row != NULL);
-
- table = e_html_editor_dom_node_find_parent_element (editor->priv->table_cell, "TABLE");
- g_return_if_fail (table != NULL);
+ EContentEditor *cnt_editor;
- ev = g_new0 (EHTMLEditorViewHistoryEvent, 1);
- prepare_history_for_table (editor, table, ev);
-
- /* Get the first row in the table */
- row = WEBKIT_DOM_ELEMENT (
- webkit_dom_node_get_first_child (
- webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (row))));
-
- index = webkit_dom_html_table_cell_element_get_cell_index (
- WEBKIT_DOM_HTML_TABLE_CELL_ELEMENT (cell));
-
- while (row) {
- webkit_dom_html_table_row_element_insert_cell (
- WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (row), index + 1, NULL);
-
- row = WEBKIT_DOM_ELEMENT (
- webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (row)));
- }
-
- save_history_for_table (editor, table, ev);
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ e_content_editor_insert_column_after (cnt_editor);
}
static void
action_context_insert_column_before_cb (GtkAction *action,
EHTMLEditor *editor)
{
- EHTMLEditorViewHistoryEvent *ev = NULL;
- WebKitDOMElement *cell, *row, *table;
- gulong index;
-
- g_return_if_fail (editor->priv->table_cell != NULL);
-
- cell = e_html_editor_dom_node_find_parent_element (editor->priv->table_cell, "TD");
- if (!cell) {
- cell = e_html_editor_dom_node_find_parent_element (
- editor->priv->table_cell, "TH");
- }
- g_return_if_fail (cell != NULL);
-
- row = e_html_editor_dom_node_find_parent_element (WEBKIT_DOM_NODE (cell), "TR");
- g_return_if_fail (row != NULL);
-
- table = e_html_editor_dom_node_find_parent_element (editor->priv->table_cell, "TABLE");
- g_return_if_fail (table != NULL);
+ EContentEditor *cnt_editor;
- ev = g_new0 (EHTMLEditorViewHistoryEvent, 1);
- prepare_history_for_table (editor, table, ev);
-
- /* Get the first row in the table */
- row = WEBKIT_DOM_ELEMENT (
- webkit_dom_node_get_first_child (
- webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (row))));
-
- index = webkit_dom_html_table_cell_element_get_cell_index (
- WEBKIT_DOM_HTML_TABLE_CELL_ELEMENT (cell));
-
- while (row) {
- webkit_dom_html_table_row_element_insert_cell (
- WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (row), index - 1, NULL);
-
- row = WEBKIT_DOM_ELEMENT (
- webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (row)));
- }
-
- save_history_for_table (editor, table, ev);
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ e_content_editor_insert_column_before (cnt_editor);
}
static void
action_context_insert_row_above_cb (GtkAction *action,
EHTMLEditor *editor)
{
- EHTMLEditorViewHistoryEvent *ev = NULL;
- WebKitDOMElement *row, *table;
- WebKitDOMHTMLCollection *cells;
- WebKitDOMHTMLElement *new_row;
- gulong index, cell_count, ii;
-
- g_return_if_fail (editor->priv->table_cell != NULL);
-
- row = e_html_editor_dom_node_find_parent_element (editor->priv->table_cell, "TR");
- g_return_if_fail (row != NULL);
-
- table = e_html_editor_dom_node_find_parent_element (WEBKIT_DOM_NODE (row), "TABLE");
- g_return_if_fail (table != NULL);
-
- ev = g_new0 (EHTMLEditorViewHistoryEvent, 1);
- prepare_history_for_table (editor, table, ev);
-
- index = webkit_dom_html_table_row_element_get_row_index (
- WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (row));
+ EContentEditor *cnt_editor;
- new_row = webkit_dom_html_table_element_insert_row (
- WEBKIT_DOM_HTML_TABLE_ELEMENT (table), index, NULL);
-
- cells = webkit_dom_html_table_row_element_get_cells (
- WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (row));
- cell_count = webkit_dom_html_collection_get_length (cells);
- for (ii = 0; ii < cell_count; ii++) {
- webkit_dom_html_table_row_element_insert_cell (
- WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (new_row), -1, NULL);
- }
- g_object_unref (cells);
-
- save_history_for_table (editor, table, ev);
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ e_content_editor_insert_row_above (cnt_editor);
}
static void
action_context_insert_row_below_cb (GtkAction *action,
EHTMLEditor *editor)
{
- EHTMLEditorViewHistoryEvent *ev = NULL;
- WebKitDOMElement *row, *table;
- WebKitDOMHTMLCollection *cells;
- WebKitDOMHTMLElement *new_row;
- gulong index, cell_count, ii;
-
- g_return_if_fail (editor->priv->table_cell != NULL);
-
- row = e_html_editor_dom_node_find_parent_element (editor->priv->table_cell, "TR");
- g_return_if_fail (row != NULL);
-
- table = e_html_editor_dom_node_find_parent_element (WEBKIT_DOM_NODE (row), "TABLE");
- g_return_if_fail (table != NULL);
-
- ev = g_new0 (EHTMLEditorViewHistoryEvent, 1);
- prepare_history_for_table (editor, table, ev);
-
- index = webkit_dom_html_table_row_element_get_row_index (
- WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (row));
-
- new_row = webkit_dom_html_table_element_insert_row (
- WEBKIT_DOM_HTML_TABLE_ELEMENT (table), index + 1, NULL);
-
- cells = webkit_dom_html_table_row_element_get_cells (
- WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (row));
- cell_count = webkit_dom_html_collection_get_length (cells);
- for (ii = 0; ii < cell_count; ii++) {
- webkit_dom_html_table_row_element_insert_cell (
- WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (new_row), -1, NULL);
- }
- g_object_unref (cells);
+ EContentEditor *cnt_editor;
- save_history_for_table (editor, table, ev);
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ e_content_editor_insert_row_below (cnt_editor);
}
static void
action_context_remove_link_cb (GtkAction *action,
EHTMLEditor *editor)
{
- EHTMLEditorView *view;
- EHTMLEditorSelection *selection;
+ EContentEditor *cnt_editor;
- view = e_html_editor_get_view (editor);
- selection = e_html_editor_view_get_selection (view);
-
- e_html_editor_selection_unlink (selection);
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ e_content_editor_selection_unlink (cnt_editor);
}
static void
action_context_spell_add_cb (GtkAction *action,
EHTMLEditor *editor)
{
+ EContentEditor *cnt_editor;
ESpellChecker *spell_checker;
- EHTMLEditorSelection *selection;
gchar *word;
- spell_checker = e_html_editor_view_get_spell_checker (
- editor->priv->html_editor_view);
- selection = e_html_editor_view_get_selection (editor->priv->html_editor_view);
-
- word = e_html_editor_selection_get_caret_word (selection);
- if (word && *word) {
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ spell_checker = e_content_editor_ref_spell_checker (cnt_editor);
+ word = e_content_editor_get_caret_word (cnt_editor);
+ if (word && *word)
e_spell_checker_learn_word (spell_checker, word);
- }
+ g_free (word);
+ g_clear_object (&spell_checker);
}
static void
action_context_spell_ignore_cb (GtkAction *action,
EHTMLEditor *editor)
{
+ EContentEditor *cnt_editor;
ESpellChecker *spell_checker;
- EHTMLEditorSelection *selection;
gchar *word;
- spell_checker = e_html_editor_view_get_spell_checker (
- editor->priv->html_editor_view);
- selection = e_html_editor_view_get_selection (editor->priv->html_editor_view);
-
- word = e_html_editor_selection_get_caret_word (selection);
- if (word && *word) {
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ spell_checker = e_content_editor_ref_spell_checker (cnt_editor);
+ word = e_content_editor_get_caret_word (cnt_editor);
+ if (word && *word)
e_spell_checker_ignore_word (spell_checker, word);
- }
+ g_free (word);
+ g_clear_object (&spell_checker);
}
static void
action_copy_cb (GtkAction *action,
EHTMLEditor *editor)
{
- EHTMLEditorView *view = e_html_editor_get_view (editor);
+ EContentEditor *cnt_editor;
- webkit_web_view_copy_clipboard (WEBKIT_WEB_VIEW (view));
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ e_content_editor_copy (cnt_editor);
}
static void
action_cut_cb (GtkAction *action,
EHTMLEditor *editor)
{
- EHTMLEditorView *view = e_html_editor_get_view (editor);
- EHTMLEditorSelection *selection;
- EHTMLEditorViewHistoryEvent *ev;
- WebKitDOMDocument *document;
- WebKitDOMDocumentFragment *fragment;
- WebKitDOMDOMWindow *dom_window;
- WebKitDOMDOMSelection *dom_selection;
- WebKitDOMRange *range;
-
- document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (view));
- dom_window = webkit_dom_document_get_default_view (document);
- dom_selection = webkit_dom_dom_window_get_selection (dom_window);
- g_object_unref (dom_window);
-
- if (!webkit_dom_dom_selection_get_range_count (dom_selection) ||
- webkit_dom_dom_selection_get_is_collapsed (dom_selection)) {
- g_object_unref (dom_selection);
- return;
- }
-
- range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
-
- selection = e_html_editor_view_get_selection (view);
-
- ev = g_new0 (EHTMLEditorViewHistoryEvent, 1);
- ev->type = HISTORY_DELETE;
+ EContentEditor *cnt_editor;
- e_html_editor_selection_get_selection_coordinates (
- selection, &ev->before.start.x, &ev->before.start.y, &ev->before.end.x, &ev->before.end.y);
-
- /* Save the fragment. */
- fragment = webkit_dom_range_clone_contents (range, NULL);
- g_object_unref (range);
- g_object_unref (dom_selection);
- ev->data.fragment = g_object_ref (fragment);
-
- webkit_web_view_cut_clipboard (WEBKIT_WEB_VIEW (view));
-
- ev->after.start.x = ev->before.start.x;
- ev->after.start.y = ev->before.start.y;
- ev->after.end.x = ev->before.start.x;
- ev->after.end.y = ev->before.start.y;
-
- e_html_editor_view_insert_new_history_event (view, ev);
-
- e_html_editor_view_force_spell_check_for_current_paragraph (view);
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ e_content_editor_cut (cnt_editor);
}
static void
action_indent_cb (GtkAction *action,
EHTMLEditor *editor)
{
- EHTMLEditorView *view = e_html_editor_get_view (editor);
+ EContentEditor *cnt_editor;
- if (gtk_widget_has_focus (GTK_WIDGET (view)))
- e_html_editor_selection_indent (editor->priv->selection);
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ if (gtk_widget_has_focus (GTK_WIDGET (cnt_editor)))
+ e_content_editor_selection_indent (cnt_editor);
}
static void
action_insert_emoticon_cb (GtkAction *action,
EHTMLEditor *editor)
{
- EHTMLEditorView *view;
+ EContentEditor *cnt_editor;
EEmoticon *emoticon;
- emoticon = e_emoticon_chooser_get_current_emoticon (
- E_EMOTICON_CHOOSER (action));
+ emoticon = e_emoticon_chooser_get_current_emoticon (E_EMOTICON_CHOOSER (action));
g_return_if_fail (emoticon != NULL);
- view = e_html_editor_get_view (editor);
- e_html_editor_view_insert_smiley (view, emoticon);
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ e_content_editor_insert_emoticon (cnt_editor, emoticon);
}
static void
@@ -620,15 +330,13 @@ action_insert_image_cb (GtkAction *action,
dialog = e_image_chooser_dialog_new (C_("dialog-title", "Insert Image"), NULL);
if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
- EHTMLEditorView *view;
- EHTMLEditorSelection *selection;
+ EContentEditor *cnt_editor;
gchar *uri;
uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (dialog));
- view = e_html_editor_get_view (editor);
- selection = e_html_editor_view_get_selection (view);
- e_html_editor_selection_insert_image (selection, uri);
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ e_content_editor_insert_image (cnt_editor, uri);
g_free (uri);
}
@@ -644,8 +352,7 @@ action_insert_link_cb (GtkAction *action,
editor->priv->link_dialog =
e_html_editor_link_dialog_new (editor);
- e_html_editor_link_dialog_show (
- E_HTML_EDITOR_LINK_DIALOG (editor->priv->link_dialog), NULL);
+ gtk_window_present (GTK_WINDOW (editor->priv->link_dialog));
}
static void
@@ -656,8 +363,7 @@ action_insert_rule_cb (GtkAction *action,
editor->priv->hrule_dialog =
e_html_editor_hrule_dialog_new (editor);
- e_html_editor_hrule_dialog_show (
- E_HTML_EDITOR_HRULE_DIALOG (editor->priv->hrule_dialog), NULL);
+ gtk_window_present (GTK_WINDOW (editor->priv->hrule_dialog));
}
static void
@@ -710,19 +416,20 @@ static void
action_language_cb (GtkToggleAction *toggle_action,
EHTMLEditor *editor)
{
- ESpellChecker *checker;
- EHTMLEditorView *view;
+ ESpellChecker *spell_checker;
+ EContentEditor *cnt_editor;
const gchar *language_code;
GtkAction *add_action;
gchar *action_name;
gboolean active;
- view = e_html_editor_get_view (editor);
- checker = e_html_editor_view_get_spell_checker (view);
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ spell_checker = e_content_editor_ref_spell_checker (cnt_editor);
language_code = gtk_action_get_name (GTK_ACTION (toggle_action));
active = gtk_toggle_action_get_active (toggle_action);
- e_spell_checker_set_language_active (checker, language_code, active);
+ e_spell_checker_set_language_active (spell_checker, language_code, active);
+ g_clear_object (&spell_checker);
/* Update "Add Word To" context menu item visibility. */
action_name = g_strdup_printf ("context-spell-add-%s", language_code);
@@ -739,15 +446,15 @@ static gboolean
update_mode_combobox (gpointer data)
{
EHTMLEditor *editor = data;
- EHTMLEditorView *view;
+ EContentEditor *cnt_editor;
GtkAction *action;
gboolean is_html;
if (!E_IS_HTML_EDITOR (editor))
return FALSE;
- view = e_html_editor_get_view (editor);
- is_html = e_html_editor_view_get_html_mode (view);
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ is_html = e_content_editor_get_html_mode (cnt_editor);
action = gtk_action_group_get_action (
editor->priv->core_editor_actions, "mode-html");
@@ -762,13 +469,13 @@ action_mode_cb (GtkRadioAction *action,
GtkRadioAction *current,
EHTMLEditor *editor)
{
+ EContentEditor *cnt_editor;
GtkActionGroup *action_group;
- EHTMLEditorView *view;
GtkWidget *style_combo_box;
gboolean is_html;
- view = e_html_editor_get_view (editor);
- is_html = e_html_editor_view_get_html_mode (view);
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ is_html = e_content_editor_get_html_mode (cnt_editor);
/* This must be done from idle callback, because apparently we can change
* current value in callback of current value change */
@@ -776,7 +483,6 @@ action_mode_cb (GtkRadioAction *action,
action_group = editor->priv->html_actions;
gtk_action_group_set_visible (action_group, is_html);
- gtk_action_group_set_sensitive (action_group, is_html);
action_group = editor->priv->html_context_actions;
gtk_action_group_set_visible (action_group, is_html);
@@ -814,36 +520,111 @@ static void
action_paste_cb (GtkAction *action,
EHTMLEditor *editor)
{
- EHTMLEditorView *view = e_html_editor_get_view (editor);
+ EContentEditor *cnt_editor;
- webkit_web_view_paste_clipboard (WEBKIT_WEB_VIEW (view));
- e_html_editor_view_force_spell_check_in_viewport (view);
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ e_content_editor_paste (cnt_editor);
+}
+
+static void
+clipboard_text_received_for_paste_as_text (GtkClipboard *clipboard,
+ const gchar *text,
+ EHTMLEditor *editor)
+{
+ EContentEditor *cnt_editor;
+
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ e_content_editor_insert_content (
+ cnt_editor,
+ text,
+ E_CONTENT_EDITOR_INSERT_CONVERT |
+ E_CONTENT_EDITOR_INSERT_TEXT_PLAIN);
}
static void
action_paste_as_text_cb (GtkAction *action,
EHTMLEditor *editor)
{
- EHTMLEditorView *view = e_html_editor_get_view (editor);
+ EContentEditor *cnt_editor;
+ GtkClipboard *clipboard;
+
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ if (!gtk_widget_has_focus (GTK_WIDGET (cnt_editor)))
+ gtk_widget_grab_focus (GTK_WIDGET (cnt_editor));
+
+ clipboard = gtk_clipboard_get_for_display (
+ gdk_display_get_default (),
+ GDK_SELECTION_CLIPBOARD);
+
+ gtk_clipboard_request_text (
+ clipboard,
+ (GtkClipboardTextReceivedFunc) clipboard_text_received_for_paste_as_text,
+ editor);
+}
+
+static void
+paste_quote_text (EHTMLEditor *editor,
+ const gchar *text,
+ gboolean is_html)
+{
+ EContentEditor *cnt_editor;
+
+ g_return_if_fail (E_IS_HTML_EDITOR (editor));
+ g_return_if_fail (text != NULL);
+
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ e_content_editor_insert_content (
+ cnt_editor,
+ text,
+ E_CONTENT_EDITOR_INSERT_QUOTE_CONTENT |
+ (is_html ? E_CONTENT_EDITOR_INSERT_TEXT_HTML : E_CONTENT_EDITOR_INSERT_TEXT_PLAIN));
+}
+
+static void
+clipboard_html_received_for_paste_quote (GtkClipboard *clipboard,
+ const gchar *text,
+ gpointer user_data)
+{
+ EHTMLEditor *editor = user_data;
- if (!gtk_widget_has_focus (GTK_WIDGET (view)))
- gtk_widget_grab_focus (GTK_WIDGET (view));
+ g_return_if_fail (E_IS_HTML_EDITOR (editor));
+ g_return_if_fail (text != NULL);
- e_html_editor_view_paste_as_text (view);
- e_html_editor_view_force_spell_check_in_viewport (view);
+ paste_quote_text (editor, text, TRUE);
+}
+
+static void
+clipboard_text_received_for_paste_quote (GtkClipboard *clipboard,
+ const gchar *text,
+ gpointer user_data)
+{
+ EHTMLEditor *editor = user_data;
+
+ g_return_if_fail (E_IS_HTML_EDITOR (editor));
+ g_return_if_fail (text != NULL);
+
+ paste_quote_text (editor, text, FALSE);
}
static void
action_paste_quote_cb (GtkAction *action,
EHTMLEditor *editor)
{
- EHTMLEditorView *view = e_html_editor_get_view (editor);
+ EContentEditor *cnt_editor;
+ GtkClipboard *clipboard;
- if (!gtk_widget_has_focus (GTK_WIDGET (view)))
- gtk_widget_grab_focus (GTK_WIDGET (view));
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ if (!gtk_widget_has_focus (GTK_WIDGET (cnt_editor)))
+ gtk_widget_grab_focus (GTK_WIDGET (cnt_editor));
- e_html_editor_view_paste_clipboard_quoted (view);
- e_html_editor_view_force_spell_check_in_viewport (view);
+ clipboard = gtk_clipboard_get_for_display (
+ gdk_display_get_default (),
+ GDK_SELECTION_CLIPBOARD);
+
+ if (e_clipboard_wait_is_html_available (clipboard))
+ e_clipboard_request_html (clipboard, clipboard_html_received_for_paste_quote, editor);
+ else if (gtk_clipboard_wait_is_text_available (clipboard))
+ gtk_clipboard_request_text (clipboard, clipboard_text_received_for_paste_quote, editor);
}
static void
@@ -855,9 +636,7 @@ action_properties_cell_cb (GtkAction *action,
e_html_editor_cell_dialog_new (editor);
}
- e_html_editor_cell_dialog_show (
- E_HTML_EDITOR_CELL_DIALOG (editor->priv->cell_dialog),
- editor->priv->table_cell);
+ gtk_window_present (GTK_WINDOW (editor->priv->cell_dialog));
}
static void
@@ -870,8 +649,7 @@ action_properties_image_cb (GtkAction *action,
}
e_html_editor_image_dialog_show (
- E_HTML_EDITOR_IMAGE_DIALOG (editor->priv->image_dialog),
- editor->priv->image);
+ E_HTML_EDITOR_IMAGE_DIALOG (editor->priv->image_dialog));
}
static void
@@ -883,9 +661,7 @@ action_properties_link_cb (GtkAction *action,
e_html_editor_link_dialog_new (editor);
}
- e_html_editor_link_dialog_show (
- E_HTML_EDITOR_LINK_DIALOG (editor->priv->link_dialog),
- editor->priv->current_node);
+ gtk_window_present (GTK_WINDOW (editor->priv->link_dialog));
}
static void
@@ -921,9 +697,7 @@ action_properties_rule_cb (GtkAction *action,
e_html_editor_hrule_dialog_new (editor);
}
- e_html_editor_hrule_dialog_show (
- E_HTML_EDITOR_HRULE_DIALOG (editor->priv->hrule_dialog),
- editor->priv->current_node);
+ gtk_window_present (GTK_WINDOW (editor->priv->hrule_dialog));
}
static void
@@ -954,20 +728,22 @@ static void
action_redo_cb (GtkAction *action,
EHTMLEditor *editor)
{
- EHTMLEditorView *view = e_html_editor_get_view (editor);
+ EContentEditor *cnt_editor;
- if (gtk_widget_has_focus (GTK_WIDGET (view)))
- e_html_editor_view_redo (view);
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ if (gtk_widget_has_focus (GTK_WIDGET (cnt_editor)))
+ e_content_editor_redo (cnt_editor);
}
static void
action_select_all_cb (GtkAction *action,
EHTMLEditor *editor)
{
- EHTMLEditorView *view = e_html_editor_get_view (editor);
+ EContentEditor *cnt_editor;
- if (gtk_widget_has_focus (GTK_WIDGET (view)))
- webkit_web_view_select_all (WEBKIT_WEB_VIEW (view));
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ if (gtk_widget_has_focus (GTK_WIDGET (cnt_editor)))
+ e_content_editor_select_all (cnt_editor);
}
static void
@@ -1021,43 +797,34 @@ static void
action_undo_cb (GtkAction *action,
EHTMLEditor *editor)
{
- EHTMLEditorView *view = e_html_editor_get_view (editor);
+ EContentEditor *cnt_editor;
- if (gtk_widget_has_focus (GTK_WIDGET (view)))
- e_html_editor_view_undo (view);
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ if (gtk_widget_has_focus (GTK_WIDGET (cnt_editor))) {
+ e_content_editor_undo (cnt_editor);
+ }
}
static void
action_unindent_cb (GtkAction *action,
EHTMLEditor *editor)
{
- EHTMLEditorView *view = e_html_editor_get_view (editor);
+ EContentEditor *cnt_editor;
- if (gtk_widget_has_focus (GTK_WIDGET (view)))
- e_html_editor_selection_unindent (editor->priv->selection);
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ if (gtk_widget_has_focus (GTK_WIDGET (cnt_editor)))
+ e_content_editor_selection_unindent (cnt_editor);
}
static void
action_wrap_lines_cb (GtkAction *action,
EHTMLEditor *editor)
{
- EHTMLEditorView *view = e_html_editor_get_view (editor);
+ EContentEditor *cnt_editor;
- if (gtk_widget_has_focus (GTK_WIDGET (view)))
- e_html_editor_selection_wrap_lines (editor->priv->selection);
-}
-
-static void
-action_show_webkit_inspector_cb (GtkAction *action,
- EHTMLEditor *editor)
-{
- WebKitWebInspector *inspector;
- EHTMLEditorView *view;
-
- view = e_html_editor_get_view (editor);
- inspector = webkit_web_view_get_inspector (WEBKIT_WEB_VIEW (view));
-
- webkit_web_inspector_show (inspector);
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ if (gtk_widget_has_focus (GTK_WIDGET (cnt_editor)))
+ e_content_editor_selection_wrap (cnt_editor);
}
/*****************************************************************************
@@ -1239,14 +1006,7 @@ static GtkActionEntry core_editor_entries[] = {
N_("_Wrap Lines"),
"<Control>k",
NULL,
- G_CALLBACK (action_wrap_lines_cb) },
-
- { "webkit-inspector",
- NULL,
- N_("Open Inspector"),
- NULL,
- NULL,
- G_CALLBACK (action_show_webkit_inspector_cb) },
+ G_CALLBACK (action_wrap_lines_cb) }
};
static GtkRadioActionEntry core_justify_entries[] = {
@@ -1256,21 +1016,21 @@ static GtkRadioActionEntry core_justify_entries[] = {
N_("_Center"),
"<Control>e",
N_("Center Alignment"),
- E_HTML_EDITOR_SELECTION_ALIGNMENT_CENTER },
+ E_CONTENT_EDITOR_ALIGNMENT_CENTER },
{ "justify-left",
"format-justify-left",
N_("_Left"),
"<Control>l",
N_("Left Alignment"),
- E_HTML_EDITOR_SELECTION_ALIGNMENT_LEFT },
+ E_CONTENT_EDITOR_ALIGNMENT_LEFT },
{ "justify-right",
"format-justify-right",
N_("_Right"),
"<Control>r",
N_("Right Alignment"),
- E_HTML_EDITOR_SELECTION_ALIGNMENT_RIGHT }
+ E_CONTENT_EDITOR_ALIGNMENT_RIGHT }
};
static GtkRadioActionEntry core_mode_entries[] = {
@@ -1280,14 +1040,14 @@ static GtkRadioActionEntry core_mode_entries[] = {
N_("_HTML"),
NULL,
N_("HTML editing mode"),
- TRUE }, /* e_html_editor_view_set_html_mode */
+ TRUE }, /* e_content_editor_set_html_mode */
{ "mode-plain",
NULL,
N_("Plain _Text"),
NULL,
N_("Plain text editing mode"),
- FALSE } /* e_html_editor_view_set_html_mode */
+ FALSE } /* e_content_editor_set_html_mode */
};
static GtkRadioActionEntry core_style_entries[] = {
@@ -1297,98 +1057,91 @@ static GtkRadioActionEntry core_style_entries[] = {
N_("_Normal"),
"<Control>0",
NULL,
- E_HTML_EDITOR_SELECTION_BLOCK_FORMAT_PARAGRAPH },
+ E_CONTENT_EDITOR_BLOCK_FORMAT_PARAGRAPH },
{ "style-h1",
NULL,
N_("Header _1"),
"<Control>1",
NULL,
- E_HTML_EDITOR_SELECTION_BLOCK_FORMAT_H1 },
+ E_CONTENT_EDITOR_BLOCK_FORMAT_H1 },
{ "style-h2",
NULL,
N_("Header _2"),
"<Control>2",
NULL,
- E_HTML_EDITOR_SELECTION_BLOCK_FORMAT_H2 },
+ E_CONTENT_EDITOR_BLOCK_FORMAT_H2 },
{ "style-h3",
NULL,
N_("Header _3"),
"<Control>3",
NULL,
- E_HTML_EDITOR_SELECTION_BLOCK_FORMAT_H3 },
+ E_CONTENT_EDITOR_BLOCK_FORMAT_H3 },
{ "style-h4",
NULL,
N_("Header _4"),
"<Control>4",
NULL,
- E_HTML_EDITOR_SELECTION_BLOCK_FORMAT_H4 },
+ E_CONTENT_EDITOR_BLOCK_FORMAT_H4 },
{ "style-h5",
NULL,
N_("Header _5"),
"<Control>5",
NULL,
- E_HTML_EDITOR_SELECTION_BLOCK_FORMAT_H5 },
+ E_CONTENT_EDITOR_BLOCK_FORMAT_H5 },
{ "style-h6",
NULL,
N_("Header _6"),
"<Control>6",
NULL,
- E_HTML_EDITOR_SELECTION_BLOCK_FORMAT_H6 },
+ E_CONTENT_EDITOR_BLOCK_FORMAT_H6 },
{ "style-preformat",
NULL,
N_("_Preformatted"),
"<Control>7",
NULL,
- E_HTML_EDITOR_SELECTION_BLOCK_FORMAT_PRE },
+ E_CONTENT_EDITOR_BLOCK_FORMAT_PRE },
{ "style-address",
NULL,
N_("A_ddress"),
"<Control>8",
NULL,
- E_HTML_EDITOR_SELECTION_BLOCK_FORMAT_ADDRESS },
-
- { "style-blockquote",
- NULL,
- N_("_Blockquote"),
- "<Control>9",
- NULL,
- E_HTML_EDITOR_SELECTION_BLOCK_FORMAT_BLOCKQUOTE },
+ E_CONTENT_EDITOR_BLOCK_FORMAT_ADDRESS },
{ "style-list-bullet",
NULL,
N_("_Bulleted List"),
NULL,
NULL,
- E_HTML_EDITOR_SELECTION_BLOCK_FORMAT_UNORDERED_LIST },
+ E_CONTENT_EDITOR_BLOCK_FORMAT_UNORDERED_LIST },
{ "style-list-roman",
NULL,
N_("_Roman Numeral List"),
NULL,
NULL,
- E_HTML_EDITOR_SELECTION_BLOCK_FORMAT_ORDERED_LIST_ROMAN },
+ E_CONTENT_EDITOR_BLOCK_FORMAT_ORDERED_LIST_ROMAN },
{ "style-list-number",
NULL,
N_("Numbered _List"),
NULL,
NULL,
- E_HTML_EDITOR_SELECTION_BLOCK_FORMAT_ORDERED_LIST },
+ E_CONTENT_EDITOR_BLOCK_FORMAT_ORDERED_LIST },
{ "style-list-alpha",
NULL,
N_("_Alphabetical List"),
NULL,
NULL,
- E_HTML_EDITOR_SELECTION_BLOCK_FORMAT_ORDERED_LIST_ALPHA }
+ E_CONTENT_EDITOR_BLOCK_FORMAT_ORDERED_LIST_ALPHA }
};
/*****************************************************************************
@@ -1549,7 +1302,7 @@ static GtkRadioActionEntry html_size_entries[] = {
N_("-2"),
NULL,
NULL,
- E_HTML_EDITOR_SELECTION_FONT_SIZE_TINY },
+ E_CONTENT_EDITOR_FONT_SIZE_TINY },
{ "size-minus-one",
NULL,
@@ -1557,7 +1310,7 @@ static GtkRadioActionEntry html_size_entries[] = {
N_("-1"),
NULL,
NULL,
- E_HTML_EDITOR_SELECTION_FONT_SIZE_SMALL },
+ E_CONTENT_EDITOR_FONT_SIZE_SMALL },
{ "size-plus-zero",
NULL,
@@ -1565,7 +1318,7 @@ static GtkRadioActionEntry html_size_entries[] = {
N_("+0"),
NULL,
NULL,
- E_HTML_EDITOR_SELECTION_FONT_SIZE_NORMAL },
+ E_CONTENT_EDITOR_FONT_SIZE_NORMAL },
{ "size-plus-one",
NULL,
@@ -1573,7 +1326,7 @@ static GtkRadioActionEntry html_size_entries[] = {
N_("+1"),
NULL,
NULL,
- E_HTML_EDITOR_SELECTION_FONT_SIZE_BIG },
+ E_CONTENT_EDITOR_FONT_SIZE_BIG },
{ "size-plus-two",
NULL,
@@ -1581,7 +1334,7 @@ static GtkRadioActionEntry html_size_entries[] = {
N_("+2"),
NULL,
NULL,
- E_HTML_EDITOR_SELECTION_FONT_SIZE_BIGGER },
+ E_CONTENT_EDITOR_FONT_SIZE_BIGGER },
{ "size-plus-three",
NULL,
@@ -1589,7 +1342,7 @@ static GtkRadioActionEntry html_size_entries[] = {
N_("+3"),
NULL,
NULL,
- E_HTML_EDITOR_SELECTION_FONT_SIZE_LARGE },
+ E_CONTENT_EDITOR_FONT_SIZE_LARGE },
{ "size-plus-four",
NULL,
@@ -1597,7 +1350,7 @@ static GtkRadioActionEntry html_size_entries[] = {
N_("+4"),
NULL,
NULL,
- E_HTML_EDITOR_SELECTION_FONT_SIZE_VERY_LARGE }
+ E_CONTENT_EDITOR_FONT_SIZE_VERY_LARGE }
};
/*****************************************************************************
@@ -1649,13 +1402,6 @@ static GtkActionEntry context_entries[] = {
NULL,
NULL },
- { "context-input-methods-menu",
- NULL,
- N_("Input Methods"),
- NULL,
- NULL,
- NULL },
-
{ "context-insert-table-menu",
NULL,
/* Translators: Popup menu item caption, containing all the Insert options for a table */
@@ -1717,13 +1463,6 @@ static GtkActionEntry html_context_entries[] = {
NULL,
G_CALLBACK (action_context_insert_row_below_cb) },
- { "context-insert-table",
- NULL,
- N_("Table"),
- NULL,
- NULL,
- G_CALLBACK (action_insert_table_cb) },
-
{ "context-properties-cell",
NULL,
N_("Cell..."),
@@ -1832,27 +1571,27 @@ static GtkActionEntry spell_context_entries[] = {
static void
editor_actions_setup_languages_menu (EHTMLEditor *editor)
{
- ESpellChecker *checker;
- EHTMLEditorView *view;
+ ESpellChecker *spell_checker;
+ EContentEditor *cnt_editor;
GtkUIManager *manager;
GtkActionGroup *action_group;
- GList *list, *link;
+ GList *list = NULL, *link;
guint merge_id;
manager = editor->priv->manager;
action_group = editor->priv->language_actions;
- view = e_html_editor_get_view (editor);
- checker = e_html_editor_view_get_spell_checker (view);
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ spell_checker = e_content_editor_ref_spell_checker (cnt_editor);
merge_id = gtk_ui_manager_new_merge_id (manager);
- list = e_spell_checker_list_available_dicts (checker);
+ list = e_spell_checker_list_available_dicts (spell_checker);
for (link = list; link != NULL; link = g_list_next (link)) {
ESpellDictionary *dictionary = link->data;
GtkToggleAction *action;
const gchar *language_name;
GString *escaped_name = NULL;
- gboolean active;
+ gboolean active = FALSE;
language_name = e_spell_dictionary_get_name (dictionary);
if (language_name && strchr (language_name, '_') != NULL)
@@ -1870,7 +1609,7 @@ editor_actions_setup_languages_menu (EHTMLEditor *editor)
* We're not prepared to invoke the signal handler yet.
* The "Add Word To" actions have not yet been added. */
active = e_spell_checker_get_language_active (
- checker, e_spell_dictionary_get_code (dictionary));
+ spell_checker, e_spell_dictionary_get_code (dictionary));
gtk_toggle_action_set_active (action, active);
g_signal_connect (
@@ -1891,21 +1630,24 @@ editor_actions_setup_languages_menu (EHTMLEditor *editor)
}
g_list_free (list);
+ g_clear_object (&spell_checker);
}
static void
editor_actions_setup_spell_check_menu (EHTMLEditor *editor)
{
- ESpellChecker *checker;
+ EContentEditor *cnt_editor;
+ ESpellChecker *spell_checker;
GtkUIManager *manager;
GtkActionGroup *action_group;
- GList *available_dicts, *iter;
+ GList *available_dicts = NULL, *iter;
guint merge_id;
manager = editor->priv->manager;
action_group = editor->priv->spell_check_actions;;
- checker = e_html_editor_view_get_spell_checker (editor->priv->html_editor_view);
- available_dicts = e_spell_checker_list_available_dicts (checker);
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ spell_checker = e_content_editor_ref_spell_checker (cnt_editor);
+ available_dicts = e_spell_checker_list_available_dicts (spell_checker);
merge_id = gtk_ui_manager_new_merge_id (manager);
for (iter = available_dicts; iter; iter = iter->next) {
@@ -1955,7 +1697,7 @@ editor_actions_setup_spell_check_menu (EHTMLEditor *editor)
/* Visibility is dependent on whether the
* corresponding language action is active. */
- gtk_action_set_visible (action, e_spell_checker_get_language_active (checker, code));
+ gtk_action_set_visible (action, FALSE);
gtk_action_group_add_action (action_group, action);
@@ -1975,6 +1717,7 @@ editor_actions_setup_spell_check_menu (EHTMLEditor *editor)
}
g_list_free (available_dicts);
+ g_clear_object (&spell_checker);
}
void
@@ -1984,14 +1727,11 @@ editor_actions_init (EHTMLEditor *editor)
GtkActionGroup *action_group;
GtkUIManager *manager;
const gchar *domain;
- EHTMLEditorView *view;
- GSettings *settings;
g_return_if_fail (E_IS_HTML_EDITOR (editor));
manager = e_html_editor_get_ui_manager (editor);
domain = GETTEXT_PACKAGE;
- view = e_html_editor_get_view (editor);
/* Core Actions */
action_group = editor->priv->core_actions;
@@ -2009,7 +1749,7 @@ editor_actions_init (EHTMLEditor *editor)
gtk_action_group_add_radio_actions (
action_group, core_justify_entries,
G_N_ELEMENTS (core_justify_entries),
- E_HTML_EDITOR_SELECTION_ALIGNMENT_LEFT,
+ E_CONTENT_EDITOR_ALIGNMENT_LEFT,
NULL, NULL);
gtk_action_group_add_radio_actions (
action_group, core_mode_entries,
@@ -2019,19 +1759,10 @@ editor_actions_init (EHTMLEditor *editor)
gtk_action_group_add_radio_actions (
action_group, core_style_entries,
G_N_ELEMENTS (core_style_entries),
- E_HTML_EDITOR_SELECTION_BLOCK_FORMAT_PARAGRAPH,
+ E_CONTENT_EDITOR_BLOCK_FORMAT_PARAGRAPH,
NULL, NULL);
gtk_ui_manager_insert_action_group (manager, action_group, 0);
- action = gtk_action_group_get_action (action_group, "mode-html");
- e_binding_bind_property (
- view, "html-mode",
- action, "current-value",
- G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
-
- /* Synchronize wiget mode with the buttons */
- e_html_editor_view_set_html_mode (view, TRUE);
-
/* Face Action */
action = e_emoticon_action_new (
"insert-emoticon", _("_Emoticon"),
@@ -2055,7 +1786,7 @@ editor_actions_init (EHTMLEditor *editor)
gtk_action_group_add_radio_actions (
action_group, html_size_entries,
G_N_ELEMENTS (html_size_entries),
- E_HTML_EDITOR_SELECTION_FONT_SIZE_NORMAL,
+ E_CONTENT_EDITOR_FONT_SIZE_NORMAL,
NULL, NULL);
gtk_ui_manager_insert_action_group (manager, action_group, 0);
@@ -2120,92 +1851,113 @@ editor_actions_init (EHTMLEditor *editor)
gtk_action_set_sensitive (ACTION (UNINDENT), FALSE);
gtk_action_set_sensitive (ACTION (FIND_AGAIN), FALSE);
+}
+
+void
+editor_actions_bind (EHTMLEditor *editor)
+{
+ GtkAction *action;
+ GtkActionGroup *action_group;
+ EContentEditor *cnt_editor;
+ g_return_if_fail (E_IS_HTML_EDITOR (editor));
+
+ cnt_editor = e_html_editor_get_content_editor (editor);
+
+ action_group = editor->priv->core_editor_actions;
+ action = gtk_action_group_get_action (action_group, "mode-html");
e_binding_bind_property (
- view, "can-redo",
+ cnt_editor, "html-mode",
+ action, "current-value",
+ G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
+
+ /* Synchronize widget mode with the buttons */
+ e_content_editor_set_html_mode (cnt_editor, TRUE);
+
+ e_binding_bind_property (
+ cnt_editor, "can-redo",
ACTION (REDO), "sensitive",
G_BINDING_SYNC_CREATE);
e_binding_bind_property (
- view, "can-undo",
+ cnt_editor, "can-undo",
ACTION (UNDO), "sensitive",
G_BINDING_SYNC_CREATE);
e_binding_bind_property (
- view, "can-copy",
+ cnt_editor, "can-copy",
ACTION (COPY), "sensitive",
G_BINDING_SYNC_CREATE);
e_binding_bind_property (
- view, "can-cut",
+ cnt_editor, "can-cut",
ACTION (CUT), "sensitive",
G_BINDING_SYNC_CREATE);
e_binding_bind_property (
- view, "can-paste",
+ cnt_editor, "can-paste",
ACTION (PASTE), "sensitive",
G_BINDING_SYNC_CREATE);
e_binding_bind_property (
- view, "can-paste",
+ cnt_editor, "can-paste",
ACTION (PASTE_QUOTE), "sensitive",
G_BINDING_SYNC_CREATE);
/* This is connected to JUSTIFY_LEFT action only, but
* it automatically applies on all actions in the group. */
e_binding_bind_property (
- editor->priv->selection, "alignment",
+ cnt_editor, "alignment",
ACTION (JUSTIFY_LEFT), "current-value",
G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
e_binding_bind_property (
- editor->priv->selection, "bold",
+ cnt_editor, "bold",
ACTION (BOLD), "active",
G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
e_binding_bind_property (
- editor->priv->selection, "font-size",
+ cnt_editor, "font-size",
ACTION (FONT_SIZE_GROUP), "current-value",
G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
e_binding_bind_property (
- editor->priv->selection, "block-format",
+ cnt_editor, "block-format",
ACTION (STYLE_NORMAL), "current-value",
G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
e_binding_bind_property (
- editor->priv->selection, "indented",
+ cnt_editor, "indented",
ACTION (UNINDENT), "sensitive",
G_BINDING_SYNC_CREATE);
e_binding_bind_property (
- editor->priv->selection, "italic",
+ cnt_editor, "italic",
ACTION (ITALIC), "active",
G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
e_binding_bind_property (
- editor->priv->selection, "monospaced",
+ cnt_editor, "monospaced",
ACTION (MONOSPACED), "active",
G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
e_binding_bind_property (
- editor->priv->selection, "strikethrough",
+ cnt_editor, "strikethrough",
ACTION (STRIKETHROUGH), "active",
G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
e_binding_bind_property (
- editor->priv->selection, "underline",
+ cnt_editor, "underline",
ACTION (UNDERLINE), "active",
G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
+ e_binding_bind_property (
+ cnt_editor, "html-mode",
+ editor->priv->html_actions, "sensitive",
+ G_BINDING_SYNC_CREATE);
+
/* Disable all actions and toolbars when editor is not editable */
e_binding_bind_property (
- view, "editable",
+ cnt_editor, "editable",
editor->priv->core_editor_actions, "sensitive",
G_BINDING_SYNC_CREATE);
e_binding_bind_property (
- view, "editable",
+ cnt_editor, "editable",
editor->priv->html_actions, "sensitive",
G_BINDING_SYNC_CREATE);
e_binding_bind_property (
- view, "editable",
+ cnt_editor, "editable",
editor->priv->spell_check_actions, "sensitive",
G_BINDING_SYNC_CREATE);
e_binding_bind_property (
- view, "editable",
+ cnt_editor, "editable",
editor->priv->suggestion_actions, "sensitive",
G_BINDING_SYNC_CREATE);
-
- settings = e_util_ref_settings ("org.gnome.evolution.mail");
- gtk_action_set_visible (
- ACTION (WEBKIT_INSPECTOR),
- g_settings_get_boolean (settings, "composer-developer-mode"));
- g_object_unref (settings);
}
diff --git a/e-util/e-html-editor-actions.h b/e-util/e-html-editor-actions.h
index 6991503..f724db0 100644
--- a/e-util/e-html-editor-actions.h
+++ b/e-util/e-html-editor-actions.h
@@ -47,8 +47,6 @@
E_HTML_EDITOR_ACTION ((editor), "context-insert-row-above")
#define E_HTML_EDITOR_ACTION_CONTEXT_INSERT_ROW_BELOW(editor) \
E_HTML_EDITOR_ACTION ((editor), "context-insert-row-below")
-#define E_HTML_EDITOR_ACTION_CONTEXT_INSERT_TABLE(editor) \
- E_HTML_EDITOR_ACTION ((editor), "context-insert-table")
#define E_HTML_EDITOR_ACTION_CONTEXT_PROPERTIES_CELL(editor) \
E_HTML_EDITOR_ACTION ((editor), "context-properties-cell")
#define E_HTML_EDITOR_ACTION_CONTEXT_PROPERTIES_IMAGE(editor) \
@@ -85,6 +83,8 @@
E_HTML_EDITOR_ACTION ((editor), "format-menu")
#define E_HTML_EDITOR_ACTION_FORMAT_TEXT(editor) \
E_HTML_EDITOR_ACTION ((editor), "format-text")
+#define E_HTML_EDITOR_ACTION_INSERT_EMOTICON(editor) \
+ E_HTML_EDITOR_ACTION ((editor), "insert-emoticon")
#define E_HTML_EDITOR_ACTION_INSERT_IMAGE(editor) \
E_HTML_EDITOR_ACTION ((editor), "insert-image")
#define E_HTML_EDITOR_ACTION_INSERT_LINK(editor) \
@@ -157,7 +157,7 @@
E_HTML_EDITOR_ACTION ((editor), "undo")
#define E_HTML_EDITOR_ACTION_UNINDENT(editor) \
E_HTML_EDITOR_ACTION ((editor), "unindent")
-#define E_HTML_EDITOR_ACTION_WEBKIT_INSPECTOR(editor) \
- E_HTML_EDITOR_ACTION ((editor), "webkit-inspector")
+#define E_HTML_EDITOR_ACTION_WRAP_LINES(editor) \
+ E_HTML_EDITOR_ACTION ((editor), "wrap-lines")
#endif /* E_HTML_EDITOR_ACTIONS_H */
diff --git a/e-util/e-html-editor-cell-dialog.c b/e-util/e-html-editor-cell-dialog.c
index 0ee0da2..b5379ec 100644
--- a/e-util/e-html-editor-cell-dialog.c
+++ b/e-util/e-html-editor-cell-dialog.c
@@ -29,10 +29,8 @@
#include "e-color-combo.h"
#include "e-dialog-widgets.h"
-#include "e-html-editor-utils.h"
#include "e-image-chooser-dialog.h"
#include "e-misc-utils.h"
-#include "e-misc-utils.h"
#define E_HTML_EDITOR_CELL_DIALOG_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE \
@@ -62,10 +60,7 @@ struct _EHTMLEditorCellDialogPrivate {
GtkWidget *remove_image_button;
- WebKitDOMElement *cell;
guint scope;
-
- EHTMLEditorViewHistoryEvent *history_event;
};
enum {
@@ -77,151 +72,12 @@ enum {
static GdkRGBA transparent = { 0, 0, 0, 0 };
-typedef void (*DOMStrFunc) (WebKitDOMHTMLTableCellElement *cell, const gchar *val, gpointer user_data);
-typedef void (*DOMUlongFunc) (WebKitDOMHTMLTableCellElement *cell, gulong val, gpointer user_data);
-typedef void (*DOMBoolFunc) (WebKitDOMHTMLTableCellElement *cell, gboolean val, gpointer user_data);
-
G_DEFINE_TYPE (
EHTMLEditorCellDialog,
e_html_editor_cell_dialog,
E_TYPE_HTML_EDITOR_DIALOG);
static void
-call_cell_dom_func (WebKitDOMHTMLTableCellElement *cell,
- gpointer func,
- GValue *value,
- gpointer user_data)
-{
- if (G_VALUE_HOLDS_STRING (value)) {
- DOMStrFunc f = func;
- f (cell, g_value_get_string (value), user_data);
- } else if (G_VALUE_HOLDS_ULONG (value)) {
- DOMUlongFunc f = func;
- f (cell, g_value_get_ulong (value), user_data);
- } else if (G_VALUE_HOLDS_BOOLEAN (value)) {
- DOMBoolFunc f = func;
- f (cell, g_value_get_boolean (value), user_data);
- }
-}
-
-static void
-for_each_cell_do (WebKitDOMElement *row,
- gpointer func,
- GValue *value,
- gpointer user_data)
-{
- WebKitDOMHTMLCollection *cells;
- gulong ii, length;
- cells = webkit_dom_html_table_row_element_get_cells (
- WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (row));
- length = webkit_dom_html_collection_get_length (cells);
- for (ii = 0; ii < length; ii++) {
- WebKitDOMNode *cell;
- cell = webkit_dom_html_collection_item (cells, ii);
- if (!cell) {
- continue;
- }
-
- call_cell_dom_func (
- WEBKIT_DOM_HTML_TABLE_CELL_ELEMENT (cell), func, value, user_data);
- g_object_unref (cell);
- }
- g_object_unref (cells);
-}
-
-static void
-html_editor_cell_dialog_set_attribute (EHTMLEditorCellDialog *dialog,
- gpointer func,
- GValue *value,
- gpointer user_data)
-{
- if (dialog->priv->scope == SCOPE_CELL) {
-
- call_cell_dom_func (
- WEBKIT_DOM_HTML_TABLE_CELL_ELEMENT (dialog->priv->cell),
- func, value, user_data);
-
- } else if (dialog->priv->scope == SCOPE_COLUMN) {
- gulong index, ii, length;
- WebKitDOMElement *table;
- WebKitDOMHTMLCollection *rows;
-
- index = webkit_dom_html_table_cell_element_get_cell_index (
- WEBKIT_DOM_HTML_TABLE_CELL_ELEMENT (dialog->priv->cell));
- table = e_html_editor_dom_node_find_parent_element (
- WEBKIT_DOM_NODE (dialog->priv->cell), "TABLE");
- if (!table) {
- return;
- }
-
- rows = webkit_dom_html_table_element_get_rows (
- WEBKIT_DOM_HTML_TABLE_ELEMENT (table));
- length = webkit_dom_html_collection_get_length (rows);
- for (ii = 0; ii < length; ii++) {
- WebKitDOMNode *row, *cell;
- WebKitDOMHTMLCollection *cells;
-
- row = webkit_dom_html_collection_item (rows, ii);
- cells = webkit_dom_html_table_row_element_get_cells (
- WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (row));
- cell = webkit_dom_html_collection_item (cells, index);
- if (!cell) {
- g_object_unref (row);
- g_object_unref (cells);
- continue;
- }
-
- call_cell_dom_func (
- WEBKIT_DOM_HTML_TABLE_CELL_ELEMENT (cell),
- func, value, user_data);
- g_object_unref (row);
- g_object_unref (cells);
- g_object_unref (cell);
- }
- g_object_unref (rows);
-
- } else if (dialog->priv->scope == SCOPE_ROW) {
- WebKitDOMElement *row;
-
- row = e_html_editor_dom_node_find_parent_element (
- WEBKIT_DOM_NODE (dialog->priv->cell), "TR");
- if (!row) {
- return;
- }
-
- for_each_cell_do (row, func, value, user_data);
-
- } else if (dialog->priv->scope == SCOPE_TABLE) {
- gulong ii, length;
- WebKitDOMElement *table;
- WebKitDOMHTMLCollection *rows;
-
- table = e_html_editor_dom_node_find_parent_element (
- WEBKIT_DOM_NODE (dialog->priv->cell), "TABLE");
- if (!table) {
- return;
- }
-
- rows = webkit_dom_html_table_element_get_rows (
- WEBKIT_DOM_HTML_TABLE_ELEMENT (table));
- length = webkit_dom_html_collection_get_length (rows);
- for (ii = 0; ii < length; ii++) {
- WebKitDOMNode *row;
-
- row = webkit_dom_html_collection_item (rows, ii);
- if (!row) {
- continue;
- }
-
- for_each_cell_do (
- WEBKIT_DOM_ELEMENT (row), func, value, user_data);
- g_object_unref (row);
- }
- g_object_unref (rows);
- }
-}
-
-static void
html_editor_cell_dialog_set_scope (EHTMLEditorCellDialog *dialog)
{
if (gtk_toggle_button_get_active (
@@ -250,249 +106,184 @@ html_editor_cell_dialog_set_scope (EHTMLEditorCellDialog *dialog)
static void
html_editor_cell_dialog_set_valign (EHTMLEditorCellDialog *dialog)
{
- GValue val = { 0 };
-
- g_value_init (&val, G_TYPE_STRING);
- g_value_set_string (
- &val,
- gtk_combo_box_get_active_id (
- GTK_COMBO_BOX (dialog->priv->valign_combo)));
+ EHTMLEditor *editor;
+ EContentEditor *cnt_editor;
- html_editor_cell_dialog_set_attribute (
- dialog, webkit_dom_html_table_cell_element_set_v_align, &val, NULL);
+ editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
+ cnt_editor = e_html_editor_get_content_editor (editor);
- g_value_unset (&val);
+ e_content_editor_cell_set_v_align (
+ cnt_editor,
+ gtk_combo_box_get_active_id (
+ GTK_COMBO_BOX (dialog->priv->valign_combo)),
+ dialog->priv->scope);
}
static void
html_editor_cell_dialog_set_halign (EHTMLEditorCellDialog *dialog)
{
- GValue val = { 0 };
-
- g_value_init (&val, G_TYPE_STRING);
- g_value_set_string (
- &val,
- gtk_combo_box_get_active_id (
- GTK_COMBO_BOX (dialog->priv->halign_combo)));
+ EHTMLEditor *editor;
+ EContentEditor *cnt_editor;
- html_editor_cell_dialog_set_attribute (
- dialog, webkit_dom_html_table_cell_element_set_align, &val, NULL);
+ editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
+ cnt_editor = e_html_editor_get_content_editor (editor);
- g_value_unset (&val);
+ e_content_editor_cell_set_align (
+ cnt_editor,
+ gtk_combo_box_get_active_id (
+ GTK_COMBO_BOX (dialog->priv->halign_combo)),
+ dialog->priv->scope);
}
static void
html_editor_cell_dialog_set_wrap_text (EHTMLEditorCellDialog *dialog)
{
- GValue val = { 0 };
-
- g_value_init (&val, G_TYPE_BOOLEAN);
- g_value_set_boolean (
- &val,
- !gtk_toggle_button_get_active (
- GTK_TOGGLE_BUTTON (dialog->priv->wrap_text_check)));
-
- html_editor_cell_dialog_set_attribute (
- dialog, webkit_dom_html_table_cell_element_set_no_wrap, &val, NULL);
-}
-
-static void
-cell_set_header_style (WebKitDOMHTMLTableCellElement *cell,
- gboolean header_style,
- gpointer user_data)
-{
- EHTMLEditorCellDialog *dialog = user_data;
- WebKitDOMDocument *document;
- WebKitDOMNodeList *nodes;
- WebKitDOMElement *new_cell;
- gulong length, ii;
- gchar *tagname;
-
- document = webkit_dom_node_get_owner_document (WEBKIT_DOM_NODE (cell));
- tagname = webkit_dom_element_get_tag_name (WEBKIT_DOM_ELEMENT (cell));
-
- if (header_style && (g_ascii_strncasecmp (tagname, "TD", 2) == 0)) {
-
- new_cell = webkit_dom_document_create_element (document, "TH", NULL);
-
- } else if (!header_style && (g_ascii_strncasecmp (tagname, "TH", 2) == 0)) {
-
- new_cell = webkit_dom_document_create_element (document, "TD", NULL);
-
- } else {
- g_free (tagname);
- return;
- }
-
- /* Move all child nodes from cell to new_cell */
- nodes = webkit_dom_node_get_child_nodes (WEBKIT_DOM_NODE (cell));
- length = webkit_dom_node_list_get_length (nodes);
- for (ii = 0; ii < length; ii++) {
- WebKitDOMNode *node;
-
- node = webkit_dom_node_list_item (nodes, ii);
- webkit_dom_node_append_child (
- WEBKIT_DOM_NODE (new_cell), node, NULL);
- g_object_unref (node);
- }
- g_object_unref (nodes);
-
- /* Insert new_cell before cell and remove cell */
- webkit_dom_node_insert_before (
- webkit_dom_node_get_parent_node (
- WEBKIT_DOM_NODE (cell)),
- WEBKIT_DOM_NODE (new_cell),
- WEBKIT_DOM_NODE (cell), NULL);
-
- webkit_dom_node_remove_child (
- webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (cell)),
- WEBKIT_DOM_NODE (cell), NULL);
+ EHTMLEditor *editor;
+ EContentEditor *cnt_editor;
- dialog->priv->cell = new_cell;
+ editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
+ cnt_editor = e_html_editor_get_content_editor (editor);
- g_free (tagname);
+ e_content_editor_cell_set_wrap (
+ cnt_editor,
+ gtk_toggle_button_get_active (
+ GTK_TOGGLE_BUTTON (dialog->priv->wrap_text_check)),
+ dialog->priv->scope);
}
static void
html_editor_cell_dialog_set_header_style (EHTMLEditorCellDialog *dialog)
{
- GValue val = { 0 };
+ EHTMLEditor *editor;
+ EContentEditor *cnt_editor;
- g_value_init (&val, G_TYPE_BOOLEAN);
- g_value_set_boolean (
- &val,
- gtk_toggle_button_get_active (
- GTK_TOGGLE_BUTTON (dialog->priv->header_style_check)));
+ editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
+ cnt_editor = e_html_editor_get_content_editor (editor);
- html_editor_cell_dialog_set_attribute (
- dialog, cell_set_header_style, &val, dialog);
+ e_content_editor_cell_set_header_style (
+ cnt_editor,
+ gtk_toggle_button_get_active (
+ GTK_TOGGLE_BUTTON (dialog->priv->header_style_check)),
+ dialog->priv->scope);
}
static void
html_editor_cell_dialog_set_width (EHTMLEditorCellDialog *dialog)
{
- GValue val = { 0 };
- gchar *width;
+ EHTMLEditor *editor;
+ EContentEditor *cnt_editor;
- if (!gtk_toggle_button_get_active (
- GTK_TOGGLE_BUTTON (dialog->priv->width_check))) {
+ editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
+ cnt_editor = e_html_editor_get_content_editor (editor);
- width = g_strdup ("auto");
- } else {
+ if (gtk_toggle_button_get_active (
+ GTK_TOGGLE_BUTTON (dialog->priv->width_check))) {
- width = g_strdup_printf (
- "%d%s",
+ e_content_editor_cell_set_width (
+ cnt_editor,
gtk_spin_button_get_value_as_int (
GTK_SPIN_BUTTON (dialog->priv->width_edit)),
- ((gtk_combo_box_get_active (
+ (gtk_combo_box_get_active (
GTK_COMBO_BOX (dialog->priv->width_units)) == 0) ?
- "px" : "%"));
- }
+ E_CONTENT_EDITOR_UNIT_PIXEL :
+ E_CONTENT_EDITOR_UNIT_PERCENTAGE,
+ dialog->priv->scope);
+ } else
+ e_content_editor_cell_set_width (
+ cnt_editor, 0, E_CONTENT_EDITOR_UNIT_AUTO, dialog->priv->scope);
+}
- g_value_init (&val, G_TYPE_STRING);
- g_value_take_string (&val, width);
- html_editor_cell_dialog_set_attribute (
- dialog, webkit_dom_html_table_cell_element_set_width, &val, NULL);
+static void
+html_editor_cell_dialog_width_units_changed (GtkWidget *widget,
+ EHTMLEditorCellDialog *dialog)
+{
+ if (gtk_combo_box_get_active (GTK_COMBO_BOX (dialog->priv->width_units)) == 0) {
+ gtk_spin_button_set_range (
+ GTK_SPIN_BUTTON (dialog->priv->width_edit), 0, G_MAXUINT);
+ } else
+ gtk_spin_button_set_range (
+ GTK_SPIN_BUTTON (dialog->priv->width_edit), 0, 100);
- g_free (width);
+ html_editor_cell_dialog_set_width (dialog);
}
static void
html_editor_cell_dialog_set_column_span (EHTMLEditorCellDialog *dialog)
{
- GValue val = { 0 };
+ EHTMLEditor *editor;
+ EContentEditor *cnt_editor;
- g_value_init (&val, G_TYPE_ULONG);
- g_value_set_ulong (
- &val,
- gtk_spin_button_get_value_as_int (
- GTK_SPIN_BUTTON (dialog->priv->col_span_edit)));
+ editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
+ cnt_editor = e_html_editor_get_content_editor (editor);
- html_editor_cell_dialog_set_attribute (
- dialog, webkit_dom_html_table_cell_element_set_col_span, &val, NULL);
+ e_content_editor_cell_set_col_span (
+ cnt_editor,
+ gtk_spin_button_get_value_as_int (
+ GTK_SPIN_BUTTON (dialog->priv->col_span_edit)),
+ dialog->priv->scope);
}
static void
html_editor_cell_dialog_set_row_span (EHTMLEditorCellDialog *dialog)
{
- GValue val = { 0 };
+ EHTMLEditor *editor;
+ EContentEditor *cnt_editor;
- g_value_init (&val, G_TYPE_ULONG);
- g_value_set_ulong (
- &val,
- gtk_spin_button_get_value_as_int (
- GTK_SPIN_BUTTON (dialog->priv->row_span_edit)));
+ editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
+ cnt_editor = e_html_editor_get_content_editor (editor);
- html_editor_cell_dialog_set_attribute (
- dialog, webkit_dom_html_table_cell_element_set_row_span, &val, NULL);
+ e_content_editor_cell_set_row_span (
+ cnt_editor,
+ gtk_spin_button_get_value_as_int (
+ GTK_SPIN_BUTTON (dialog->priv->row_span_edit)),
+ dialog->priv->scope);
}
static void
html_editor_cell_dialog_set_background_color (EHTMLEditorCellDialog *dialog)
{
- gchar *color = NULL;
+ EHTMLEditor *editor;
+ EContentEditor *cnt_editor;
GdkRGBA rgba;
- GValue val = { 0 };
+
+ editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
+ cnt_editor = e_html_editor_get_content_editor (editor);
e_color_combo_get_current_color (
E_COLOR_COMBO (dialog->priv->background_color_picker), &rgba);
- if (rgba.alpha != 0.0)
- color = g_strdup_printf ("#%06x", e_rgba_to_value (&rgba));
- else
- color = g_strdup ("");
-
- g_value_init (&val, G_TYPE_STRING);
- g_value_take_string (&val, color);
-
- html_editor_cell_dialog_set_attribute (
- dialog, webkit_dom_html_table_cell_element_set_bg_color, &val, NULL);
-
- g_free (color);
+ e_content_editor_cell_set_background_color (cnt_editor, &rgba, dialog->priv->scope);
}
static void
-cell_set_background_image (WebKitDOMHTMLTableCellElement *cell,
- const gchar *uri,
- EHTMLEditorCellDialog *dialog)
+html_editor_cell_dialog_set_background_image (EHTMLEditorCellDialog *dialog)
{
EHTMLEditor *editor;
- EHTMLEditorView *view;
+ EContentEditor *cnt_editor;
+ gchar *uri;
editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
- view = e_html_editor_get_view (editor);
-
- if (uri && *uri) {
- e_html_editor_selection_replace_image_src (
- e_html_editor_view_get_selection (view),
- WEBKIT_DOM_ELEMENT (cell),
- uri);
- } else
- remove_image_attributes_from_element (WEBKIT_DOM_ELEMENT (cell));
-
- gtk_widget_set_sensitive (dialog->priv->remove_image_button, uri && *uri);
-}
-
-static void
-html_editor_cell_dialog_set_background_image (EHTMLEditorCellDialog *dialog)
-{
- gchar *uri;
- GValue val = { 0 };
+ cnt_editor = e_html_editor_get_content_editor (editor);
uri = gtk_file_chooser_get_uri (
GTK_FILE_CHOOSER (dialog->priv->background_image_chooser));
- g_value_init (&val, G_TYPE_STRING);
- g_value_take_string (&val, uri);
+ e_content_editor_cell_set_background_image_uri (cnt_editor, uri);
+
+ gtk_widget_set_sensitive (dialog->priv->remove_image_button, uri && *uri);
- html_editor_cell_dialog_set_attribute (
- dialog, cell_set_background_image, &val, dialog);
+ g_free (uri);
}
static void
html_editor_cell_dialog_remove_image (EHTMLEditorCellDialog *dialog)
{
- remove_image_attributes_from_element (
- WEBKIT_DOM_ELEMENT (dialog->priv->cell));
+ EHTMLEditor *editor;
+ EContentEditor *cnt_editor;
+
+ editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
+ cnt_editor = e_html_editor_get_content_editor (editor);
+
+ e_content_editor_cell_set_background_image_uri (cnt_editor, NULL);
gtk_file_chooser_unselect_all (
GTK_FILE_CHOOSER (dialog->priv->background_image_chooser));
@@ -504,123 +295,72 @@ static void
html_editor_cell_dialog_show (GtkWidget *widget)
{
EHTMLEditor *editor;
+ EContentEditor *cnt_editor;
+ EContentEditorUnit unit;
EHTMLEditorCellDialog *dialog;
- EHTMLEditorView *view;
- gchar *tmp;
- GdkRGBA color;
+ GdkRGBA rgba;
+ gchar *alignment, *uri;
+ gint width;
dialog = E_HTML_EDITOR_CELL_DIALOG (widget);
editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
- view = e_html_editor_get_view (editor);
+ cnt_editor = e_html_editor_get_content_editor (editor);
- if (!e_html_editor_view_is_undo_redo_in_progress (view)) {
- EHTMLEditorViewHistoryEvent *ev;
- WebKitDOMElement *table;
-
- ev = g_new0 (EHTMLEditorViewHistoryEvent, 1);
- ev->type = HISTORY_TABLE_DIALOG;
-
- e_html_editor_selection_get_selection_coordinates (
- e_html_editor_view_get_selection (view),
- &ev->before.start.x, &ev->before.start.y,
- &ev->before.end.x, &ev->before.end.y);
-
- table = e_html_editor_dom_node_find_parent_element (
- WEBKIT_DOM_NODE (dialog->priv->cell), "TABLE");
- ev->data.dom.from = webkit_dom_node_clone_node (
- WEBKIT_DOM_NODE (table), TRUE);
- dialog->priv->history_event = ev;
- }
+ e_content_editor_on_cell_dialog_open (cnt_editor);
gtk_toggle_button_set_active (
GTK_TOGGLE_BUTTON (dialog->priv->scope_cell_button), TRUE);
- tmp = webkit_dom_html_table_cell_element_get_align (
- WEBKIT_DOM_HTML_TABLE_CELL_ELEMENT (dialog->priv->cell));
+ alignment = e_content_editor_cell_get_align (cnt_editor);
gtk_combo_box_set_active_id (
GTK_COMBO_BOX (dialog->priv->halign_combo),
- (tmp && *tmp) ? tmp : "left");
- g_free (tmp);
+ (alignment && *alignment) ? alignment : "left");
+ g_free (alignment);
- tmp = webkit_dom_html_table_cell_element_get_v_align (
- WEBKIT_DOM_HTML_TABLE_CELL_ELEMENT (dialog->priv->cell));
+ alignment = e_content_editor_cell_get_v_align (cnt_editor);
gtk_combo_box_set_active_id (
GTK_COMBO_BOX (dialog->priv->valign_combo),
- (tmp && *tmp) ? tmp : "middle");
- g_free (tmp);
+ (alignment && *alignment) ? alignment : "middle");
+ g_free (alignment);
gtk_toggle_button_set_active (
GTK_TOGGLE_BUTTON (dialog->priv->wrap_text_check),
- !webkit_dom_html_table_cell_element_get_no_wrap (
- WEBKIT_DOM_HTML_TABLE_CELL_ELEMENT (dialog->priv->cell)));
+ e_content_editor_cell_get_wrap (cnt_editor));
- tmp = webkit_dom_element_get_tag_name (
- WEBKIT_DOM_ELEMENT (dialog->priv->cell));
gtk_toggle_button_set_active (
GTK_TOGGLE_BUTTON (dialog->priv->header_style_check),
- (g_ascii_strncasecmp (tmp, "TH", 2) == 0));
- g_free (tmp);
-
- tmp = webkit_dom_html_table_cell_element_get_width (
- WEBKIT_DOM_HTML_TABLE_CELL_ELEMENT (dialog->priv->cell));
- if (tmp && *tmp) {
- gint val = atoi (tmp);
- gtk_spin_button_set_value (
- GTK_SPIN_BUTTON (dialog->priv->width_edit), val);
- gtk_toggle_button_set_active (
- GTK_TOGGLE_BUTTON (dialog->priv->width_check), TRUE);
- } else {
- gtk_spin_button_set_value (
- GTK_SPIN_BUTTON (dialog->priv->width_edit), 0);
- gtk_toggle_button_set_active (
- GTK_TOGGLE_BUTTON (dialog->priv->width_check), FALSE);
- }
+ e_content_editor_cell_is_header (cnt_editor));
+
+ width = e_content_editor_cell_get_width (cnt_editor, &unit);
+ gtk_spin_button_set_value (
+ GTK_SPIN_BUTTON (dialog->priv->width_edit), width);
+ gtk_toggle_button_set_active (
+ GTK_TOGGLE_BUTTON (dialog->priv->width_check),
+ unit != E_CONTENT_EDITOR_UNIT_AUTO);
gtk_combo_box_set_active_id (
- GTK_COMBO_BOX (dialog->priv->width_units), "units-px");
- g_free (tmp);
+ GTK_COMBO_BOX (dialog->priv->width_units),
+ (unit == E_CONTENT_EDITOR_UNIT_PIXEL) ? "units-px" : "units-percent");
gtk_spin_button_set_value (
GTK_SPIN_BUTTON (dialog->priv->row_span_edit),
- webkit_dom_html_table_cell_element_get_row_span (
- WEBKIT_DOM_HTML_TABLE_CELL_ELEMENT (dialog->priv->cell)));
+ e_content_editor_cell_get_row_span (cnt_editor));
+
gtk_spin_button_set_value (
GTK_SPIN_BUTTON (dialog->priv->col_span_edit),
- webkit_dom_html_table_cell_element_get_col_span (
- WEBKIT_DOM_HTML_TABLE_CELL_ELEMENT (dialog->priv->cell)));
-
- if (webkit_dom_element_has_attribute (
- WEBKIT_DOM_ELEMENT (dialog->priv->cell), "background")) {
- tmp = webkit_dom_element_get_attribute (
- WEBKIT_DOM_ELEMENT (dialog->priv->cell), "data-uri");
+ e_content_editor_cell_get_col_span (cnt_editor));
+ uri = e_content_editor_cell_get_background_image_uri (cnt_editor);
+ if (uri && *uri)
gtk_file_chooser_set_uri (
- GTK_FILE_CHOOSER (dialog->priv->background_image_chooser),
- tmp);
-
- g_free (tmp);
- } else {
+ GTK_FILE_CHOOSER (dialog->priv->background_image_chooser), uri);
+ else
gtk_file_chooser_unselect_all (
GTK_FILE_CHOOSER (dialog->priv->background_image_chooser));
- }
+ g_free (uri);
- tmp = webkit_dom_html_table_cell_element_get_bg_color (
- WEBKIT_DOM_HTML_TABLE_CELL_ELEMENT (dialog->priv->cell));
- if (tmp && *tmp) {
- if (gdk_rgba_parse (&color, tmp)) {
- e_color_combo_set_current_color (
- E_COLOR_COMBO (dialog->priv->background_color_picker),
- &color);
- } else {
- e_color_combo_set_current_color (
- E_COLOR_COMBO (dialog->priv->background_color_picker),
- &transparent);
- }
- } else {
- e_color_combo_set_current_color (
- E_COLOR_COMBO (dialog->priv->background_color_picker),
- &transparent);
- }
- g_free (tmp);
+ e_content_editor_cell_get_background_color (cnt_editor, &rgba);
+ e_color_combo_set_current_color (
+ E_COLOR_COMBO (dialog->priv->background_color_picker), &rgba);
GTK_WIDGET_CLASS (e_html_editor_cell_dialog_parent_class)->show (widget);
}
@@ -628,43 +368,15 @@ html_editor_cell_dialog_show (GtkWidget *widget)
static void
html_editor_cell_dialog_hide (GtkWidget *widget)
{
- EHTMLEditorCellDialogPrivate *priv;
- EHTMLEditorViewHistoryEvent *ev;
-
- priv = E_HTML_EDITOR_CELL_DIALOG_GET_PRIVATE (widget);
- ev = priv->history_event;
-
- if (ev) {
- EHTMLEditorCellDialog *dialog;
- EHTMLEditor *editor;
- EHTMLEditorSelection *selection;
- EHTMLEditorView *view;
- WebKitDOMElement *table;
-
- dialog = E_HTML_EDITOR_CELL_DIALOG (widget);
- editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
- view = e_html_editor_get_view (editor);
- selection = e_html_editor_view_get_selection (view);
-
- table = e_html_editor_dom_node_find_parent_element (
- WEBKIT_DOM_NODE (dialog->priv->cell), "TABLE");
-
- ev->data.dom.to = webkit_dom_node_clone_node (
- WEBKIT_DOM_NODE (table), TRUE);
-
- if (!webkit_dom_node_is_equal_node (ev->data.dom.from, ev->data.dom.to)) {
- e_html_editor_selection_get_selection_coordinates (
- selection, &ev->after.start.x, &ev->after.start.y, &ev->after.end.x,
&ev->after.end.y);
- e_html_editor_view_insert_new_history_event (view, ev);
- } else {
- g_object_unref (ev->data.dom.from);
- g_object_unref (ev->data.dom.to);
- g_free (ev);
- }
- }
+ EHTMLEditor *editor;
+ EHTMLEditorCellDialog *dialog;
+ EContentEditor *cnt_editor;
+
+ dialog = E_HTML_EDITOR_CELL_DIALOG (widget);
+ editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
+ cnt_editor = e_html_editor_get_content_editor (editor);
- g_object_unref (priv->cell);
- priv->cell = NULL;
+ e_content_editor_on_cell_dialog_close (cnt_editor);
GTK_WIDGET_CLASS (e_html_editor_cell_dialog_parent_class)->hide (widget);
}
@@ -842,7 +554,8 @@ e_html_editor_cell_dialog_init (EHTMLEditorCellDialog *dialog)
gtk_grid_attach (grid, widget, 0, 0, 1, 1);
dialog->priv->width_check = widget;
- widget = gtk_spin_button_new_with_range (0, G_MAXUINT, 1);
+ widget = gtk_spin_button_new_with_range (1, 100, 1);
+ gtk_spin_button_set_digits (GTK_SPIN_BUTTON (widget), 0);
gtk_grid_attach (grid, widget, 1, 0, 1, 1);
dialog->priv->width_edit = widget;
@@ -855,14 +568,14 @@ e_html_editor_cell_dialog_init (EHTMLEditorCellDialog *dialog)
G_BINDING_SYNC_CREATE);
widget = gtk_combo_box_text_new ();
- gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (widget), "unit-px", "px");
- gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (widget), "unit-percent", "%");
+ gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (widget), "units-px", "px");
+ gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (widget), "units-percent", "%");
gtk_grid_attach (grid, widget, 2, 0, 1, 1);
dialog->priv->width_units = widget;
- g_signal_connect_swapped (
+ g_signal_connect (
widget, "changed",
- G_CALLBACK (html_editor_cell_dialog_set_width), dialog);
+ G_CALLBACK (html_editor_cell_dialog_width_units_changed), dialog);
e_binding_bind_property (
dialog->priv->width_check, "active",
widget, "sensitive",
@@ -975,23 +688,3 @@ e_html_editor_cell_dialog_new (EHTMLEditor *editor)
"title", _("Cell Properties"),
NULL));
}
-
-void
-e_html_editor_cell_dialog_show (EHTMLEditorCellDialog *dialog,
- WebKitDOMNode *cell)
-{
- EHTMLEditorCellDialogClass *class;
-
- g_return_if_fail (E_IS_HTML_EDITOR_CELL_DIALOG (dialog));
- g_return_if_fail (cell != NULL);
-
- dialog->priv->cell = e_html_editor_dom_node_find_parent_element (cell, "TD");
- if (dialog->priv->cell == NULL) {
- dialog->priv->cell =
- e_html_editor_dom_node_find_parent_element (cell, "TH");
- }
-
- class = E_HTML_EDITOR_CELL_DIALOG_GET_CLASS (dialog);
- GTK_WIDGET_CLASS (class)->show (GTK_WIDGET (dialog));
-}
-
diff --git a/e-util/e-html-editor-cell-dialog.h b/e-util/e-html-editor-cell-dialog.h
index 3a7f608..68ae1bb 100644
--- a/e-util/e-html-editor-cell-dialog.h
+++ b/e-util/e-html-editor-cell-dialog.h
@@ -64,8 +64,6 @@ struct _EHTMLEditorCellDialogClass {
GType e_html_editor_cell_dialog_get_type
(void) G_GNUC_CONST;
GtkWidget * e_html_editor_cell_dialog_new (EHTMLEditor *editor);
-void e_html_editor_cell_dialog_show (EHTMLEditorCellDialog *dialog,
- WebKitDOMNode *cell);
G_END_DECLS
diff --git a/e-util/e-html-editor-dialog.h b/e-util/e-html-editor-dialog.h
index 37fc7a5..f1f5700 100644
--- a/e-util/e-html-editor-dialog.h
+++ b/e-util/e-html-editor-dialog.h
@@ -62,6 +62,16 @@ struct _EHTMLEditorDialogClass {
GtkWindowClass parent_class;
};
+#if 0 /* FIXME WK2 */
+struct _EContentEditorDialogInterface {
+ GTypeInterface parent_interface;
+
+ void (*dialog_opened) (EContentEditorDialog *dialog);
+
+ void (*dialog_closed) (EContentEditorDialog *dialog);
+};
+#endif
+
GType e_html_editor_dialog_get_type (void) G_GNUC_CONST;
EHTMLEditor * e_html_editor_dialog_get_editor (EHTMLEditorDialog *dialog);
GtkBox * e_html_editor_dialog_get_button_box
diff --git a/e-util/e-html-editor-find-dialog.c b/e-util/e-html-editor-find-dialog.c
index 6fe61cf..f1ad2f2 100644
--- a/e-util/e-html-editor-find-dialog.c
+++ b/e-util/e-html-editor-find-dialog.c
@@ -41,6 +41,9 @@ struct _EHTMLEditorFindDialogPrivate {
GtkWidget *find_button;
GtkWidget *result_label;
+
+ EContentEditor *cnt_editor;
+ gulong find_done_handler_id;
};
G_DEFINE_TYPE (
@@ -56,6 +59,17 @@ reset_dialog (EHTMLEditorFindDialog *dialog)
}
static void
+html_editor_find_dialog_hide (GtkWidget *widget)
+{
+ EHTMLEditorFindDialog *dialog = E_HTML_EDITOR_FIND_DIALOG (widget);
+
+ e_content_editor_on_find_dialog_close (dialog->priv->cnt_editor);
+
+ /* Chain up to parent's implementation */
+ GTK_WIDGET_CLASS (e_html_editor_find_dialog_parent_class)->hide (widget);
+}
+
+static void
html_editor_find_dialog_show (GtkWidget *widget)
{
EHTMLEditorFindDialog *dialog = E_HTML_EDITOR_FIND_DIALOG (widget);
@@ -63,48 +77,45 @@ html_editor_find_dialog_show (GtkWidget *widget)
reset_dialog (dialog);
gtk_widget_grab_focus (dialog->priv->entry);
+ e_content_editor_on_find_dialog_open (dialog->priv->cnt_editor);
+
/* Chain up to parent's implementation */
GTK_WIDGET_CLASS (e_html_editor_find_dialog_parent_class)->show (widget);
}
static void
-html_editor_find_dialog_find_cb (EHTMLEditorFindDialog *dialog)
+content_editor_find_done_cb (EContentEditor *cnt_editor,
+ guint match_count,
+ EHTMLEditorFindDialog *dialog)
{
- gboolean found;
- EHTMLEditor *editor;
- EHTMLEditorView *view;
-
- editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
- view = e_html_editor_get_view (editor);
- found = webkit_web_view_search_text (
- WEBKIT_WEB_VIEW (view),
- gtk_entry_get_text (
- GTK_ENTRY (dialog->priv->entry)),
- gtk_toggle_button_get_active (
- GTK_TOGGLE_BUTTON (
- dialog->priv->case_sensitive)),
- !gtk_toggle_button_get_active (
- GTK_TOGGLE_BUTTON (
- dialog->priv->backwards)),
- gtk_toggle_button_get_active (
- GTK_TOGGLE_BUTTON (
- dialog->priv->wrap_search)));
-
- gtk_widget_set_sensitive (dialog->priv->find_button, found);
-
- /* We give focus to WebKit so that the selection is highlited.
- * Without focus selection is not visible (at least with my default
- * color scheme). The focus in fact is not given to WebKit, because
- * this dialog is modal, but it satisfies it in a way that it paints
- * the selection :) */
- gtk_widget_grab_focus (GTK_WIDGET (view));
-
- if (!found) {
- gtk_label_set_label (
- GTK_LABEL (dialog->priv->result_label),
- N_("No match found"));
+ if (match_count) {
+ gtk_widget_hide (dialog->priv->result_label);
+ } else {
+ gtk_label_set_label (GTK_LABEL (dialog->priv->result_label), _("No match found"));
gtk_widget_show (dialog->priv->result_label);
}
+
+ gtk_widget_set_sensitive (dialog->priv->find_button, match_count > 0);
+}
+
+static void
+html_editor_find_dialog_find_cb (EHTMLEditorFindDialog *dialog)
+{
+ guint32 flags = E_CONTENT_EDITOR_FIND_NEXT;
+
+ if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->backwards)))
+ flags |= E_CONTENT_EDITOR_FIND_MODE_BACKWARDS;
+
+ if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->case_sensitive)))
+ flags |= E_CONTENT_EDITOR_FIND_CASE_INSENSITIVE;
+
+ if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->wrap_search)))
+ flags |= E_CONTENT_EDITOR_FIND_WRAP_AROUND;
+
+ e_content_editor_find (
+ dialog->priv->cnt_editor,
+ flags,
+ gtk_entry_get_text (GTK_ENTRY (dialog->priv->entry)));
}
static gboolean
@@ -125,13 +136,59 @@ entry_key_release_event (GtkWidget *widget,
}
static void
+html_editor_find_dialog_dispose (GObject *object)
+{
+ EHTMLEditorFindDialogPrivate *priv;
+
+ priv = E_HTML_EDITOR_FIND_DIALOG_GET_PRIVATE (object);
+
+ if (priv->find_done_handler_id > 0) {
+ g_signal_handler_disconnect (
+ priv->cnt_editor,
+ priv->find_done_handler_id);
+ priv->find_done_handler_id = 0;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (e_html_editor_find_dialog_parent_class)->dispose (object);
+}
+
+static void
+html_editor_find_dialog_constructed (GObject *object)
+{
+ EHTMLEditor *editor;
+ EHTMLEditorFindDialog *dialog;
+ EContentEditor *cnt_editor;
+
+ dialog = E_HTML_EDITOR_FIND_DIALOG (object);
+ dialog->priv = E_HTML_EDITOR_FIND_DIALOG_GET_PRIVATE (dialog);
+
+ editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
+ cnt_editor = e_html_editor_get_content_editor (editor);
+
+ dialog->priv->find_done_handler_id = g_signal_connect (
+ cnt_editor, "find-done",
+ G_CALLBACK (content_editor_find_done_cb), dialog);
+
+ dialog->priv->cnt_editor = cnt_editor;
+
+ G_OBJECT_CLASS (e_html_editor_find_dialog_parent_class)->constructed (object);
+}
+
+static void
e_html_editor_find_dialog_class_init (EHTMLEditorFindDialogClass *class)
{
+ GObjectClass *object_class;
GtkWidgetClass *widget_class;
g_type_class_add_private (class, sizeof (EHTMLEditorFindDialogPrivate));
+ object_class = G_OBJECT_CLASS (class);
+ object_class->constructed = html_editor_find_dialog_constructed;
+ object_class->dispose = html_editor_find_dialog_dispose;
+
widget_class = GTK_WIDGET_CLASS (class);
+ widget_class->hide = html_editor_find_dialog_hide;
widget_class->show = html_editor_find_dialog_show;
}
@@ -217,9 +274,8 @@ e_html_editor_find_dialog_new (EHTMLEditor *editor)
void
e_html_editor_find_dialog_find_next (EHTMLEditorFindDialog *dialog)
{
- if (gtk_entry_get_text_length (GTK_ENTRY (dialog->priv->entry)) == 0) {
+ if (gtk_entry_get_text_length (GTK_ENTRY (dialog->priv->entry)) == 0)
return;
- }
html_editor_find_dialog_find_cb (dialog);
}
diff --git a/e-util/e-html-editor-hrule-dialog.c b/e-util/e-html-editor-hrule-dialog.c
index bb92276..5dc6860 100644
--- a/e-util/e-html-editor-hrule-dialog.c
+++ b/e-util/e-html-editor-hrule-dialog.c
@@ -23,11 +23,8 @@
#endif
#include "e-html-editor-hrule-dialog.h"
-#include "e-html-editor-utils.h"
-#include "e-html-editor-view.h"
#include <glib/gi18n-lib.h>
-#include <webkit/webkitdom.h>
#include <stdlib.h>
#define E_HTML_EDITOR_HRULE_DIALOG_GET_PRIVATE(obj) \
@@ -41,10 +38,6 @@ struct _EHTMLEditorHRuleDialogPrivate {
GtkWidget *alignment_combo;
GtkWidget *shaded_check;
-
- WebKitDOMHTMLHRElement *hr_element;
-
- EHTMLEditorViewHistoryEvent *history_event;
};
G_DEFINE_TYPE (
@@ -55,185 +48,148 @@ G_DEFINE_TYPE (
static void
html_editor_hrule_dialog_set_alignment (EHTMLEditorHRuleDialog *dialog)
{
- const gchar *alignment;
+ EHTMLEditor *editor;
+ EContentEditor *cnt_editor;
+ const gchar *value;
- g_return_if_fail (WEBKIT_DOM_IS_HTMLHR_ELEMENT (dialog->priv->hr_element));
+ editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
+ cnt_editor = e_html_editor_get_content_editor (editor);
- alignment = gtk_combo_box_get_active_id (
- GTK_COMBO_BOX (dialog->priv->alignment_combo));
+ value = gtk_combo_box_get_active_id (
+ GTK_COMBO_BOX (dialog->priv->alignment_combo));
- webkit_dom_htmlhr_element_set_align (dialog->priv->hr_element, alignment);
+ e_content_editor_h_rule_set_align (cnt_editor, value);
}
static void
html_editor_hrule_dialog_get_alignment (EHTMLEditorHRuleDialog *dialog)
{
- gchar *alignment;
-
- g_return_if_fail (WEBKIT_DOM_IS_HTMLHR_ELEMENT (dialog->priv->hr_element));
+ EHTMLEditor *editor;
+ EContentEditor *cnt_editor;
+ gchar *value;
- alignment = webkit_dom_htmlhr_element_get_align (dialog->priv->hr_element);
+ editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
+ cnt_editor = e_html_editor_get_content_editor (editor);
- gtk_combo_box_set_active_id (
- GTK_COMBO_BOX (dialog->priv->alignment_combo), alignment);
- g_free (alignment);
+ value = e_content_editor_h_rule_get_align (cnt_editor);
+ if (value && *value)
+ gtk_combo_box_set_active_id (
+ GTK_COMBO_BOX (dialog->priv->alignment_combo), value);
+ g_free (value);
}
static void
html_editor_hrule_dialog_set_size (EHTMLEditorHRuleDialog *dialog)
{
- gchar *size;
-
- g_return_if_fail (WEBKIT_DOM_IS_HTMLHR_ELEMENT (dialog->priv->hr_element));
-
- size = g_strdup_printf (
- "%d",
- (gint) gtk_spin_button_get_value (
- GTK_SPIN_BUTTON (dialog->priv->size_edit)));
+ EHTMLEditor *editor;
+ EContentEditor *cnt_editor;
+ gint value;
- webkit_dom_htmlhr_element_set_size (dialog->priv->hr_element, size);
+ editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
+ cnt_editor = e_html_editor_get_content_editor (editor);
- g_free (size);
+ value = gtk_spin_button_get_value_as_int GTK_SPIN_BUTTON (dialog->priv->size_edit);
+ e_content_editor_h_rule_set_size (cnt_editor, value);
}
static void
html_editor_hrule_dialog_get_size (EHTMLEditorHRuleDialog *dialog)
{
- gchar *size;
- gint size_int = 0;
+ EHTMLEditor *editor;
+ EContentEditor *cnt_editor;
+ gint value;
- g_return_if_fail (WEBKIT_DOM_IS_HTMLHR_ELEMENT (dialog->priv->hr_element));
+ editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
+ cnt_editor = e_html_editor_get_content_editor (editor);
- size = webkit_dom_htmlhr_element_get_size (dialog->priv->hr_element);
- if (size && *size) {
- size_int = atoi (size);
- }
-
- if (size_int == 0) {
- size_int = 2;
- }
+ value = e_content_editor_h_rule_get_size (cnt_editor);
gtk_spin_button_set_value (
- GTK_SPIN_BUTTON (dialog->priv->size_edit), (gdouble) size_int);
-
- g_free (size);
+ GTK_SPIN_BUTTON (dialog->priv->size_edit), (gdouble) value);
}
static void
html_editor_hrule_dialog_set_width (EHTMLEditorHRuleDialog *dialog)
{
- gchar *width, *units;
+ EHTMLEditor *editor;
+ EContentEditor *cnt_editor;
- g_return_if_fail (WEBKIT_DOM_IS_HTMLHR_ELEMENT (dialog->priv->hr_element));
+ editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
+ cnt_editor = e_html_editor_get_content_editor (editor);
- units = gtk_combo_box_text_get_active_text (
- GTK_COMBO_BOX_TEXT (dialog->priv->unit_combo));
- width = g_strdup_printf (
- "%d%s",
- (gint) gtk_spin_button_get_value (
+ e_content_editor_h_rule_set_width (
+ cnt_editor,
+ gtk_spin_button_get_value_as_int (
GTK_SPIN_BUTTON (dialog->priv->width_edit)),
- units);
-
- webkit_dom_htmlhr_element_set_width (dialog->priv->hr_element, width);
-
- g_free (units);
- g_free (width);
+ (gtk_combo_box_get_active (
+ GTK_COMBO_BOX (dialog->priv->unit_combo)) == 0) ?
+ E_CONTENT_EDITOR_UNIT_PIXEL :
+ E_CONTENT_EDITOR_UNIT_PERCENTAGE);
}
static void
html_editor_hrule_dialog_get_width (EHTMLEditorHRuleDialog *dialog)
{
- gchar *width;
- const gchar *units;
- gint width_int = 0;
-
- g_return_if_fail (WEBKIT_DOM_IS_HTMLHR_ELEMENT (dialog->priv->hr_element));
-
- width = webkit_dom_htmlhr_element_get_width (dialog->priv->hr_element);
- if (width && *width) {
- width_int = atoi (width);
-
- if (strstr (width, "%") != NULL) {
- units = "units-percent";
- } else {
- units = "units-px";
- }
- }
+ EHTMLEditor *editor;
+ EContentEditor *cnt_editor;
+ EContentEditorUnit unit;
+ gint value;
- if (width_int == 0) {
- width_int = 100;
- units = "units-percent";
- }
+ editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ value = e_content_editor_h_rule_get_width (cnt_editor, &unit);
gtk_spin_button_set_value (
- GTK_SPIN_BUTTON (dialog->priv->width_edit), (gdouble) width_int);
+ GTK_SPIN_BUTTON (dialog->priv->width_edit),
+ value == 0 && unit == E_CONTENT_EDITOR_UNIT_PERCENTAGE ? 100 : value);
gtk_combo_box_set_active_id (
- GTK_COMBO_BOX (dialog->priv->unit_combo), units);
-
- g_free (width);
+ GTK_COMBO_BOX (dialog->priv->unit_combo),
+ unit == E_CONTENT_EDITOR_UNIT_PIXEL ? "units-px" : "units-percent");
}
static void
html_editor_hrule_dialog_set_shading (EHTMLEditorHRuleDialog *dialog)
{
- gboolean no_shade;
+ EHTMLEditor *editor;
+ EContentEditor *cnt_editor;
+ gboolean value;
- g_return_if_fail (WEBKIT_DOM_IS_HTMLHR_ELEMENT (dialog->priv->hr_element));
+ editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
+ cnt_editor = e_html_editor_get_content_editor (editor);
- no_shade = !gtk_toggle_button_get_active (
- GTK_TOGGLE_BUTTON (dialog->priv->shaded_check));
+ value = !gtk_toggle_button_get_active (
+ GTK_TOGGLE_BUTTON (dialog->priv->shaded_check));
- webkit_dom_htmlhr_element_set_no_shade (dialog->priv->hr_element, no_shade);
+ e_content_editor_h_rule_set_no_shade (cnt_editor, value);
}
static void
html_editor_hrule_dialog_get_shading (EHTMLEditorHRuleDialog *dialog)
{
- g_return_if_fail (WEBKIT_DOM_IS_HTMLHR_ELEMENT (dialog->priv->hr_element));
+ EHTMLEditor *editor;
+ EContentEditor *cnt_editor;
+ gboolean value = FALSE;
+
+ editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ value = e_content_editor_h_rule_get_no_shade (cnt_editor);
gtk_toggle_button_set_active (
- GTK_TOGGLE_BUTTON (dialog->priv->shaded_check),
- !webkit_dom_htmlhr_element_get_no_shade (dialog->priv->hr_element));
+ GTK_TOGGLE_BUTTON (dialog->priv->shaded_check), !value);
}
static void
html_editor_hrule_dialog_hide (GtkWidget *widget)
{
- EHTMLEditorHRuleDialogPrivate *priv;
- EHTMLEditorViewHistoryEvent *ev;
-
- priv = E_HTML_EDITOR_HRULE_DIALOG_GET_PRIVATE (widget);
- ev = priv->history_event;
-
- if (ev) {
- EHTMLEditorHRuleDialog *dialog;
- EHTMLEditor *editor;
- EHTMLEditorSelection *selection;
- EHTMLEditorView *view;
-
- dialog = E_HTML_EDITOR_HRULE_DIALOG (widget);
- editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
- view = e_html_editor_get_view (editor);
- selection = e_html_editor_view_get_selection (view);
-
- ev->data.dom.to = webkit_dom_node_clone_node (
- WEBKIT_DOM_NODE (priv->hr_element), FALSE);
-
- if (!webkit_dom_node_is_equal_node (ev->data.dom.from, ev->data.dom.to)) {
- e_html_editor_selection_get_selection_coordinates (
- selection, &ev->after.start.x, &ev->after.start.y, &ev->after.end.x,
&ev->after.end.y);
- e_html_editor_view_insert_new_history_event (view, ev);
-
- if (!ev->data.dom.from)
- g_object_unref (priv->hr_element);
- } else {
- g_object_unref (ev->data.dom.from);
- g_object_unref (ev->data.dom.to);
- g_free (ev);
- }
- }
+ EHTMLEditor *editor;
+ EHTMLEditorHRuleDialog *dialog;
+ EContentEditor *cnt_editor;
+
+ dialog = E_HTML_EDITOR_HRULE_DIALOG (widget);
+ editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
+ cnt_editor = e_html_editor_get_content_editor (editor);
- priv->hr_element = NULL;
+ e_content_editor_on_h_rule_dialog_close (cnt_editor);
GTK_WIDGET_CLASS (e_html_editor_hrule_dialog_parent_class)->hide (widget);
}
@@ -243,55 +199,21 @@ html_editor_hrule_dialog_show (GtkWidget *widget)
{
EHTMLEditorHRuleDialog *dialog;
EHTMLEditor *editor;
- EHTMLEditorSelection *selection;
- EHTMLEditorView *view;
-
- WebKitDOMDocument *document;
+ EContentEditor *cnt_editor;
+ gboolean created_new_h_rule = FALSE;
dialog = E_HTML_EDITOR_HRULE_DIALOG (widget);
editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
- view = e_html_editor_get_view (editor);
- selection = e_html_editor_view_get_selection (view);
-
- if (!e_html_editor_view_is_undo_redo_in_progress (view)) {
- EHTMLEditorViewHistoryEvent *ev;
-
- ev = g_new0 (EHTMLEditorViewHistoryEvent, 1);
- ev->type = HISTORY_HRULE_DIALOG;
-
- e_html_editor_selection_get_selection_coordinates (
- selection, &ev->before.start.x, &ev->before.start.y, &ev->before.end.x,
&ev->before.end.y);
- if (dialog->priv->hr_element)
- ev->data.dom.from = webkit_dom_node_clone_node (
- WEBKIT_DOM_NODE (dialog->priv->hr_element), FALSE);
- else
- ev->data.dom.from = NULL;
- dialog->priv->history_event = ev;
- }
-
- if (!dialog->priv->hr_element) {
- WebKitDOMElement *selection_start, *parent, *rule;
-
- document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (view));
- e_html_editor_selection_save (selection);
-
- selection_start = webkit_dom_document_get_element_by_id (
- document, "-x-evo-selection-start-marker");
- parent = get_parent_block_element (WEBKIT_DOM_NODE (selection_start));
-
- rule = webkit_dom_document_create_element (document, "HR", NULL);
-
- /* Insert horizontal rule into body below the caret */
- webkit_dom_node_insert_before (
- webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (parent)),
- WEBKIT_DOM_NODE (rule),
- webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (parent)),
- NULL);
-
- e_html_editor_selection_restore (selection);
+ cnt_editor = e_html_editor_get_content_editor (editor);
- dialog->priv->hr_element = WEBKIT_DOM_HTMLHR_ELEMENT (rule);
+ created_new_h_rule = e_content_editor_on_h_rule_dialog_open (cnt_editor);
+ if (!created_new_h_rule) {
+ html_editor_hrule_dialog_get_alignment (dialog);
+ html_editor_hrule_dialog_get_size (dialog);
+ html_editor_hrule_dialog_get_width (dialog);
+ html_editor_hrule_dialog_get_shading (dialog);
+ } else {
/* For new rule reset the values to default */
gtk_spin_button_set_value (
GTK_SPIN_BUTTON (dialog->priv->width_edit), 100.0);
@@ -309,12 +231,7 @@ html_editor_hrule_dialog_show (GtkWidget *widget)
html_editor_hrule_dialog_set_alignment (dialog);
html_editor_hrule_dialog_set_shading (dialog);
- e_html_editor_view_set_changed (view, TRUE);
- } else {
- html_editor_hrule_dialog_get_alignment (dialog);
- html_editor_hrule_dialog_get_size (dialog);
- html_editor_hrule_dialog_get_width (dialog);
- html_editor_hrule_dialog_get_shading (dialog);
+ e_content_editor_set_changed (cnt_editor, TRUE);
}
/* Chain up to parent implementation */
@@ -448,17 +365,3 @@ e_html_editor_hrule_dialog_new (EHTMLEditor *editor)
"title", _("Rule properties"),
NULL));
}
-
-void
-e_html_editor_hrule_dialog_show (EHTMLEditorHRuleDialog *dialog,
- WebKitDOMNode *rule)
-{
- EHTMLEditorHRuleDialogClass *class;
-
- g_return_if_fail (E_IS_HTML_EDITOR_HRULE_DIALOG (dialog));
-
- dialog->priv->hr_element = rule ? WEBKIT_DOM_HTMLHR_ELEMENT (rule) : NULL;
-
- class = E_HTML_EDITOR_HRULE_DIALOG_GET_CLASS (dialog);
- GTK_WIDGET_CLASS (class)->show (GTK_WIDGET (dialog));
-}
diff --git a/e-util/e-html-editor-hrule-dialog.h b/e-util/e-html-editor-hrule-dialog.h
index b616da9..876fc25 100644
--- a/e-util/e-html-editor-hrule-dialog.h
+++ b/e-util/e-html-editor-hrule-dialog.h
@@ -64,8 +64,6 @@ struct _EHTMLEditorHRuleDialogClass {
GType e_html_editor_hrule_dialog_get_type
(void) G_GNUC_CONST;
GtkWidget * e_html_editor_hrule_dialog_new (EHTMLEditor *editor);
-void e_html_editor_hrule_dialog_show (EHTMLEditorHRuleDialog *dialog,
- WebKitDOMNode *rule);
G_END_DECLS
diff --git a/e-util/e-html-editor-image-dialog.c b/e-util/e-html-editor-image-dialog.c
index 5eb7909..50db162 100644
--- a/e-util/e-html-editor-image-dialog.c
+++ b/e-util/e-html-editor-image-dialog.c
@@ -27,7 +27,6 @@
#include <stdlib.h>
#include <glib/gi18n-lib.h>
-#include "e-html-editor-utils.h"
#include "e-image-chooser-dialog.h"
#define E_HTML_EDITOR_IMAGE_DIALOG_GET_PRIVATE(obj) \
@@ -50,10 +49,6 @@ struct _EHTMLEditorImageDialogPrivate {
GtkWidget *url_edit;
GtkWidget *test_url_button;
-
- WebKitDOMHTMLImageElement *image;
-
- EHTMLEditorViewHistoryEvent *history_event;
};
G_DEFINE_TYPE (
@@ -65,19 +60,16 @@ static void
html_editor_image_dialog_set_src (EHTMLEditorImageDialog *dialog)
{
EHTMLEditor *editor;
- EHTMLEditorSelection *editor_selection;
- EHTMLEditorView *view;
+ EContentEditor *cnt_editor;
gchar *uri;
editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
- view = e_html_editor_get_view (editor);
- editor_selection = e_html_editor_view_get_selection (view);
+ cnt_editor = e_html_editor_get_content_editor (editor);
uri = gtk_file_chooser_get_uri (
GTK_FILE_CHOOSER (dialog->priv->file_chooser));
- e_html_editor_selection_replace_image_src (
- editor_selection, WEBKIT_DOM_ELEMENT (dialog->priv->image), uri);
+ e_content_editor_image_set_src (cnt_editor, uri);
g_free (uri);
}
@@ -85,22 +77,34 @@ html_editor_image_dialog_set_src (EHTMLEditorImageDialog *dialog)
static void
html_editor_image_dialog_set_alt (EHTMLEditorImageDialog *dialog)
{
- webkit_dom_html_image_element_set_alt (
- dialog->priv->image,
- gtk_entry_get_text (GTK_ENTRY (dialog->priv->description_edit)));
+ EHTMLEditor *editor;
+ EContentEditor *cnt_editor;
+ const gchar *value;
+
+ editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
+ cnt_editor = e_html_editor_get_content_editor (editor);
+
+ value = gtk_entry_get_text (GTK_ENTRY (dialog->priv->description_edit));
+
+ e_content_editor_image_set_alt (cnt_editor, value);
}
static void
html_editor_image_dialog_set_width (EHTMLEditorImageDialog *dialog)
{
+ EHTMLEditor *editor;
+ EContentEditor *cnt_editor;
gint requested;
- gulong natural;
+ gint32 natural = 0;
gint width;
- natural = webkit_dom_html_image_element_get_natural_width (
- dialog->priv->image);
+ editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
+ cnt_editor = e_html_editor_get_content_editor (editor);
+
+ natural = e_content_editor_image_get_natural_width (cnt_editor);
+
requested = gtk_spin_button_get_value_as_int (
- GTK_SPIN_BUTTON (dialog->priv->width_edit));
+ GTK_SPIN_BUTTON (dialog->priv->width_edit));
switch (gtk_combo_box_get_active (GTK_COMBO_BOX (dialog->priv->width_units))) {
case 0: /* px */
@@ -119,18 +123,23 @@ html_editor_image_dialog_set_width (EHTMLEditorImageDialog *dialog)
return;
}
- webkit_dom_html_image_element_set_width (dialog->priv->image, width);
+ e_content_editor_image_set_width (cnt_editor, width);
}
static void
html_editor_image_dialog_set_width_units (EHTMLEditorImageDialog *dialog)
{
+ EHTMLEditor *editor;
+ EContentEditor *cnt_editor;
gint requested;
- gulong natural;
+ gint32 natural = 0;
gint width = 0;
- natural = webkit_dom_html_image_element_get_natural_width (
- dialog->priv->image);
+ editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
+ cnt_editor = e_html_editor_get_content_editor (editor);
+
+ natural = e_content_editor_image_get_natural_width (cnt_editor);
+
requested = gtk_spin_button_get_value_as_int (
GTK_SPIN_BUTTON (dialog->priv->width_edit));
@@ -143,8 +152,6 @@ html_editor_image_dialog_set_width_units (EHTMLEditorImageDialog *dialog)
} else {
width = natural;
}
- webkit_dom_element_remove_attribute (
- WEBKIT_DOM_ELEMENT (dialog->priv->image), "style");
gtk_widget_set_sensitive (dialog->priv->width_edit, TRUE);
break;
@@ -154,38 +161,38 @@ html_editor_image_dialog_set_width_units (EHTMLEditorImageDialog *dialog)
} else {
width = 100;
}
- webkit_dom_element_remove_attribute (
- WEBKIT_DOM_ELEMENT (dialog->priv->image), "style");
gtk_widget_set_sensitive (dialog->priv->width_edit, TRUE);
break;
case 2: /* follow */
- webkit_dom_element_set_attribute (
- WEBKIT_DOM_ELEMENT (dialog->priv->image),
- "style",
- "width: auto;",
- NULL);
gtk_widget_set_sensitive (dialog->priv->width_edit, FALSE);
break;
}
- if (width != 0) {
+ e_content_editor_image_set_width_follow (
+ cnt_editor, !gtk_widget_get_sensitive (dialog->priv->width_edit));
+
+ if (width != 0)
gtk_spin_button_set_value (
GTK_SPIN_BUTTON (dialog->priv->width_edit), width);
- }
}
static void
html_editor_image_dialog_set_height (EHTMLEditorImageDialog *dialog)
{
+ EHTMLEditor *editor;
+ EContentEditor *cnt_editor;
gint requested;
- gulong natural;
+ gint32 natural = 0;
gint height;
- natural = webkit_dom_html_image_element_get_natural_height (
- dialog->priv->image);
+ editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
+ cnt_editor = e_html_editor_get_content_editor (editor);
+
+ natural = e_content_editor_image_get_natural_height (cnt_editor);
+
requested = gtk_spin_button_get_value_as_int (
- GTK_SPIN_BUTTON (dialog->priv->height_edit));
+ GTK_SPIN_BUTTON (dialog->priv->height_edit));
switch (gtk_combo_box_get_active (GTK_COMBO_BOX (dialog->priv->height_units))) {
case 0: /* px */
@@ -204,20 +211,25 @@ html_editor_image_dialog_set_height (EHTMLEditorImageDialog *dialog)
return;
}
- webkit_dom_html_image_element_set_height (dialog->priv->image, height);
+ e_content_editor_image_set_height (cnt_editor, height);
}
static void
html_editor_image_dialog_set_height_units (EHTMLEditorImageDialog *dialog)
{
+ EHTMLEditor *editor;
+ EContentEditor *cnt_editor;
gint requested;
- gulong natural;
+ gulong natural = 0;
gint height = -1;
- natural = webkit_dom_html_image_element_get_natural_height (
- dialog->priv->image);
+ editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
+ cnt_editor = e_html_editor_get_content_editor (editor);
+
+ natural = e_content_editor_image_get_natural_height (cnt_editor);
+
requested = gtk_spin_button_get_value_as_int (
- GTK_SPIN_BUTTON (dialog->priv->height_edit));
+ GTK_SPIN_BUTTON (dialog->priv->height_edit));
switch (gtk_combo_box_get_active (
GTK_COMBO_BOX (dialog->priv->height_units))) {
@@ -228,8 +240,6 @@ html_editor_image_dialog_set_height_units (EHTMLEditorImageDialog *dialog)
} else {
height = natural;
}
- webkit_dom_element_remove_attribute (
- WEBKIT_DOM_ELEMENT (dialog->priv->image), "style");
gtk_widget_set_sensitive (dialog->priv->height_edit, TRUE);
break;
@@ -239,116 +249,95 @@ html_editor_image_dialog_set_height_units (EHTMLEditorImageDialog *dialog)
} else {
height = 100;
}
- webkit_dom_element_remove_attribute (
- WEBKIT_DOM_ELEMENT (dialog->priv->image), "style");
gtk_widget_set_sensitive (dialog->priv->height_edit, TRUE);
break;
case 2: /* follow */
- webkit_dom_element_set_attribute (
- WEBKIT_DOM_ELEMENT (dialog->priv->image),
- "style",
- "height: auto;",
- NULL);
gtk_widget_set_sensitive (dialog->priv->height_edit, FALSE);
break;
}
- if (height != -1) {
+ e_content_editor_image_set_height_follow (
+ cnt_editor, !gtk_widget_get_sensitive (dialog->priv->height_edit));
+
+ if (height != -1)
gtk_spin_button_set_value (
GTK_SPIN_BUTTON (dialog->priv->height_edit), height);
- }
}
static void
html_editor_image_dialog_set_alignment (EHTMLEditorImageDialog *dialog)
{
- webkit_dom_html_image_element_set_align (
- dialog->priv->image,
- gtk_combo_box_get_active_id (
- GTK_COMBO_BOX (dialog->priv->alignment)));
+ EHTMLEditor *editor;
+ EContentEditor *cnt_editor;
+ const gchar *value;
+
+ editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
+ cnt_editor = e_html_editor_get_content_editor (editor);
+
+ value = gtk_combo_box_get_active_id (GTK_COMBO_BOX (dialog->priv->alignment));
+ e_content_editor_image_set_align (cnt_editor, value);
}
static void
html_editor_image_dialog_set_x_padding (EHTMLEditorImageDialog *dialog)
{
- webkit_dom_html_image_element_set_hspace (
- dialog->priv->image,
- gtk_spin_button_get_value_as_int (
- GTK_SPIN_BUTTON (dialog->priv->x_padding_edit)));
+ EHTMLEditor *editor;
+ EContentEditor *cnt_editor;
+ gint value;
+
+ editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
+ cnt_editor = e_html_editor_get_content_editor (editor);
+
+ value = gtk_spin_button_get_value_as_int (
+ GTK_SPIN_BUTTON (dialog->priv->x_padding_edit));
+ e_content_editor_image_set_hspace (cnt_editor, value);
}
static void
html_editor_image_dialog_set_y_padding (EHTMLEditorImageDialog *dialog)
{
- webkit_dom_html_image_element_set_vspace (
- dialog->priv->image,
- gtk_spin_button_get_value_as_int (
- GTK_SPIN_BUTTON (dialog->priv->y_padding_edit)));
+ EHTMLEditor *editor;
+ EContentEditor *cnt_editor;
+ gint value;
+
+ editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
+ cnt_editor = e_html_editor_get_content_editor (editor);
+
+ value = gtk_spin_button_get_value_as_int (
+ GTK_SPIN_BUTTON (dialog->priv->y_padding_edit));
+ e_content_editor_image_set_vspace (cnt_editor, value);
}
static void
html_editor_image_dialog_set_border (EHTMLEditorImageDialog *dialog)
{
- gchar *val;
+ EHTMLEditor *editor;
+ EContentEditor *cnt_editor;
+ gint value;
- val = g_strdup_printf (
- "%d", gtk_spin_button_get_value_as_int (
- GTK_SPIN_BUTTON (dialog->priv->border_edit)));
+ editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
+ cnt_editor = e_html_editor_get_content_editor (editor);
- webkit_dom_html_image_element_set_border (dialog->priv->image, val);
+ value = gtk_spin_button_get_value_as_int (
+ GTK_SPIN_BUTTON (dialog->priv->border_edit));
- g_free (val);
+ e_content_editor_image_set_border (cnt_editor, value);
}
static void
html_editor_image_dialog_set_url (EHTMLEditorImageDialog *dialog)
{
- WebKitDOMElement *link;
- const gchar *url;
-
- url = gtk_entry_get_text (GTK_ENTRY (dialog->priv->url_edit));
- link = e_html_editor_dom_node_find_parent_element (
- WEBKIT_DOM_NODE (dialog->priv->image), "A");
-
- if (link) {
- if (!url || !*url) {
- webkit_dom_node_insert_before (
- webkit_dom_node_get_parent_node (
- WEBKIT_DOM_NODE (link)),
- WEBKIT_DOM_NODE (dialog->priv->image),
- WEBKIT_DOM_NODE (link), NULL);
- webkit_dom_node_remove_child (
- webkit_dom_node_get_parent_node (
- WEBKIT_DOM_NODE (link)),
- WEBKIT_DOM_NODE (link), NULL);
- } else {
- webkit_dom_html_anchor_element_set_href (
- WEBKIT_DOM_HTML_ANCHOR_ELEMENT (link), url);
- }
- } else {
- if (url && *url) {
- WebKitDOMDocument *document;
-
- document = webkit_dom_node_get_owner_document (
- WEBKIT_DOM_NODE (dialog->priv->image));
- link = webkit_dom_document_create_element (
- document, "A", NULL);
-
- webkit_dom_html_anchor_element_set_href (
- WEBKIT_DOM_HTML_ANCHOR_ELEMENT (link), url);
-
- webkit_dom_node_insert_before (
- webkit_dom_node_get_parent_node (
- WEBKIT_DOM_NODE (dialog->priv->image)),
- WEBKIT_DOM_NODE (link),
- WEBKIT_DOM_NODE (dialog->priv->image), NULL);
-
- webkit_dom_node_append_child (
- WEBKIT_DOM_NODE (link),
- WEBKIT_DOM_NODE (dialog->priv->image), NULL);
- }
- }
+ EHTMLEditor *editor;
+ EContentEditor *cnt_editor;
+ const gchar *value;
+
+ editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
+ cnt_editor = e_html_editor_get_content_editor (editor);
+
+ value = gtk_entry_get_text (GTK_ENTRY (dialog->priv->url_edit));
+
+ e_content_editor_image_set_url (cnt_editor, value);
}
static void
@@ -364,42 +353,21 @@ html_editor_image_dialog_test_url (EHTMLEditorImageDialog *dialog)
static void
html_editor_image_dialog_show (GtkWidget *widget)
{
- EHTMLEditorImageDialog *dialog;
EHTMLEditor *editor;
- EHTMLEditorSelection *selection;
- EHTMLEditorView *view;
- WebKitDOMElement *link;
- gchar *tmp;
- glong val;
+ EHTMLEditorImageDialog *dialog;
+ EContentEditor *cnt_editor;
+ gchar *value;
dialog = E_HTML_EDITOR_IMAGE_DIALOG (widget);
-
- if (!dialog->priv->image) {
- return;
- }
-
editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
- view = e_html_editor_get_view (editor);
- selection = e_html_editor_view_get_selection (view);
+ cnt_editor = e_html_editor_get_content_editor (editor);
- if (!e_html_editor_view_is_undo_redo_in_progress (view)) {
- EHTMLEditorViewHistoryEvent *ev;
+ e_content_editor_on_image_dialog_open (cnt_editor);
- ev = g_new0 (EHTMLEditorViewHistoryEvent, 1);
- ev->type = HISTORY_IMAGE_DIALOG;
-
- e_html_editor_selection_get_selection_coordinates (
- selection, &ev->before.start.x, &ev->before.start.y, &ev->before.end.x,
&ev->before.end.y);
- ev->data.dom.from = webkit_dom_node_clone_node (
- WEBKIT_DOM_NODE (dialog->priv->image), FALSE);
- dialog->priv->history_event = ev;
- }
-
- tmp = webkit_dom_element_get_attribute (
- WEBKIT_DOM_ELEMENT (dialog->priv->image), "data-uri");
- if (tmp && *tmp) {
+ value = e_content_editor_image_get_src (cnt_editor);
+ if (value && *value) {
gtk_file_chooser_set_uri (
- GTK_FILE_CHOOSER (dialog->priv->file_chooser), tmp);
+ GTK_FILE_CHOOSER (dialog->priv->file_chooser), value);
gtk_widget_set_sensitive (
GTK_WIDGET (dialog->priv->file_chooser), TRUE);
} else {
@@ -408,56 +376,49 @@ html_editor_image_dialog_show (GtkWidget *widget)
gtk_widget_set_sensitive (
GTK_WIDGET (dialog->priv->file_chooser), FALSE);
}
- g_free (tmp);
+ g_free (value);
- tmp = webkit_dom_html_image_element_get_alt (dialog->priv->image);
- gtk_entry_set_text (GTK_ENTRY (dialog->priv->description_edit), tmp ? tmp : "");
- g_free (tmp);
+ value = e_content_editor_image_get_alt (cnt_editor);
+ gtk_entry_set_text (
+ GTK_ENTRY (dialog->priv->description_edit), value ? value : "");
+ g_free (value);
- val = webkit_dom_html_image_element_get_width (dialog->priv->image);
gtk_spin_button_set_value (
- GTK_SPIN_BUTTON (dialog->priv->width_edit), val);
+ GTK_SPIN_BUTTON (dialog->priv->width_edit),
+ e_content_editor_image_get_width (cnt_editor));
+
gtk_combo_box_set_active_id (
GTK_COMBO_BOX (dialog->priv->width_units), "units-px");
- val = webkit_dom_html_image_element_get_height (dialog->priv->image);
gtk_spin_button_set_value (
- GTK_SPIN_BUTTON (dialog->priv->height_edit), val);
+ GTK_SPIN_BUTTON (dialog->priv->height_edit),
+ e_content_editor_image_get_height (cnt_editor));
+
gtk_combo_box_set_active_id (
GTK_COMBO_BOX (dialog->priv->height_units), "units-px");
- tmp = webkit_dom_html_image_element_get_border (dialog->priv->image);
- if (tmp && *tmp) {
- gint border;
-
- border = atoi (tmp);
- gtk_spin_button_set_value (
- GTK_SPIN_BUTTON (dialog->priv->border_edit), border);
- }
- g_free (tmp);
+ gtk_spin_button_set_value (
+ GTK_SPIN_BUTTON (dialog->priv->border_edit),
+ e_content_editor_image_get_border (cnt_editor));
- tmp = webkit_dom_html_image_element_get_align (dialog->priv->image);
+ value = e_content_editor_image_get_align (cnt_editor);
gtk_combo_box_set_active_id (
GTK_COMBO_BOX (dialog->priv->alignment),
- (tmp && *tmp) ? tmp : "bottom");
- g_free (tmp);
+ (value && *value) ? value : "bottom");
+ g_free (value);
- val = webkit_dom_html_image_element_get_hspace (dialog->priv->image);
gtk_spin_button_set_value (
- GTK_SPIN_BUTTON (dialog->priv->x_padding_edit), val);
+ GTK_SPIN_BUTTON (dialog->priv->y_padding_edit),
+ e_content_editor_image_get_hspace (cnt_editor));
- val = webkit_dom_html_image_element_get_vspace (dialog->priv->image);
gtk_spin_button_set_value (
- GTK_SPIN_BUTTON (dialog->priv->y_padding_edit), val);
-
- link = e_html_editor_dom_node_find_parent_element (
- WEBKIT_DOM_NODE (dialog->priv->image), "A");
- if (link) {
- tmp = webkit_dom_html_anchor_element_get_href (
- WEBKIT_DOM_HTML_ANCHOR_ELEMENT (link));
- gtk_entry_set_text (GTK_ENTRY (dialog->priv->url_edit), tmp);
- g_free (tmp);
- }
+ GTK_SPIN_BUTTON (dialog->priv->y_padding_edit),
+ e_content_editor_image_get_vspace (cnt_editor));
+
+ value = e_content_editor_image_get_url (cnt_editor);
+ if (value && *value)
+ gtk_entry_set_text (GTK_ENTRY (dialog->priv->url_edit), value);
+ g_free (value);
/* Chain up to parent implementation */
GTK_WIDGET_CLASS (e_html_editor_image_dialog_parent_class)->show (widget);
@@ -466,33 +427,15 @@ html_editor_image_dialog_show (GtkWidget *widget)
static void
html_editor_image_dialog_hide (GtkWidget *widget)
{
- EHTMLEditorImageDialogPrivate *priv;
- EHTMLEditorViewHistoryEvent *ev;
-
- priv = E_HTML_EDITOR_IMAGE_DIALOG_GET_PRIVATE (widget);
- ev = priv->history_event;
-
- if (ev) {
- EHTMLEditorImageDialog *dialog;
- EHTMLEditor *editor;
- EHTMLEditorSelection *selection;
- EHTMLEditorView *view;
-
- dialog = E_HTML_EDITOR_IMAGE_DIALOG (widget);
- editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
- view = e_html_editor_get_view (editor);
- selection = e_html_editor_view_get_selection (view);
-
- ev->data.dom.to = webkit_dom_node_clone_node (
- WEBKIT_DOM_NODE (priv->image), FALSE);
+ EHTMLEditor *editor;
+ EHTMLEditorImageDialog *dialog;
+ EContentEditor *cnt_editor;
- e_html_editor_selection_get_selection_coordinates (
- selection, &ev->after.start.x, &ev->after.start.y, &ev->after.end.x,
&ev->after.end.y);
- e_html_editor_view_insert_new_history_event (view, ev);
- }
+ dialog = E_HTML_EDITOR_IMAGE_DIALOG (widget);
+ editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
+ cnt_editor = e_html_editor_get_content_editor (editor);
- g_object_unref (priv->image);
- priv->image = NULL;
+ e_content_editor_on_image_dialog_close (cnt_editor);
GTK_WIDGET_CLASS (e_html_editor_image_dialog_parent_class)->hide (widget);
}
@@ -742,19 +685,12 @@ e_html_editor_image_dialog_new (EHTMLEditor *editor)
}
void
-e_html_editor_image_dialog_show (EHTMLEditorImageDialog *dialog,
- WebKitDOMNode *image)
+e_html_editor_image_dialog_show (EHTMLEditorImageDialog *dialog)
{
EHTMLEditorImageDialogClass *class;
g_return_if_fail (E_IS_HTML_EDITOR_IMAGE_DIALOG (dialog));
- if (image) {
- dialog->priv->image = WEBKIT_DOM_HTML_IMAGE_ELEMENT (image);
- } else {
- dialog->priv->image = NULL;
- }
-
class = E_HTML_EDITOR_IMAGE_DIALOG_GET_CLASS (dialog);
GTK_WIDGET_CLASS (class)->show (GTK_WIDGET (dialog));
}
diff --git a/e-util/e-html-editor-image-dialog.h b/e-util/e-html-editor-image-dialog.h
index efdbaf9..a4d0304 100644
--- a/e-util/e-html-editor-image-dialog.h
+++ b/e-util/e-html-editor-image-dialog.h
@@ -64,8 +64,7 @@ struct _EHTMLEditorImageDialogClass {
GType e_html_editor_image_dialog_get_type
(void) G_GNUC_CONST;
GtkWidget * e_html_editor_image_dialog_new (EHTMLEditor *editor);
-void e_html_editor_image_dialog_show (EHTMLEditorImageDialog *dialog,
- WebKitDOMNode *image);
+void e_html_editor_image_dialog_show (EHTMLEditorImageDialog *dialog);
G_END_DECLS
diff --git a/e-util/e-html-editor-link-dialog.c b/e-util/e-html-editor-link-dialog.c
index 78bc97d..5db93ed 100644
--- a/e-util/e-html-editor-link-dialog.c
+++ b/e-util/e-html-editor-link-dialog.c
@@ -23,10 +23,6 @@
#endif
#include "e-html-editor-link-dialog.h"
-#include "e-html-editor-selection.h"
-#include "e-html-editor-utils.h"
-#include "e-html-editor-view.h"
-#include "e-web-view.h"
#include <glib/gi18n-lib.h>
@@ -48,11 +44,6 @@ struct _EHTMLEditorLinkDialogPrivate {
GtkWidget *ok_button;
gboolean label_autofill;
- gboolean unlinking;
-
- WebKitDOMElement *link_element;
-
- EHTMLEditorViewHistoryEvent *history_event;
};
static void
@@ -94,14 +85,12 @@ static void
html_editor_link_dialog_remove_link (EHTMLEditorLinkDialog *dialog)
{
EHTMLEditor *editor;
- EHTMLEditorView *view;
- EHTMLEditorSelection *selection;
+ EContentEditor *cnt_editor;
editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
- view = e_html_editor_get_view (editor);
- selection = e_html_editor_view_get_selection (view);
- e_html_editor_selection_unlink (selection);
- dialog->priv->unlinking = TRUE;
+ cnt_editor = e_html_editor_get_content_editor (editor);
+
+ e_content_editor_selection_unlink (cnt_editor);
gtk_widget_hide (GTK_WIDGET (dialog));
}
@@ -110,108 +99,15 @@ static void
html_editor_link_dialog_ok (EHTMLEditorLinkDialog *dialog)
{
EHTMLEditor *editor;
- EHTMLEditorSelection *selection;
- EHTMLEditorView *view;
- WebKitDOMDocument *document;
+ EContentEditor *cnt_editor;
editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
- view = e_html_editor_get_view (editor);
- selection = e_html_editor_view_get_selection (view);
- document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (view));
-
- if (dialog->priv->link_element) {
- WebKitDOMElement *element;
-
- webkit_dom_html_anchor_element_set_href (
- WEBKIT_DOM_HTML_ANCHOR_ELEMENT (dialog->priv->link_element),
- gtk_entry_get_text (GTK_ENTRY (dialog->priv->url_edit)));
- webkit_dom_html_element_set_inner_html (
- WEBKIT_DOM_HTML_ELEMENT (dialog->priv->link_element),
- gtk_entry_get_text (GTK_ENTRY (dialog->priv->label_edit)),
- NULL);
-
- element = webkit_dom_document_create_element (document, "SPAN", NULL);
- webkit_dom_element_set_id (element, "-x-evo-selection-end-marker");
- webkit_dom_node_insert_before (
- webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (dialog->priv->link_element)),
- WEBKIT_DOM_NODE (element),
- webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (dialog->priv->link_element)),
- NULL);
-
- element = webkit_dom_document_create_element (document, "SPAN", NULL);
- webkit_dom_element_set_id (element, "-x-evo-selection-start-marker");
- webkit_dom_node_insert_before (
- webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (dialog->priv->link_element)),
- WEBKIT_DOM_NODE (element),
- webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (dialog->priv->link_element)),
- NULL);
-
- e_html_editor_selection_restore (selection);
- } else {
- WebKitDOMDOMWindow *dom_window;
- WebKitDOMDOMSelection *dom_selection;
- WebKitDOMRange *range;
-
- dom_window = webkit_dom_document_get_default_view (document);
- dom_selection = webkit_dom_dom_window_get_selection (dom_window);
- g_object_unref (dom_window);
-
- e_html_editor_selection_restore (selection);
- range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
- if (webkit_dom_range_get_collapsed (range, NULL)) {
- WebKitDOMElement *selection_marker;
- WebKitDOMElement *anchor;
-
- e_html_editor_selection_save (selection);
- selection_marker = webkit_dom_document_get_element_by_id (
- document, "-x-evo-selection-start-marker");
- anchor = webkit_dom_document_create_element (document, "A", NULL);
- webkit_dom_element_set_attribute (
- anchor, "href", gtk_entry_get_text (GTK_ENTRY (dialog->priv->url_edit)),
NULL);
- webkit_dom_html_element_set_inner_text (
- WEBKIT_DOM_HTML_ELEMENT (anchor),
- gtk_entry_get_text (
- GTK_ENTRY (dialog->priv->label_edit)),
- NULL);
- dialog->priv->link_element = anchor;
-
- webkit_dom_node_insert_before (
- webkit_dom_node_get_parent_node (
- WEBKIT_DOM_NODE (selection_marker)),
- WEBKIT_DOM_NODE (anchor),
- WEBKIT_DOM_NODE (selection_marker),
- NULL);
- e_html_editor_selection_restore (selection);
- } else {
- gchar *text;
-
- text = webkit_dom_range_get_text (range);
- if (text && *text) {
- WebKitDOMElement *selection_marker;
- WebKitDOMNode *parent;
-
- e_html_editor_selection_create_link (
- selection, gtk_entry_get_text (GTK_ENTRY (dialog->priv->url_edit)));
-
- dialog->priv->history_event->data.dom.from =
- WEBKIT_DOM_NODE (webkit_dom_document_create_text_node (document,
text));
-
- e_html_editor_selection_save (selection);
- selection_marker = webkit_dom_document_get_element_by_id (
- document, "-x-evo-selection-start-marker");
- parent = webkit_dom_node_get_parent_node (
- WEBKIT_DOM_NODE (selection_marker));
- if (WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (parent))
- dialog->priv->link_element = WEBKIT_DOM_ELEMENT (parent);
- e_html_editor_selection_restore (selection);
- webkit_dom_dom_selection_collapse_to_end (dom_selection, NULL);
- }
- g_free (text);
- }
-
- g_object_unref (range);
- g_object_unref (dom_selection);
- }
+ cnt_editor = e_html_editor_get_content_editor (editor);
+
+ e_content_editor_link_set_values (
+ cnt_editor,
+ gtk_entry_get_text (GTK_ENTRY (dialog->priv->url_edit)),
+ gtk_entry_get_text (GTK_ENTRY (dialog->priv->label_edit)));
gtk_widget_hide (GTK_WIDGET (dialog));
}
@@ -220,7 +116,7 @@ static gboolean
html_editor_link_dialog_entry_key_pressed (EHTMLEditorLinkDialog *dialog,
GdkEventKey *event)
{
- /* We can't do thins in key_released, because then you could not open
+ /* We can't do things in key_released, because then you could not open
* this dialog from main menu by pressing enter on Insert->Link action */
if (event->keyval == GDK_KEY_Return) {
html_editor_link_dialog_ok (dialog);
@@ -231,139 +127,66 @@ html_editor_link_dialog_entry_key_pressed (EHTMLEditorLinkDialog *dialog,
}
static void
+html_editor_link_dialog_hide (GtkWidget *widget)
+{
+ EHTMLEditor *editor;
+ EHTMLEditorLinkDialog *dialog;
+ EContentEditor *cnt_editor;
+
+ dialog = E_HTML_EDITOR_LINK_DIALOG (widget);
+ editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
+ cnt_editor = e_html_editor_get_content_editor (editor);
+
+ e_content_editor_on_link_dialog_close (cnt_editor);
+
+ /* Chain up to parent implementation */
+ GTK_WIDGET_CLASS (e_html_editor_link_dialog_parent_class)->hide (widget);
+}
+
+static void
html_editor_link_dialog_show (GtkWidget *widget)
{
EHTMLEditor *editor;
EHTMLEditorLinkDialog *dialog;
- EHTMLEditorSelection *selection;
- EHTMLEditorView *view;
+ EContentEditor *cnt_editor;
+ gchar *href = NULL, *text = NULL;
dialog = E_HTML_EDITOR_LINK_DIALOG (widget);
editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
- view = e_html_editor_get_view (editor);
- selection = e_html_editor_view_get_selection (view);
+ cnt_editor = e_html_editor_get_content_editor (editor);
/* Reset to default values */
gtk_entry_set_text (GTK_ENTRY (dialog->priv->url_edit), "http://");
gtk_entry_set_text (GTK_ENTRY (dialog->priv->label_edit), "");
gtk_widget_set_sensitive (dialog->priv->label_edit, TRUE);
gtk_widget_set_sensitive (dialog->priv->remove_link_button, TRUE);
- dialog->priv->label_autofill = TRUE;
- dialog->priv->unlinking = FALSE;
-
- if (!e_html_editor_view_is_undo_redo_in_progress (view)) {
- EHTMLEditorViewHistoryEvent *ev;
-
- ev = g_new0 (EHTMLEditorViewHistoryEvent, 1);
- ev->type = HISTORY_LINK_DIALOG;
-
- e_html_editor_selection_get_selection_coordinates (
- selection, &ev->before.start.x, &ev->before.start.y, &ev->before.end.x,
&ev->before.end.y);
- if (dialog->priv->link_element)
- ev->data.dom.from = webkit_dom_node_clone_node (
- WEBKIT_DOM_NODE (dialog->priv->link_element), TRUE);
- else
- ev->data.dom.from = NULL;
- dialog->priv->history_event = ev;
- }
- if (dialog->priv->link_element) {
- gchar *href, *text;
+ dialog->priv->label_autofill = TRUE;
- href = webkit_dom_element_get_attribute (dialog->priv->link_element, "href");
- text = webkit_dom_html_element_get_inner_text (
- WEBKIT_DOM_HTML_ELEMENT (dialog->priv->link_element));
+ e_content_editor_on_link_dialog_open (cnt_editor);
+ e_content_editor_link_get_values (cnt_editor, &href, &text);
+ if (href && *href)
gtk_entry_set_text (
GTK_ENTRY (dialog->priv->url_edit), href);
+ else
+ gtk_widget_set_sensitive (
+ dialog->priv->remove_link_button, FALSE);
+
+ g_free (href);
+
+ if (text && *text) {
gtk_entry_set_text (
GTK_ENTRY (dialog->priv->label_edit), text);
-
- g_free (text);
- g_free (href);
- } else {
- gchar *text;
- WebKitDOMDocument *document;
- WebKitDOMDOMWindow *dom_window;
- WebKitDOMDOMSelection *dom_selection;
- WebKitDOMRange *range;
-
- document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (view));
- dom_window = webkit_dom_document_get_default_view (document);
- dom_selection = webkit_dom_dom_window_get_selection (dom_window);
- g_object_unref (dom_window);
-
- /* No selection at all */
- if (!dom_selection || webkit_dom_dom_selection_get_range_count (dom_selection) < 1)
- gtk_widget_set_sensitive (dialog->priv->remove_link_button, FALSE);
-
- range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
- text = webkit_dom_range_get_text (range);
- if (text && *text) {
- gtk_entry_set_text (
- GTK_ENTRY (dialog->priv->label_edit), text);
- gtk_widget_set_sensitive (
- dialog->priv->label_edit, FALSE);
- gtk_widget_set_sensitive (
- dialog->priv->remove_link_button, FALSE);
- }
- g_free (text);
-
- g_object_unref (range);
- g_object_unref (dom_selection);
-
- e_html_editor_selection_save (selection);
+ dialog->priv->label_autofill = FALSE;
}
+ g_free (text);
/* Chain up to parent implementation */
GTK_WIDGET_CLASS (e_html_editor_link_dialog_parent_class)->show (widget);
}
static void
-html_editor_link_dialog_hide (GtkWidget *widget)
-{
- EHTMLEditorLinkDialogPrivate *priv;
- EHTMLEditorViewHistoryEvent *ev;
-
- priv = E_HTML_EDITOR_LINK_DIALOG_GET_PRIVATE (widget);
- ev = priv->history_event;
-
- if (priv->unlinking || !priv->link_element) {
- g_clear_object (&ev->data.dom.from);
- g_free (ev);
- } else if (ev) {
- EHTMLEditorLinkDialog *dialog;
- EHTMLEditor *editor;
- EHTMLEditorSelection *selection;
- EHTMLEditorView *view;
-
- dialog = E_HTML_EDITOR_LINK_DIALOG (widget);
- editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
- view = e_html_editor_get_view (editor);
- selection = e_html_editor_view_get_selection (view);
-
- ev->data.dom.to = webkit_dom_node_clone_node (
- WEBKIT_DOM_NODE (priv->link_element), TRUE);
-
- if (!webkit_dom_node_is_equal_node (ev->data.dom.from, ev->data.dom.to)) {
- e_html_editor_selection_get_selection_coordinates (
- selection, &ev->after.start.x, &ev->after.start.y, &ev->after.end.x,
&ev->after.end.y);
- e_html_editor_view_insert_new_history_event (view, ev);
- if (!ev->data.dom.from)
- g_object_unref (priv->link_element);
- } else {
- g_object_unref (ev->data.dom.from);
- g_object_unref (ev->data.dom.to);
- g_free (ev);
- }
- }
-
- priv->link_element = NULL;
-
- GTK_WIDGET_CLASS (e_html_editor_link_dialog_parent_class)->hide (widget);
-}
-
-static void
e_html_editor_link_dialog_class_init (EHTMLEditorLinkDialogClass *class)
{
GtkWidgetClass *widget_class;
@@ -383,7 +206,6 @@ e_html_editor_link_dialog_init (EHTMLEditorLinkDialog *dialog)
GtkWidget *widget;
dialog->priv = E_HTML_EDITOR_LINK_DIALOG_GET_PRIVATE (dialog);
- dialog->priv->link_element = NULL;
main_layout = e_html_editor_dialog_get_container (E_HTML_EDITOR_DIALOG (dialog));
@@ -454,17 +276,3 @@ e_html_editor_link_dialog_new (EHTMLEditor *editor)
"title", _("Link Properties"),
NULL));
}
-
-void
-e_html_editor_link_dialog_show (EHTMLEditorLinkDialog *dialog,
- WebKitDOMNode *link)
-{
- EHTMLEditorLinkDialogClass *class;
-
- g_return_if_fail (E_IS_HTML_EDITOR_LINK_DIALOG (dialog));
-
- dialog->priv->link_element = link ? WEBKIT_DOM_ELEMENT (link) : NULL;
-
- class = E_HTML_EDITOR_LINK_DIALOG_GET_CLASS (dialog);
- GTK_WIDGET_CLASS (class)->show (GTK_WIDGET (dialog));
-}
diff --git a/e-util/e-html-editor-link-dialog.h b/e-util/e-html-editor-link-dialog.h
index c3a9709..a1e426f 100644
--- a/e-util/e-html-editor-link-dialog.h
+++ b/e-util/e-html-editor-link-dialog.h
@@ -65,8 +65,6 @@ GType e_html_editor_link_dialog_get_type
(void) G_GNUC_CONST;
GtkWidget * e_html_editor_link_dialog_new (EHTMLEditor *editor);
-void e_html_editor_link_dialog_show (EHTMLEditorLinkDialog *dialog,
- WebKitDOMNode *link);
G_END_DECLS
#endif /* E_HTML_EDITOR_LINK_DIALOG_H */
diff --git a/e-util/e-html-editor-manager.ui b/e-util/e-html-editor-manager.ui
index 97a4861..fa7bc0b 100644
--- a/e-util/e-html-editor-manager.ui
+++ b/e-util/e-html-editor-manager.ui
@@ -27,7 +27,7 @@
<placeholder name='pre-insert-menu'>
<menu action='view-menu'>
<placeholder name='view-menu-top'/>
- <menuitem action='webkit-inspector'/>
+ <placeholder name='view-menu-custom'/>
<separator/>
</menu>
</placeholder>
@@ -69,7 +69,6 @@
<menuitem action='style-normal'/>
<menuitem action='style-preformat'/>
<menuitem action='style-address'/>
- <menuitem action='style-blockquote'/>
<separator/>
<menuitem action='style-h1'/>
<menuitem action='style-h2'/>
@@ -164,8 +163,6 @@
</menu>
<separator/>
<menu action='context-insert-table-menu'>
- <menuitem action='context-insert-table'/>
- <separator/>
<menuitem action='context-insert-row-above'/>
<menuitem action='context-insert-row-below'/>
<separator/>
@@ -178,7 +175,5 @@
<menuitem action='context-delete-column'/>
<menuitem action='context-delete-cell'/>
</menu>
- <separator/>
- <menu action='context-input-methods-menu'/>
</popup>
</ui>
diff --git a/e-util/e-html-editor-page-dialog.c b/e-util/e-html-editor-page-dialog.c
index 9033ff3..2399566 100644
--- a/e-util/e-html-editor-page-dialog.c
+++ b/e-util/e-html-editor-page-dialog.c
@@ -44,8 +44,6 @@ struct _EHTMLEditorPageDialogPrivate {
GtkWidget *background_image_filechooser;
GtkWidget *remove_image_button;
-
- EHTMLEditorViewHistoryEvent *history_event;
};
typedef struct _Template {
@@ -150,85 +148,64 @@ static void
html_editor_page_dialog_set_text_color (EHTMLEditorPageDialog *dialog)
{
EHTMLEditor *editor;
- EHTMLEditorView *view;
- WebKitDOMDocument *document;
- WebKitDOMHTMLElement *body;
+ EContentEditor *cnt_editor;
GdkRGBA rgba;
- gchar *color;
editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
- view = e_html_editor_get_view (editor);
- document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (view));
- body = webkit_dom_document_get_body (document);
+ cnt_editor = e_html_editor_get_content_editor (editor);
e_color_combo_get_current_color (
E_COLOR_COMBO (dialog->priv->text_color_picker), &rgba);
- color = g_strdup_printf ("#%06x", e_rgba_to_value (&rgba));
- webkit_dom_html_body_element_set_text (
- WEBKIT_DOM_HTML_BODY_ELEMENT (body), color);
-
- g_free (color);
+ e_content_editor_page_set_text_color (cnt_editor, &rgba);
}
static void
html_editor_page_dialog_set_link_color (EHTMLEditorPageDialog *dialog)
{
EHTMLEditor *editor;
- EHTMLEditorView *view;
+ EContentEditor *cnt_editor;
GdkRGBA rgba;
editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
- view = e_html_editor_get_view (editor);
+ cnt_editor = e_html_editor_get_content_editor (editor);
e_color_combo_get_current_color (
E_COLOR_COMBO (dialog->priv->link_color_picker), &rgba);
- e_html_editor_view_set_link_color (view, &rgba);
+ e_content_editor_page_set_link_color (cnt_editor, &rgba);
}
static void
html_editor_page_dialog_set_visited_link_color (EHTMLEditorPageDialog *dialog)
{
EHTMLEditor *editor;
- EHTMLEditorView *view;
+ EContentEditor *cnt_editor;
GdkRGBA rgba;
editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
- view = e_html_editor_get_view (editor);
+ cnt_editor = e_html_editor_get_content_editor (editor);
e_color_combo_get_current_color (
E_COLOR_COMBO (dialog->priv->visited_link_color_picker), &rgba);
- e_html_editor_view_set_visited_link_color (view, &rgba);
+ e_content_editor_page_set_visited_link_color (cnt_editor, &rgba);
}
static void
html_editor_page_dialog_set_background_color (EHTMLEditorPageDialog *dialog)
{
EHTMLEditor *editor;
- EHTMLEditorView *view;
- WebKitDOMDocument *document;
- WebKitDOMHTMLElement *body;
+ EContentEditor *cnt_editor;
GdkRGBA rgba;
- gchar *color;
editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
- view = e_html_editor_get_view (editor);
- document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (view));
- body = webkit_dom_document_get_body (document);
+ cnt_editor = e_html_editor_get_content_editor (editor);
e_color_combo_get_current_color (
E_COLOR_COMBO (dialog->priv->background_color_picker), &rgba);
- if (rgba.alpha != 0.0)
- color = g_strdup_printf ("#%06x", e_rgba_to_value (&rgba));
- else
- color = g_strdup ("");
-
- webkit_dom_html_body_element_set_bg_color (
- WEBKIT_DOM_HTML_BODY_ELEMENT (body), color);
- g_free (color);
+ e_content_editor_page_set_background_color (cnt_editor, &rgba);
}
static void
@@ -271,28 +248,16 @@ static void
html_editor_page_dialog_set_background_image (EHTMLEditorPageDialog *dialog)
{
EHTMLEditor *editor;
- EHTMLEditorView *view;
- WebKitDOMDocument *document;
- WebKitDOMHTMLElement *body;
+ EContentEditor *cnt_editor;
gchar *uri;
editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
- view = e_html_editor_get_view (editor);
- document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (view));
- body = webkit_dom_document_get_body (document);
+ cnt_editor = e_html_editor_get_content_editor (editor);
uri = gtk_file_chooser_get_uri (
- GTK_FILE_CHOOSER (
- dialog->priv->background_image_filechooser));
-
- if (uri && *uri)
- e_html_editor_selection_replace_image_src (
- e_html_editor_view_get_selection (view),
- WEBKIT_DOM_ELEMENT (body),
- uri);
- else
- remove_image_attributes_from_element (
- WEBKIT_DOM_ELEMENT (body));
+ GTK_FILE_CHOOSER (dialog->priv->background_image_filechooser));
+
+ e_content_editor_page_set_background_image_uri (cnt_editor, uri);
gtk_widget_set_sensitive (dialog->priv->remove_image_button, uri && *uri);
@@ -303,16 +268,12 @@ static void
html_editor_page_dialog_remove_image (EHTMLEditorPageDialog *dialog)
{
EHTMLEditor *editor;
- EHTMLEditorView *view;
- WebKitDOMDocument *document;
- WebKitDOMHTMLElement *body;
+ EContentEditor *cnt_editor;
editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
- view = e_html_editor_get_view (editor);
- document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (view));
- body = webkit_dom_document_get_body (document);
+ cnt_editor = e_html_editor_get_content_editor (editor);
- remove_image_attributes_from_element (WEBKIT_DOM_ELEMENT (body));
+ e_content_editor_page_set_background_image_uri (cnt_editor, NULL);
gtk_file_chooser_unselect_all (
GTK_FILE_CHOOSER (dialog->priv->background_image_filechooser));
@@ -324,44 +285,21 @@ static void
html_editor_page_dialog_show (GtkWidget *widget)
{
EHTMLEditor *editor;
- EHTMLEditorView *view;
+ EContentEditor *cnt_editor;
EHTMLEditorPageDialog *dialog;
- WebKitDOMDocument *document;
- WebKitDOMHTMLElement *body;
- gchar *tmp;
GdkRGBA rgba;
+ gchar *uri;
dialog = E_HTML_EDITOR_PAGE_DIALOG (widget);
editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
- view = e_html_editor_get_view (editor);
+ cnt_editor = e_html_editor_get_content_editor (editor);
- /* We have to block the style changes of the view as otherwise the colors
- * will be changed when this dialog will be shown (as the view will be
- * unfocused). */
- e_html_editor_view_block_style_updated_callbacks (view);
-
- document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (view));
- body = webkit_dom_document_get_body (document);
-
- if (!e_html_editor_view_is_undo_redo_in_progress (view)) {
- EHTMLEditorSelection *selection;
- EHTMLEditorViewHistoryEvent *ev;
-
- ev = g_new0 (EHTMLEditorViewHistoryEvent, 1);
- ev->type = HISTORY_PAGE_DIALOG;
-
- selection = e_html_editor_view_get_selection (view);
- e_html_editor_selection_get_selection_coordinates (
- selection, &ev->before.start.x, &ev->before.start.y, &ev->before.end.x,
&ev->before.end.y);
- ev->data.dom.from = webkit_dom_node_clone_node (WEBKIT_DOM_NODE (body), FALSE);
- dialog->priv->history_event = ev;
- }
+ e_content_editor_on_page_dialog_open (cnt_editor);
- tmp = webkit_dom_element_get_attribute (
- WEBKIT_DOM_ELEMENT (body), "data-uri");
- if (tmp && *tmp) {
+ uri = e_content_editor_page_get_background_image_uri (cnt_editor);
+ if (uri && *uri) {
gint ii;
- gchar *fname = g_filename_from_uri (tmp, NULL, NULL);
+ gchar *fname = g_filename_from_uri (uri, NULL, NULL);
for (ii = 0; ii < G_N_ELEMENTS (templates); ii++) {
const Template *tmplt = &templates[ii];
@@ -377,140 +315,39 @@ html_editor_page_dialog_show (GtkWidget *widget)
gtk_combo_box_set_active (
GTK_COMBO_BOX (dialog->priv->background_template_combo), 0);
}
- g_free (tmp);
+ g_free (uri);
- tmp = webkit_dom_html_body_element_get_text (
- WEBKIT_DOM_HTML_BODY_ELEMENT (body));
- if (!tmp || !*tmp || !gdk_rgba_parse (&rgba, tmp))
- e_utils_get_theme_color (widget, "theme_text_color,theme_fg_color",
E_UTILS_DEFAULT_THEME_TEXT_COLOR, &rgba);
- g_free (tmp);
+ e_content_editor_page_get_text_color (cnt_editor, &rgba);
e_color_combo_set_current_color (
E_COLOR_COMBO (dialog->priv->text_color_picker), &rgba);
- tmp = webkit_dom_html_body_element_get_link (
- WEBKIT_DOM_HTML_BODY_ELEMENT (body));
- if (!gdk_rgba_parse (&rgba, tmp)) {
- rgba.alpha = 1;
- rgba.red = 0;
- rgba.green = 0;
- rgba.blue = 1;
- }
- g_free (tmp);
+ e_content_editor_page_get_link_color (cnt_editor, &rgba);
e_color_combo_set_current_color (
E_COLOR_COMBO (dialog->priv->link_color_picker), &rgba);
- tmp = webkit_dom_html_body_element_get_v_link (
- WEBKIT_DOM_HTML_BODY_ELEMENT (body));
- if (!gdk_rgba_parse (&rgba, tmp)) {
- rgba.alpha = 1;
- rgba.red = 1;
- rgba.green = 0;
- rgba.blue = 0;
- }
- g_free (tmp);
+ e_content_editor_page_get_visited_link_color (cnt_editor, &rgba);
e_color_combo_set_current_color (
E_COLOR_COMBO (dialog->priv->visited_link_color_picker), &rgba);
- tmp = webkit_dom_html_body_element_get_bg_color (
- WEBKIT_DOM_HTML_BODY_ELEMENT (body));
- if (!tmp || !*tmp || !gdk_rgba_parse (&rgba, tmp))
- e_utils_get_theme_color (widget, "theme_base_color", E_UTILS_DEFAULT_THEME_BASE_COLOR, &rgba);
- g_free (tmp);
+ e_content_editor_page_get_background_color (cnt_editor, &rgba);
e_color_combo_set_current_color (
E_COLOR_COMBO (dialog->priv->background_color_picker), &rgba);
GTK_WIDGET_CLASS (e_html_editor_page_dialog_parent_class)->show (widget);
}
-static gboolean
-user_changed_content (EHTMLEditorViewHistoryEvent *event)
-{
- WebKitDOMElement *original, *current;
- gchar *original_value, *current_value;
- gboolean changed = TRUE;
-
- original = WEBKIT_DOM_ELEMENT (event->data.dom.from);
- current = WEBKIT_DOM_ELEMENT (event->data.dom.to);
-
- original_value = webkit_dom_element_get_attribute (original, "bgcolor");
- current_value = webkit_dom_element_get_attribute (current, "bgcolor");
- changed = g_strcmp0 (original_value, current_value) != 0;
- g_free (original_value);
- g_free (current_value);
- if (changed)
- return TRUE;
-
- original_value = webkit_dom_element_get_attribute (original, "text");
- current_value = webkit_dom_element_get_attribute (current, "text");
- changed = g_strcmp0 (original_value, current_value) != 0;
- g_free (original_value);
- g_free (current_value);
- if (changed)
- return TRUE;
-
- original_value = webkit_dom_element_get_attribute (original, "link");
- current_value = webkit_dom_element_get_attribute (current, "link");
- changed = g_strcmp0 (original_value, current_value) != 0;
- g_free (original_value);
- g_free (current_value);
- if (changed)
- return TRUE;
-
- original_value = webkit_dom_element_get_attribute (original, "vlink");
- current_value = webkit_dom_element_get_attribute (current, "vlink");
- changed = g_strcmp0 (original_value, current_value) != 0;
- g_free (original_value);
- g_free (current_value);
-
- return changed;
-}
-
static void
html_editor_page_dialog_hide (GtkWidget *widget)
{
- EHTMLEditorPageDialogPrivate *priv;
- EHTMLEditorViewHistoryEvent *ev;
- EHTMLEditorPageDialog *dialog;
EHTMLEditor *editor;
- EHTMLEditorView *view;
+ EContentEditor *cnt_editor;
+ EHTMLEditorPageDialog *dialog;
dialog = E_HTML_EDITOR_PAGE_DIALOG (widget);
editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
- view = e_html_editor_get_view (editor);
- priv = E_HTML_EDITOR_PAGE_DIALOG_GET_PRIVATE (widget);
- ev = priv->history_event;
-
- if (ev) {
- EHTMLEditorSelection *selection;
- WebKitDOMDocument *document;
- WebKitDOMHTMLElement *body;
-
- selection = e_html_editor_view_get_selection (view);
-
- document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (view));
- body = webkit_dom_document_get_body (document);
-
- ev->data.dom.to = webkit_dom_node_clone_node (WEBKIT_DOM_NODE (body), FALSE);
-
- /* If user changed any of page colors we have to mark it to send
- * the correct colors and to disable the color changes when the
- * view i.e. not focused (at it would overwrite these user set colors. */
- if (user_changed_content (ev))
- webkit_dom_element_set_attribute (
- WEBKIT_DOM_ELEMENT (body), "data-user-colors", "", NULL);
-
- if (!webkit_dom_node_is_equal_node (ev->data.dom.from, ev->data.dom.to)) {
- e_html_editor_selection_get_selection_coordinates (
- selection, &ev->after.start.x, &ev->after.start.y, &ev->after.end.x,
&ev->after.end.y);
- e_html_editor_view_insert_new_history_event (view, ev);
- } else {
- g_object_unref (ev->data.dom.from);
- g_object_unref (ev->data.dom.to);
- g_free (ev);
- }
- }
+ cnt_editor = e_html_editor_get_content_editor (editor);
- e_html_editor_view_unblock_style_updated_callbacks (view);
+ e_content_editor_on_page_dialog_close (cnt_editor);
GTK_WIDGET_CLASS (e_html_editor_page_dialog_parent_class)->hide (widget);
}
diff --git a/e-util/e-html-editor-private.h b/e-util/e-html-editor-private.h
index 60f6706..37523a5 100644
--- a/e-util/e-html-editor-private.h
+++ b/e-util/e-html-editor-private.h
@@ -36,7 +36,6 @@
#include <e-html-editor-spell-check-dialog.h>
#include <e-html-editor-table-dialog.h>
#include <e-html-editor-text-dialog.h>
-#include <e-html-editor-view.h>
#ifdef HAVE_XFREE
#include <X11/XF86keysym.h>
@@ -84,21 +83,24 @@ struct _EHTMLEditorPrivate {
GtkWidget *style_combo_box;
GtkWidget *scrolled_window;
- EHTMLEditorView *html_editor_view;
- EHTMLEditorSelection *selection;
+ GHashTable *content_editors;
+ EContentEditor *use_content_editor;
+
+ EContentEditorNodeFlags node_flags;
gchar *filename;
guint spell_suggestions_merge_id;
- WebKitDOMNode *image;
- WebKitDOMNode *table_cell;
- WebKitDOMNode *current_node;
-
gint editor_layout_row;
+
+ gboolean is_testing;
};
void editor_actions_init (EHTMLEditor *editor);
+void editor_actions_bind (EHTMLEditor *editor);
+const gchar * e_html_editor_get_content_editor_name
+ (EHTMLEditor *editor);
G_END_DECLS
diff --git a/e-util/e-html-editor-replace-dialog.c b/e-util/e-html-editor-replace-dialog.c
index d21bef2..59b69a7 100644
--- a/e-util/e-html-editor-replace-dialog.c
+++ b/e-util/e-html-editor-replace-dialog.c
@@ -49,7 +49,9 @@ struct _EHTMLEditorReplaceDialogPrivate {
GtkWidget *replace_button;
GtkWidget *replace_all_button;
- EHTMLEditor *editor;
+ EContentEditor *cnt_editor;
+ gulong find_done_handler_id;
+ gulong replace_all_done_handler_id;
};
enum {
@@ -57,130 +59,111 @@ enum {
PROP_EDITOR
};
-static gboolean
-jump (EHTMLEditorReplaceDialog *dialog)
+static void
+content_editor_find_done_cb (EContentEditor *cnt_editor,
+ guint match_count,
+ EHTMLEditorReplaceDialog *dialog)
{
- EHTMLEditor *editor;
- WebKitWebView *web_view;
- gboolean found;
+ if (match_count) {
+ gtk_widget_hide (dialog->priv->result_label);
+ } else {
+ gtk_label_set_label (GTK_LABEL (dialog->priv->result_label), _("No match found"));
+ gtk_widget_show (dialog->priv->result_label);
+ }
+}
- editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
- web_view = WEBKIT_WEB_VIEW (
- e_html_editor_get_view (editor));
+static void
+replace_occurance (EHTMLEditorReplaceDialog *dialog)
+{
+ gtk_widget_hide (dialog->priv->result_label);
- found = webkit_web_view_search_text (
- web_view,
- gtk_entry_get_text (GTK_ENTRY (dialog->priv->search_entry)),
- gtk_toggle_button_get_active (
- GTK_TOGGLE_BUTTON (dialog->priv->case_sensitive)),
- !gtk_toggle_button_get_active (
- GTK_TOGGLE_BUTTON (dialog->priv->backwards)),
- gtk_toggle_button_get_active (
- GTK_TOGGLE_BUTTON (dialog->priv->wrap)));
-
- return found;
+ e_content_editor_replace (
+ dialog->priv->cnt_editor,
+ gtk_entry_get_text (GTK_ENTRY (dialog->priv->replace_entry)));
}
static void
-html_editor_replace_dialog_skip_cb (EHTMLEditorReplaceDialog *dialog)
+content_editor_replace_all_done_cb (EContentEditor *cnt_editor,
+ guint replaced_count,
+ EHTMLEditorReplaceDialog *dialog)
{
- if (!jump (dialog)) {
- gtk_label_set_label (
- GTK_LABEL (dialog->priv->result_label),
- N_("No match found"));
- gtk_widget_show (dialog->priv->result_label);
- } else {
- gtk_widget_hide (dialog->priv->result_label);
- }
+ gchar *result;
+
+ result = g_strdup_printf (ngettext("%d occurrence replaced",
+ "%d occurrences replaced",
+ replaced_count),
+ replaced_count);
+
+ gtk_label_set_label (GTK_LABEL (dialog->priv->result_label), result);
+ gtk_widget_show (dialog->priv->result_label);
+ g_free (result);
}
-static void
-html_editor_replace_dialog_replace_cb (EHTMLEditorReplaceDialog *dialog)
+static guint32
+replace_dialog_get_find_flags (EHTMLEditorReplaceDialog *dialog)
{
- EHTMLEditor *editor;
- EHTMLEditorView *view;
- EHTMLEditorSelection *selection;
+ guint32 flags = E_CONTENT_EDITOR_FIND_NEXT;
- /* Jump to next matching word */
- if (!jump (dialog)) {
- gtk_label_set_label (
- GTK_LABEL (dialog->priv->result_label),
- N_("No match found"));
- gtk_widget_show (dialog->priv->result_label);
- return;
- } else {
- gtk_widget_hide (dialog->priv->result_label);
- }
+ if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->backwards)))
+ flags |= E_CONTENT_EDITOR_FIND_MODE_BACKWARDS;
- editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
- view = e_html_editor_get_view (editor);
- selection = e_html_editor_view_get_selection (view);
+ if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->case_sensitive)))
+ flags |= E_CONTENT_EDITOR_FIND_CASE_INSENSITIVE;
- e_html_editor_selection_replace (
- selection,
- gtk_entry_get_text (GTK_ENTRY (dialog->priv->replace_entry)));
+ if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->wrap)))
+ flags |= E_CONTENT_EDITOR_FIND_WRAP_AROUND;
+
+ return flags;
}
static void
-html_editor_replace_dialog_replace_all_cb (EHTMLEditorReplaceDialog *dialog)
+search (EHTMLEditorReplaceDialog *dialog)
{
- gint i = 0;
- gchar *result;
- EHTMLEditor *editor;
- EHTMLEditorView *view;
- EHTMLEditorViewHistoryEvent *ev = NULL;
- EHTMLEditorSelection *selection;
- const gchar *replacement, *search_text;
- editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
- view = e_html_editor_get_view (editor);
- selection = e_html_editor_view_get_selection (view);
- replacement = gtk_entry_get_text (GTK_ENTRY (dialog->priv->replace_entry));
- search_text = gtk_entry_get_text (GTK_ENTRY (dialog->priv->search_entry));
-
- while (jump (dialog)) {
- e_html_editor_selection_replace (selection, replacement);
- i++;
-
- /* Jump behind the word */
- e_html_editor_selection_move (
- selection, TRUE, E_HTML_EDITOR_SELECTION_GRANULARITY_WORD);
- }
+ e_content_editor_find (
+ dialog->priv->cnt_editor,
+ replace_dialog_get_find_flags (dialog),
+ gtk_entry_get_text (GTK_ENTRY (dialog->priv->search_entry)));
+}
- if (i != 0) {
- if (!e_html_editor_view_is_undo_redo_in_progress (view)) {
- ev = g_new0 (EHTMLEditorViewHistoryEvent, 1);
- ev->type = HISTORY_REPLACE_ALL;
+static void
+html_editor_replace_dialog_skip_cb (EHTMLEditorReplaceDialog *dialog)
+{
+ search (dialog);
+}
- ev->data.string.from = g_strdup (search_text);
- ev->data.string.to = g_strdup (replacement);
+static void
+html_editor_replace_dialog_replace_cb (EHTMLEditorReplaceDialog *dialog)
+{
+ replace_occurance (dialog);
- e_html_editor_view_insert_new_history_event (view, ev);
- }
- e_html_editor_view_force_spell_check_in_viewport (view);
- }
+ /* Jump to next matching word */
+ search (dialog);
+}
- result = g_strdup_printf (ngettext("%d occurrence replaced",
- "%d occurrences replaced",
- i),
- i);
- gtk_label_set_label (GTK_LABEL (dialog->priv->result_label), result);
- gtk_widget_show (dialog->priv->result_label);
- g_free (result);
+static void
+html_editor_replace_dialog_replace_all_cb (EHTMLEditorReplaceDialog *dialog)
+{
+ e_content_editor_replace_all (
+ dialog->priv->cnt_editor,
+ replace_dialog_get_find_flags (dialog),
+ gtk_entry_get_text (GTK_ENTRY (dialog->priv->search_entry)),
+ gtk_entry_get_text (GTK_ENTRY (dialog->priv->replace_entry)));
}
static void
html_editor_replace_dialog_entry_changed (EHTMLEditorReplaceDialog *dialog)
{
gboolean ready;
- ready = ((gtk_entry_get_text_length (
- GTK_ENTRY (dialog->priv->search_entry)) != 0) &&
- (gtk_entry_get_text_length (
- GTK_ENTRY (dialog->priv->replace_entry)) != 0));
+
+ ready = gtk_entry_get_text_length (GTK_ENTRY (dialog->priv->search_entry)) != 0;
gtk_widget_set_sensitive (dialog->priv->skip_button, ready);
gtk_widget_set_sensitive (dialog->priv->replace_button, ready);
gtk_widget_set_sensitive (dialog->priv->replace_all_button, ready);
+
+ if (ready)
+ search (dialog);
}
static void
@@ -188,6 +171,8 @@ html_editor_replace_dialog_show (GtkWidget *widget)
{
EHTMLEditorReplaceDialog *dialog = E_HTML_EDITOR_REPLACE_DIALOG (widget);
+ e_content_editor_on_replace_dialog_open (dialog->priv->cnt_editor);
+
gtk_widget_grab_focus (dialog->priv->search_entry);
gtk_widget_hide (dialog->priv->result_label);
@@ -196,14 +181,82 @@ html_editor_replace_dialog_show (GtkWidget *widget)
}
static void
+html_editor_replace_dialog_hide (GtkWidget *widget)
+{
+ EHTMLEditorReplaceDialog *dialog = E_HTML_EDITOR_REPLACE_DIALOG (widget);
+
+ e_content_editor_on_replace_dialog_close (dialog->priv->cnt_editor);
+
+ /* Chain up to parent implementation */
+ GTK_WIDGET_CLASS (e_html_editor_replace_dialog_parent_class)->hide (widget);
+}
+
+static void
+html_editor_replace_dialog_constructed (GObject *object)
+{
+ EContentEditor *cnt_editor;
+ EHTMLEditor *editor;
+ EHTMLEditorReplaceDialog *dialog;
+
+ dialog = E_HTML_EDITOR_REPLACE_DIALOG (object);
+ dialog->priv = E_HTML_EDITOR_REPLACE_DIALOG_GET_PRIVATE (dialog);
+
+ editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
+ cnt_editor = e_html_editor_get_content_editor (editor);
+
+ dialog->priv->find_done_handler_id = g_signal_connect (
+ cnt_editor, "find-done",
+ G_CALLBACK (content_editor_find_done_cb), dialog);
+
+ dialog->priv->replace_all_done_handler_id = g_signal_connect (
+ cnt_editor, "replace-all-done",
+ G_CALLBACK (content_editor_replace_all_done_cb), dialog);
+
+ dialog->priv->cnt_editor = cnt_editor;
+
+ G_OBJECT_CLASS (e_html_editor_replace_dialog_parent_class)->constructed (object);
+}
+
+static void
+html_editor_replace_dialog_dispose (GObject *object)
+{
+ EHTMLEditorReplaceDialogPrivate *priv;
+
+ priv = E_HTML_EDITOR_REPLACE_DIALOG_GET_PRIVATE (object);
+
+ if (priv->find_done_handler_id > 0) {
+ g_signal_handler_disconnect (
+ priv->cnt_editor,
+ priv->find_done_handler_id);
+ priv->find_done_handler_id = 0;
+ }
+
+ if (priv->replace_all_done_handler_id > 0) {
+ g_signal_handler_disconnect (
+ priv->cnt_editor,
+ priv->replace_all_done_handler_id);
+ priv->replace_all_done_handler_id = 0;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (e_html_editor_replace_dialog_parent_class)->dispose (object);
+}
+
+static void
e_html_editor_replace_dialog_class_init (EHTMLEditorReplaceDialogClass *class)
{
+ GObjectClass *object_class;
GtkWidgetClass *widget_class;
g_type_class_add_private (class, sizeof (EHTMLEditorReplaceDialogPrivate));
+ object_class = G_OBJECT_CLASS (class);
+ object_class->constructed = html_editor_replace_dialog_constructed;
+ object_class->dispose = html_editor_replace_dialog_dispose;
+
widget_class = GTK_WIDGET_CLASS (class);
widget_class->show = html_editor_replace_dialog_show;
+ widget_class->hide = html_editor_replace_dialog_hide;
}
static void
@@ -232,9 +285,6 @@ e_html_editor_replace_dialog_init (EHTMLEditorReplaceDialog *dialog)
widget = gtk_entry_new ();
gtk_grid_attach (main_layout, widget, 1, 1, 2, 1);
dialog->priv->replace_entry = widget;
- g_signal_connect_swapped (
- widget, "notify::text-length",
- G_CALLBACK (html_editor_replace_dialog_entry_changed), dialog);
widget = gtk_label_new_with_mnemonic (_("_With:"));
gtk_label_set_mnemonic_widget (GTK_LABEL (widget), dialog->priv->replace_entry);
diff --git a/e-util/e-html-editor-spell-check-dialog.c b/e-util/e-html-editor-spell-check-dialog.c
index 5d83ec2..d7447e0 100644
--- a/e-util/e-html-editor-spell-check-dialog.c
+++ b/e-util/e-html-editor-spell-check-dialog.c
@@ -27,7 +27,6 @@
#include <glib/gi18n-lib.h>
#include <enchant/enchant.h>
-#include "e-html-editor-view.h"
#include "e-spell-checker.h"
#include "e-spell-dictionary.h"
@@ -48,8 +47,6 @@ struct _EHTMLEditorSpellCheckDialogPrivate {
GtkWidget *suggestion_label;
GtkWidget *tree_view;
- WebKitDOMDOMSelection *selection;
-
gchar *word;
ESpellDictionary *current_dict;
};
@@ -70,7 +67,7 @@ html_editor_spell_check_dialog_set_word (EHTMLEditorSpellCheckDialog *dialog,
const gchar *word)
{
EHTMLEditor *editor;
- EHTMLEditorView *view;
+ EContentEditor *cnt_editor;
GtkTreeView *tree_view;
GtkListStore *store;
gchar *markup;
@@ -127,97 +124,27 @@ html_editor_spell_check_dialog_set_word (EHTMLEditorSpellCheckDialog *dialog,
* given to WebKit, because this dialog is modal, but it satisfies
* it in a way that it paints the selection :) */
editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
- view = e_html_editor_get_view (editor);
- gtk_widget_grab_focus (GTK_WIDGET (view));
-}
-
-static gboolean
-select_next_word (EHTMLEditorSpellCheckDialog *dialog)
-{
- WebKitDOMNode *anchor, *focus;
- gulong anchor_offset, focus_offset;
-
- anchor = webkit_dom_dom_selection_get_anchor_node (dialog->priv->selection);
- anchor_offset = webkit_dom_dom_selection_get_anchor_offset (dialog->priv->selection);
-
- focus = webkit_dom_dom_selection_get_focus_node (dialog->priv->selection);
- focus_offset = webkit_dom_dom_selection_get_focus_offset (dialog->priv->selection);
-
- /* Jump _behind_ next word */
- webkit_dom_dom_selection_modify (
- dialog->priv->selection, "move", "forward", "word");
- /* Jump before the word */
- webkit_dom_dom_selection_modify (
- dialog->priv->selection, "move", "backward", "word");
- /* Select it */
- webkit_dom_dom_selection_modify (
- dialog->priv->selection, "extend", "forward", "word");
-
- /* If the selection didn't change, then we have most probably
- * reached the end of document - return FALSE */
- return !((anchor == webkit_dom_dom_selection_get_anchor_node (
- dialog->priv->selection)) &&
- (anchor_offset == webkit_dom_dom_selection_get_anchor_offset (
- dialog->priv->selection)) &&
- (focus == webkit_dom_dom_selection_get_focus_node (
- dialog->priv->selection)) &&
- (focus_offset == webkit_dom_dom_selection_get_focus_offset (
- dialog->priv->selection)));
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ gtk_widget_grab_focus (GTK_WIDGET (cnt_editor));
}
static gboolean
html_editor_spell_check_dialog_next (EHTMLEditorSpellCheckDialog *dialog)
{
- WebKitDOMNode *start = NULL, *end = NULL;
- gulong start_offset = 0, end_offset = 0;
-
- if (dialog->priv->word == NULL) {
- webkit_dom_dom_selection_modify (
- dialog->priv->selection, "move", "left", "documentboundary");
- } else {
- /* Remember last selected word */
- start = webkit_dom_dom_selection_get_anchor_node (
- dialog->priv->selection);
- end = webkit_dom_dom_selection_get_focus_node (
- dialog->priv->selection);
- start_offset = webkit_dom_dom_selection_get_anchor_offset (
- dialog->priv->selection);
- end_offset = webkit_dom_dom_selection_get_focus_offset (
- dialog->priv->selection);
- }
+ EHTMLEditor *editor;
+ EContentEditor *cnt_editor;
+ gchar *next_word;
- while (select_next_word (dialog)) {
- WebKitDOMRange *range;
- WebKitSpellChecker *checker;
- gint loc, len;
- gchar *word;
-
- range = webkit_dom_dom_selection_get_range_at (
- dialog->priv->selection, 0, NULL);
- word = webkit_dom_range_get_text (range);
- g_object_unref (range);
-
- checker = WEBKIT_SPELL_CHECKER (webkit_get_text_checker ());
- webkit_spell_checker_check_spelling_of_string (
- checker, word, &loc, &len);
-
- /* Found misspelled word! */
- if (loc != -1) {
- html_editor_spell_check_dialog_set_word (dialog, word);
- g_free (word);
- return TRUE;
- }
-
- g_free (word);
- }
+ editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
+ cnt_editor = e_html_editor_get_content_editor (editor);
- /* Restore the selection to contain the last misspelled word. This is
- * reached only when we reach the end of the document */
- if (start && end) {
- webkit_dom_dom_selection_set_base_and_extent (
- dialog->priv->selection, start, start_offset,
- end, end_offset, NULL);
+ next_word = e_content_editor_spell_check_next_word (cnt_editor, dialog->priv->word);
+ if (next_word && *next_word) {
+ html_editor_spell_check_dialog_set_word (dialog, next_word);
+ g_free (next_word);
+ return TRUE;
}
+ g_free (next_word);
/* Close the dialog */
gtk_widget_hide (GTK_WIDGET (dialog));
@@ -225,117 +152,53 @@ html_editor_spell_check_dialog_next (EHTMLEditorSpellCheckDialog *dialog)
}
static gboolean
-select_previous_word (EHTMLEditorSpellCheckDialog *dialog)
-{
- WebKitDOMNode *old_anchor_node;
- WebKitDOMNode *new_anchor_node;
- gulong old_anchor_offset;
- gulong new_anchor_offset;
-
- old_anchor_node = webkit_dom_dom_selection_get_anchor_node (
- dialog->priv->selection);
- old_anchor_offset = webkit_dom_dom_selection_get_anchor_offset (
- dialog->priv->selection);
-
- /* Jump on the beginning of current word */
- webkit_dom_dom_selection_modify (
- dialog->priv->selection, "move", "backward", "word");
- /* Jump before previous word */
- webkit_dom_dom_selection_modify (
- dialog->priv->selection, "move", "backward", "word");
- /* Select it */
- webkit_dom_dom_selection_modify (
- dialog->priv->selection, "extend", "forward", "word");
-
- /* If the selection start didn't change, then we have most probably
- * reached the beginnig of document. Return FALSE */
-
- new_anchor_node = webkit_dom_dom_selection_get_anchor_node (
- dialog->priv->selection);
- new_anchor_offset = webkit_dom_dom_selection_get_anchor_offset (
- dialog->priv->selection);
-
- return (new_anchor_node != old_anchor_node) ||
- (new_anchor_offset != old_anchor_offset);
-}
-
-static gboolean
html_editor_spell_check_dialog_prev (EHTMLEditorSpellCheckDialog *dialog)
{
- WebKitDOMNode *start = NULL, *end = NULL;
- gulong start_offset = 0, end_offset = 0;
-
- if (dialog->priv->word == NULL) {
- webkit_dom_dom_selection_modify (
- dialog->priv->selection,
- "move", "right", "documentboundary");
- webkit_dom_dom_selection_modify (
- dialog->priv->selection,
- "extend", "backward", "word");
- } else {
- /* Remember last selected word */
- start = webkit_dom_dom_selection_get_anchor_node (
- dialog->priv->selection);
- end = webkit_dom_dom_selection_get_focus_node (
- dialog->priv->selection);
- start_offset = webkit_dom_dom_selection_get_anchor_offset (
- dialog->priv->selection);
- end_offset = webkit_dom_dom_selection_get_focus_offset (
- dialog->priv->selection);
- }
+ EHTMLEditor *editor;
+ EContentEditor *cnt_editor;
+ gchar *prev_word;
- while (select_previous_word (dialog)) {
- WebKitDOMRange *range;
- WebKitSpellChecker *checker;
- gint loc, len;
- gchar *word;
-
- range = webkit_dom_dom_selection_get_range_at (
- dialog->priv->selection, 0, NULL);
- word = webkit_dom_range_get_text (range);
- g_object_unref (range);
-
- checker = WEBKIT_SPELL_CHECKER (webkit_get_text_checker ());
- webkit_spell_checker_check_spelling_of_string (
- checker, word, &loc, &len);
-
- /* Found misspelled word! */
- if (loc != -1) {
- html_editor_spell_check_dialog_set_word (dialog, word);
- g_free (word);
- return TRUE;
- }
-
- g_free (word);
- }
+ editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
+ cnt_editor = e_html_editor_get_content_editor (editor);
- /* Restore the selection to contain the last misspelled word. This is
- * reached only when we reach the beginning of the document */
- if (start && end) {
- webkit_dom_dom_selection_set_base_and_extent (
- dialog->priv->selection, start, start_offset,
- end, end_offset, NULL);
+ prev_word = e_content_editor_spell_check_prev_word (cnt_editor, dialog->priv->word);
+ if (prev_word && *prev_word) {
+ html_editor_spell_check_dialog_set_word (dialog, prev_word);
+ g_free (prev_word);
+ return TRUE;
}
+ g_free (prev_word);
/* Close the dialog */
gtk_widget_hide (GTK_WIDGET (dialog));
return FALSE;
}
+static gboolean
+html_editor_spell_check_dialog_next_idle_cb (gpointer user_data)
+{
+ EHTMLEditorSpellCheckDialog *dialog = user_data;
+
+ g_return_val_if_fail (E_IS_HTML_EDITOR_SPELL_CHECK_DIALOG (dialog), FALSE);
+
+ html_editor_spell_check_dialog_next (dialog);
+ g_object_unref (dialog);
+
+ return FALSE;
+}
+
static void
html_editor_spell_check_dialog_replace (EHTMLEditorSpellCheckDialog *dialog)
{
EHTMLEditor *editor;
- EHTMLEditorView *view;
- EHTMLEditorSelection *editor_selection;
+ EContentEditor *cnt_editor;
GtkTreeModel *model;
GtkTreeSelection *selection;
GtkTreeIter iter;
gchar *replacement;
editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
- view = e_html_editor_get_view (editor);
- editor_selection = e_html_editor_view_get_selection (view);
+ cnt_editor = e_html_editor_get_content_editor (editor);
selection = gtk_tree_view_get_selection (
GTK_TREE_VIEW (dialog->priv->tree_view));
@@ -343,47 +206,43 @@ html_editor_spell_check_dialog_replace (EHTMLEditorSpellCheckDialog *dialog)
return;
gtk_tree_model_get (model, &iter, 0, &replacement, -1);
- e_html_editor_selection_insert_html (
- editor_selection, replacement);
+ e_content_editor_insert_content (
+ cnt_editor,
+ replacement,
+ E_CONTENT_EDITOR_INSERT_TEXT_PLAIN);
g_free (replacement);
- html_editor_spell_check_dialog_next (dialog);
+
+ g_idle_add (html_editor_spell_check_dialog_next_idle_cb, g_object_ref (dialog));
}
static void
html_editor_spell_check_dialog_replace_all (EHTMLEditorSpellCheckDialog *dialog)
{
EHTMLEditor *editor;
- EHTMLEditorView *view;
- EHTMLEditorSelection *editor_selection;
+ EContentEditor *cnt_editor;
GtkTreeModel *model;
GtkTreeSelection *selection;
GtkTreeIter iter;
gchar *replacement;
- editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
- view = e_html_editor_get_view (editor);
- editor_selection = e_html_editor_view_get_selection (view);
-
selection = gtk_tree_view_get_selection (
GTK_TREE_VIEW (dialog->priv->tree_view));
if (!gtk_tree_selection_get_selected (selection, &model, &iter))
return;
gtk_tree_model_get (model, &iter, 0, &replacement, -1);
- /* Repeatedly search for 'word', then replace selection by
- * 'replacement'. Repeat until there's at least one occurrence of
- * 'word' in the document */
- while (webkit_web_view_search_text (
- WEBKIT_WEB_VIEW (view), dialog->priv->word,
- FALSE, TRUE, TRUE)) {
+ editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
+ cnt_editor = e_html_editor_get_content_editor (editor);
- e_html_editor_selection_insert_html (
- editor_selection, replacement);
- }
+ e_content_editor_replace_all (
+ cnt_editor,
+ E_CONTENT_EDITOR_FIND_CASE_INSENSITIVE |
+ E_CONTENT_EDITOR_FIND_WRAP_AROUND,
+ dialog->priv->word,
+ replacement);
- g_free (replacement);
- html_editor_spell_check_dialog_next (dialog);
+ g_idle_add (html_editor_spell_check_dialog_next_idle_cb, g_object_ref (dialog));
}
static void
@@ -391,7 +250,6 @@ html_editor_spell_check_dialog_ignore (EHTMLEditorSpellCheckDialog *dialog)
{
if (dialog->priv->word == NULL)
return;
-
e_spell_dictionary_ignore_word (
dialog->priv->current_dict, dialog->priv->word, -1);
@@ -404,8 +262,7 @@ html_editor_spell_check_dialog_learn (EHTMLEditorSpellCheckDialog *dialog)
if (dialog->priv->word == NULL)
return;
- e_spell_dictionary_learn_word (
- dialog->priv->current_dict, dialog->priv->word, -1);
+ e_spell_dictionary_learn_word (dialog->priv->current_dict, dialog->priv->word, -1);
html_editor_spell_check_dialog_next (dialog);
}
@@ -434,45 +291,54 @@ html_editor_spell_check_dialog_set_dictionary (EHTMLEditorSpellCheckDialog *dial
static void
html_editor_spell_check_dialog_show (GtkWidget *widget)
{
- EHTMLEditor *editor;
- EHTMLEditorView *view;
EHTMLEditorSpellCheckDialog *dialog;
- WebKitDOMDocument *document;
- WebKitDOMDOMWindow *dom_window;
dialog = E_HTML_EDITOR_SPELL_CHECK_DIALOG (widget);
g_free (dialog->priv->word);
dialog->priv->word = NULL;
- editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
- view = e_html_editor_get_view (editor);
-
- document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (view));
- dom_window = webkit_dom_document_get_default_view (document);
- dialog->priv->selection = webkit_dom_dom_window_get_selection (dom_window);
- g_object_unref (dom_window);
-
/* Select the first word or quit */
if (html_editor_spell_check_dialog_next (dialog)) {
- GTK_WIDGET_CLASS (e_html_editor_spell_check_dialog_parent_class)->
- show (widget);
+ EHTMLEditor *editor;
+ EContentEditor *cnt_editor;
+
+ editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
+ cnt_editor = e_html_editor_get_content_editor (editor);
+
+ e_content_editor_on_spell_check_dialog_open (cnt_editor);
+
+ GTK_WIDGET_CLASS (e_html_editor_spell_check_dialog_parent_class)->show (widget);
}
}
static void
+html_editor_spell_check_dialog_hide (GtkWidget *widget)
+{
+ EContentEditor *cnt_editor;
+ EHTMLEditor *editor;
+ EHTMLEditorSpellCheckDialog *dialog = E_HTML_EDITOR_SPELL_CHECK_DIALOG (widget);
+
+ editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
+ cnt_editor = e_html_editor_get_content_editor (editor);
+
+ e_content_editor_on_spell_check_dialog_close (cnt_editor);
+
+ /* Chain up to parent implementation */
+ GTK_WIDGET_CLASS (e_html_editor_spell_check_dialog_parent_class)->hide (widget);
+}
+
+static void
html_editor_spell_check_dialog_finalize (GObject *object)
{
EHTMLEditorSpellCheckDialogPrivate *priv;
priv = E_HTML_EDITOR_SPELL_CHECK_DIALOG_GET_PRIVATE (object);
- g_clear_object (&priv->selection);
g_free (priv->word);
/* Chain up to parent's finalize() method. */
- G_OBJECT_CLASS (e_html_editor_spell_check_dialog_parent_class)->
- finalize (object);
+ G_OBJECT_CLASS (e_html_editor_spell_check_dialog_parent_class)->finalize (object);
}
static void
@@ -484,6 +350,7 @@ html_editor_spell_check_dialog_constructed (GObject *object)
G_OBJECT_CLASS (e_html_editor_spell_check_dialog_parent_class)->constructed (object);
dialog = E_HTML_EDITOR_SPELL_CHECK_DIALOG (object);
+
e_html_editor_spell_check_dialog_update_dictionaries (dialog);
}
@@ -502,6 +369,7 @@ e_html_editor_spell_check_dialog_class_init (EHTMLEditorSpellCheckDialogClass *c
widget_class = GTK_WIDGET_CLASS (class);
widget_class->show = html_editor_spell_check_dialog_show;
+ widget_class->hide = html_editor_spell_check_dialog_hide;
}
static void
@@ -644,10 +512,10 @@ void
e_html_editor_spell_check_dialog_update_dictionaries (EHTMLEditorSpellCheckDialog *dialog)
{
EHTMLEditor *editor;
- EHTMLEditorView *view;
+ EContentEditor *cnt_editor;
ESpellChecker *spell_checker;
GtkComboBox *combo_box;
- GtkListStore *store;
+ GtkListStore *store = NULL;
GQueue queue = G_QUEUE_INIT;
gchar **languages;
guint n_languages = 0;
@@ -656,8 +524,8 @@ e_html_editor_spell_check_dialog_update_dictionaries (EHTMLEditorSpellCheckDialo
g_return_if_fail (E_IS_HTML_EDITOR_SPELL_CHECK_DIALOG (dialog));
editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
- view = e_html_editor_get_view (editor);
- spell_checker = e_html_editor_view_get_spell_checker (view);
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ spell_checker = e_content_editor_ref_spell_checker (cnt_editor);
languages = e_spell_checker_list_active_languages (
spell_checker, &n_languages);
@@ -684,7 +552,7 @@ e_html_editor_spell_check_dialog_update_dictionaries (EHTMLEditorSpellCheckDialo
while (!g_queue_is_empty (&queue)) {
ESpellDictionary *dictionary;
GtkTreeIter iter;
- const gchar *name;
+ const gchar *name = NULL;
dictionary = g_queue_pop_head (&queue);
name = e_spell_dictionary_get_name (dictionary);
@@ -705,5 +573,6 @@ e_html_editor_spell_check_dialog_update_dictionaries (EHTMLEditorSpellCheckDialo
gtk_combo_box_set_active (combo_box, 0);
g_object_unref (store);
+ g_clear_object (&spell_checker);
}
diff --git a/e-util/e-html-editor-table-dialog.c b/e-util/e-html-editor-table-dialog.c
index f7155d6..370b72f 100644
--- a/e-util/e-html-editor-table-dialog.c
+++ b/e-util/e-html-editor-table-dialog.c
@@ -28,7 +28,6 @@
#include "e-color-combo.h"
#include "e-dialog-widgets.h"
-#include "e-html-editor-utils.h"
#include "e-image-chooser-dialog.h"
#include "e-misc-utils.h"
@@ -50,15 +49,11 @@ struct _EHTMLEditorTableDialogPrivate {
GtkWidget *alignment_combo;
- GtkWidget *background_color_button;
- GtkWidget *background_image_button;
+ GtkWidget *background_color_picker;
+ GtkWidget *background_image_chooser;
GtkWidget *image_chooser_dialog;
GtkWidget *remove_image_button;
-
- WebKitDOMHTMLTableElement *table_element;
-
- EHTMLEditorViewHistoryEvent *history_event;
};
static GdkRGBA transparent = { 0, 0, 0, 0 };
@@ -68,267 +63,145 @@ G_DEFINE_TYPE (
e_html_editor_table_dialog,
E_TYPE_HTML_EDITOR_DIALOG);
-static WebKitDOMElement *
-html_editor_table_dialog_create_table (EHTMLEditorTableDialog *dialog)
+static void
+html_editor_table_dialog_set_row_count (EHTMLEditorTableDialog *dialog)
{
EHTMLEditor *editor;
- EHTMLEditorSelection *editor_selection;
- EHTMLEditorView *view;
- gint i;
- gchar *text_content;
- gboolean empty = FALSE;
- WebKitDOMDocument *document;
- WebKitDOMElement *table, *br, *caret, *element, *cell;
- WebKitDOMNode *clone;
+ EContentEditor *cnt_editor;
editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
- view = e_html_editor_get_view (editor);
- editor_selection = e_html_editor_view_get_selection (view);
-
- document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (view));
-
- /* Default 3x3 table */
- table = webkit_dom_document_create_element (document, "TABLE", NULL);
- for (i = 0; i < 3; i++) {
- WebKitDOMHTMLElement *row;
- gint j;
-
- row = webkit_dom_html_table_element_insert_row (
- WEBKIT_DOM_HTML_TABLE_ELEMENT (table), -1, NULL);
-
- for (j = 0; j < 3; j++) {
- webkit_dom_html_table_row_element_insert_cell (
- WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (row), -1, NULL);
- }
- }
+ cnt_editor = e_html_editor_get_content_editor (editor);
- e_html_editor_selection_save (editor_selection);
- caret = webkit_dom_document_get_element_by_id (
- document, "-x-evo-selection-end-marker");
-
- element = get_parent_block_element (WEBKIT_DOM_NODE (caret));
- text_content = webkit_dom_node_get_text_content (WEBKIT_DOM_NODE (element));
- empty = text_content && !*text_content;
- g_free (text_content);
-
- clone = webkit_dom_node_clone_node (WEBKIT_DOM_NODE (element), FALSE);
- br = webkit_dom_document_create_element (document, "BR", NULL);
- webkit_dom_node_append_child (clone, WEBKIT_DOM_NODE (br), NULL);
- webkit_dom_node_insert_before (
- webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element)),
- clone,
- webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (element)),
- NULL);
-
- /* Move caret to the first cell */
- cell = webkit_dom_element_query_selector (table, "td", NULL);
- webkit_dom_node_append_child (
- WEBKIT_DOM_NODE (cell), WEBKIT_DOM_NODE (caret), NULL);
- caret = webkit_dom_document_get_element_by_id (
- document, "-x-evo-selection-start-marker");
- webkit_dom_node_insert_before (
- WEBKIT_DOM_NODE (cell),
- WEBKIT_DOM_NODE (caret),
- webkit_dom_node_get_last_child (WEBKIT_DOM_NODE (cell)),
- NULL);
-
- /* Insert the table into body unred the current block (if current block is not empty)
- * otherwise replace the current block. */
- if (empty) {
- webkit_dom_node_replace_child (
- webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element)),
- WEBKIT_DOM_NODE (table),
- WEBKIT_DOM_NODE (element),
- NULL);
- } else {
- webkit_dom_node_insert_before (
- webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element)),
- WEBKIT_DOM_NODE (table),
- webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (element)),
- NULL);
- }
-
- e_html_editor_selection_restore (editor_selection);
-
- e_html_editor_view_set_changed (view, TRUE);
-
- return table;
-}
-
-static void
-html_editor_table_dialog_set_row_count (EHTMLEditorTableDialog *dialog)
-{
- WebKitDOMHTMLCollection *rows;
- gulong ii, current_count, expected_count;
-
- g_return_if_fail (dialog->priv->table_element);
-
- rows = webkit_dom_html_table_element_get_rows (dialog->priv->table_element);
- current_count = webkit_dom_html_collection_get_length (rows);
- expected_count = gtk_spin_button_get_value (
- GTK_SPIN_BUTTON (dialog->priv->rows_edit));
-
- if (current_count < expected_count) {
- for (ii = 0; ii < expected_count - current_count; ii++) {
- webkit_dom_html_table_element_insert_row (
- dialog->priv->table_element, -1, NULL);
- }
- } else if (current_count > expected_count) {
- for (ii = 0; ii < current_count - expected_count; ii++) {
- webkit_dom_html_table_element_delete_row (
- dialog->priv->table_element, -1, NULL);
- }
- }
- g_object_unref (rows);
+ e_content_editor_table_set_row_count (
+ cnt_editor,
+ gtk_spin_button_get_value (
+ GTK_SPIN_BUTTON (dialog->priv->rows_edit)));
}
static void
html_editor_table_dialog_get_row_count (EHTMLEditorTableDialog *dialog)
{
- WebKitDOMHTMLCollection *rows;
-
- g_return_if_fail (dialog->priv->table_element);
+ EHTMLEditor *editor;
+ EContentEditor *cnt_editor;
- rows = webkit_dom_html_table_element_get_rows (dialog->priv->table_element);
+ editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
+ cnt_editor = e_html_editor_get_content_editor (editor);
gtk_spin_button_set_value (
GTK_SPIN_BUTTON (dialog->priv->rows_edit),
- webkit_dom_html_collection_get_length (rows));
- g_object_unref (rows);
+ e_content_editor_table_get_row_count (cnt_editor));
}
static void
html_editor_table_dialog_set_column_count (EHTMLEditorTableDialog *dialog)
{
- WebKitDOMHTMLCollection *rows;
- gulong ii, row_count, expected_columns;
-
- g_return_if_fail (dialog->priv->table_element);
-
- rows = webkit_dom_html_table_element_get_rows (dialog->priv->table_element);
- row_count = webkit_dom_html_collection_get_length (rows);
- expected_columns = gtk_spin_button_get_value (
- GTK_SPIN_BUTTON (dialog->priv->columns_edit));
-
- for (ii = 0; ii < row_count; ii++) {
- WebKitDOMHTMLTableRowElement *row;
- WebKitDOMHTMLCollection *cells;
- gulong jj, current_columns;
-
- row = WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (
- webkit_dom_html_collection_item (rows, ii));
-
- cells = webkit_dom_html_table_row_element_get_cells (row);
- current_columns = webkit_dom_html_collection_get_length (cells);
-
- if (current_columns < expected_columns) {
- for (jj = 0; jj < expected_columns - current_columns; jj++) {
- webkit_dom_html_table_row_element_insert_cell (
- row, -1, NULL);
- }
- } else if (expected_columns < current_columns) {
- for (jj = 0; jj < current_columns - expected_columns; jj++) {
- webkit_dom_html_table_row_element_delete_cell (
- row, -1, NULL);
- }
- }
- g_object_unref (row);
- g_object_unref (cells);
- }
- g_object_unref (rows);
+ EHTMLEditor *editor;
+ EContentEditor *cnt_editor;
+
+ editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
+ cnt_editor = e_html_editor_get_content_editor (editor);
+
+ e_content_editor_table_set_column_count (
+ cnt_editor,
+ gtk_spin_button_get_value (
+ GTK_SPIN_BUTTON (dialog->priv->columns_edit)));
}
static void
html_editor_table_dialog_get_column_count (EHTMLEditorTableDialog *dialog)
{
- WebKitDOMHTMLCollection *rows, *columns;
- WebKitDOMNode *row;
-
- g_return_if_fail (dialog->priv->table_element);
-
- rows = webkit_dom_html_table_element_get_rows (dialog->priv->table_element);
- row = webkit_dom_html_collection_item (rows, 0);
+ EHTMLEditor *editor;
+ EContentEditor *cnt_editor;
- columns = webkit_dom_html_table_row_element_get_cells (
- WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (row));
+ editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
+ cnt_editor = e_html_editor_get_content_editor (editor);
gtk_spin_button_set_value (
GTK_SPIN_BUTTON (dialog->priv->columns_edit),
- webkit_dom_html_collection_get_length (columns));
- g_object_unref (row);
- g_object_unref (rows);
- g_object_unref (columns);
+ e_content_editor_table_get_column_count (cnt_editor));
}
static void
html_editor_table_dialog_set_width (EHTMLEditorTableDialog *dialog)
{
- gchar *width;
+ EHTMLEditor *editor;
+ EContentEditor *cnt_editor;
- g_return_if_fail (dialog->priv->table_element);
+ editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
+ cnt_editor = e_html_editor_get_content_editor (editor);
if (gtk_toggle_button_get_active (
GTK_TOGGLE_BUTTON (dialog->priv->width_check))) {
- gchar *units;
- units = gtk_combo_box_text_get_active_text (
- GTK_COMBO_BOX_TEXT (dialog->priv->width_units));
- width = g_strdup_printf (
- "%d%s",
+ e_content_editor_table_set_width (
+ cnt_editor,
gtk_spin_button_get_value_as_int (
GTK_SPIN_BUTTON (dialog->priv->width_edit)),
- units);
- g_free (units);
+ (gtk_combo_box_get_active (
+ GTK_COMBO_BOX (dialog->priv->width_units)) == 0) ?
+ E_CONTENT_EDITOR_UNIT_PIXEL :
+ E_CONTENT_EDITOR_UNIT_PERCENTAGE);
gtk_widget_set_sensitive (dialog->priv->width_edit, TRUE);
gtk_widget_set_sensitive (dialog->priv->width_units, TRUE);
} else {
- width = g_strdup ("auto");
+ e_content_editor_table_set_width (
+ cnt_editor, 0, E_CONTENT_EDITOR_UNIT_AUTO);
gtk_widget_set_sensitive (dialog->priv->width_edit, FALSE);
gtk_widget_set_sensitive (dialog->priv->width_units, FALSE);
}
+}
- webkit_dom_html_table_element_set_width (
- dialog->priv->table_element, width);
- g_free (width);
+static void
+html_editor_table_dialog_width_units_changed (GtkWidget *widget,
+ EHTMLEditorTableDialog *dialog)
+{
+ if (gtk_combo_box_get_active (GTK_COMBO_BOX (dialog->priv->width_units)) == 0) {
+ gtk_spin_button_set_range (
+ GTK_SPIN_BUTTON (dialog->priv->width_edit), 0, G_MAXUINT);
+ } else
+ gtk_spin_button_set_range (
+ GTK_SPIN_BUTTON (dialog->priv->width_edit), 0, 100);
+
+ html_editor_table_dialog_set_width (dialog);
}
static void
html_editor_table_dialog_get_width (EHTMLEditorTableDialog *dialog)
{
- gchar *width;
-
- width = webkit_dom_html_table_element_get_width (dialog->priv->table_element);
- if (!width || !*width || g_ascii_strncasecmp (width, "auto", 4) == 0) {
- gtk_toggle_button_set_active (
- GTK_TOGGLE_BUTTON (dialog->priv->width_check), FALSE);
- gtk_spin_button_set_value (
- GTK_SPIN_BUTTON (dialog->priv->width_edit), 100);
- gtk_combo_box_set_active_id (
- GTK_COMBO_BOX (dialog->priv->width_units), "units-percent");
- } else {
- gint width_int = atoi (width);
-
- gtk_toggle_button_set_active (
- GTK_TOGGLE_BUTTON (dialog->priv->width_check), TRUE);
- gtk_spin_button_set_value (
- GTK_SPIN_BUTTON (dialog->priv->width_edit), width_int);
- gtk_combo_box_set_active_id (
- GTK_COMBO_BOX (dialog->priv->width_units),
- ((strstr (width, "%") == NULL) ?
- "units-px" : "units-percent"));
- }
- g_free (width);
+ EHTMLEditor *editor;
+ EContentEditor *cnt_editor;
+ EContentEditorUnit unit;
+ gint width;
+
+ editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
+ cnt_editor = e_html_editor_get_content_editor (editor);
+
+ width = e_content_editor_table_get_width (cnt_editor, &unit);
+
+ gtk_toggle_button_set_active (
+ GTK_TOGGLE_BUTTON (dialog->priv->width_check),
+ unit != E_CONTENT_EDITOR_UNIT_AUTO);
+ gtk_spin_button_set_value (
+ GTK_SPIN_BUTTON (dialog->priv->width_edit),
+ unit == E_CONTENT_EDITOR_UNIT_AUTO ? 100 : width);
+ gtk_combo_box_set_active_id (
+ GTK_COMBO_BOX (dialog->priv->width_units),
+ unit == E_CONTENT_EDITOR_UNIT_PIXEL ? "units-px" : "units-percent");
}
static void
html_editor_table_dialog_set_alignment (EHTMLEditorTableDialog *dialog)
{
- g_return_if_fail (dialog->priv->table_element);
+ EHTMLEditor *editor;
+ EContentEditor *cnt_editor;
- webkit_dom_html_table_element_set_align (
- dialog->priv->table_element,
+ editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
+ cnt_editor = e_html_editor_get_content_editor (editor);
+
+ e_content_editor_table_set_align (
+ cnt_editor,
gtk_combo_box_get_active_id (
GTK_COMBO_BOX (dialog->priv->alignment_combo)));
}
@@ -336,208 +209,150 @@ html_editor_table_dialog_set_alignment (EHTMLEditorTableDialog *dialog)
static void
html_editor_table_dialog_get_alignment (EHTMLEditorTableDialog *dialog)
{
- gchar *alignment;
-
- g_return_if_fail (dialog->priv->table_element);
+ EHTMLEditor *editor;
+ EContentEditor *cnt_editor;
+ gchar *value;
- alignment = webkit_dom_html_table_element_get_align (
- dialog->priv->table_element);
+ editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ value = e_content_editor_table_get_align (cnt_editor);
gtk_combo_box_set_active_id (
- GTK_COMBO_BOX (dialog->priv->alignment_combo), alignment);
-
- g_free (alignment);
+ GTK_COMBO_BOX (dialog->priv->alignment_combo), value);
+ g_free (value);
}
static void
html_editor_table_dialog_set_padding (EHTMLEditorTableDialog *dialog)
{
- gchar *padding;
-
- g_return_if_fail (dialog->priv->table_element);
-
- padding = g_strdup_printf (
- "%d",
- gtk_spin_button_get_value_as_int (
- GTK_SPIN_BUTTON (dialog->priv->padding_edit)));
+ EHTMLEditor *editor;
+ EContentEditor *cnt_editor;
- webkit_dom_html_table_element_set_cell_padding (
- dialog->priv->table_element, padding);
+ editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
+ cnt_editor = e_html_editor_get_content_editor (editor);
- g_free (padding);
+ e_content_editor_table_set_padding (
+ cnt_editor,
+ gtk_spin_button_get_value_as_int (
+ GTK_SPIN_BUTTON (dialog->priv->padding_edit)));
}
static void
html_editor_table_dialog_get_padding (EHTMLEditorTableDialog *dialog)
{
- gchar *padding;
- gint padding_int;
-
- g_return_if_fail (dialog->priv->table_element);
+ EHTMLEditor *editor;
+ EContentEditor *cnt_editor;
- padding = webkit_dom_html_table_element_get_cell_padding (
- dialog->priv->table_element);
- if (!padding || !*padding) {
- padding_int = 0;
- } else {
- padding_int = atoi (padding);
- }
+ editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
+ cnt_editor = e_html_editor_get_content_editor (editor);
gtk_spin_button_set_value (
- GTK_SPIN_BUTTON (dialog->priv->padding_edit), padding_int);
-
- g_free (padding);
+ GTK_SPIN_BUTTON (dialog->priv->padding_edit),
+ e_content_editor_table_get_padding (cnt_editor));
}
static void
html_editor_table_dialog_set_spacing (EHTMLEditorTableDialog *dialog)
{
- gchar *spacing;
-
- g_return_if_fail (dialog->priv->table_element);
-
- spacing = g_strdup_printf (
- "%d",
- gtk_spin_button_get_value_as_int (
- GTK_SPIN_BUTTON (dialog->priv->spacing_edit)));
+ EHTMLEditor *editor;
+ EContentEditor *cnt_editor;
- webkit_dom_html_table_element_set_cell_spacing (
- dialog->priv->table_element, spacing);
+ editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
+ cnt_editor = e_html_editor_get_content_editor (editor);
- g_free (spacing);
+ e_content_editor_table_set_spacing (
+ cnt_editor,
+ gtk_spin_button_get_value_as_int (
+ GTK_SPIN_BUTTON (dialog->priv->spacing_edit)));
}
static void
html_editor_table_dialog_get_spacing (EHTMLEditorTableDialog *dialog)
{
- gchar *spacing;
- gint spacing_int;
-
- g_return_if_fail (dialog->priv->table_element);
+ EHTMLEditor *editor;
+ EContentEditor *cnt_editor;
- spacing = webkit_dom_html_table_element_get_cell_spacing (
- dialog->priv->table_element);
- if (!spacing || !*spacing) {
- spacing_int = 0;
- } else {
- spacing_int = atoi (spacing);
- }
+ editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
+ cnt_editor = e_html_editor_get_content_editor (editor);
gtk_spin_button_set_value (
- GTK_SPIN_BUTTON (dialog->priv->spacing_edit), spacing_int);
-
- g_free (spacing);
+ GTK_SPIN_BUTTON (dialog->priv->spacing_edit),
+ e_content_editor_table_get_spacing (cnt_editor));
}
static void
html_editor_table_dialog_set_border (EHTMLEditorTableDialog *dialog)
{
- gchar *border;
-
- g_return_if_fail (dialog->priv->table_element);
-
- border = g_strdup_printf (
- "%d",
- gtk_spin_button_get_value_as_int (
- GTK_SPIN_BUTTON (dialog->priv->border_edit)));
+ EHTMLEditor *editor;
+ EContentEditor *cnt_editor;
- webkit_dom_html_table_element_set_border (
- dialog->priv->table_element, border);
+ editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
+ cnt_editor = e_html_editor_get_content_editor (editor);
- g_free (border);
+ e_content_editor_table_set_border (
+ cnt_editor,
+ gtk_spin_button_get_value_as_int (
+ GTK_SPIN_BUTTON (dialog->priv->border_edit)));
}
static void
html_editor_table_dialog_get_border (EHTMLEditorTableDialog *dialog)
{
- gchar *border;
- gint border_int;
-
- g_return_if_fail (dialog->priv->table_element);
+ EHTMLEditor *editor;
+ EContentEditor *cnt_editor;
- border = webkit_dom_html_table_element_get_border (
- dialog->priv->table_element);
- if (!border || !*border) {
- border_int = 0;
- } else {
- border_int = atoi (border);
- }
+ editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
+ cnt_editor = e_html_editor_get_content_editor (editor);
gtk_spin_button_set_value (
- GTK_SPIN_BUTTON (dialog->priv->border_edit), border_int);
-
- g_free (border);
+ GTK_SPIN_BUTTON (dialog->priv->border_edit),
+ e_content_editor_table_get_border (cnt_editor));
}
static void
html_editor_table_dialog_set_background_color (EHTMLEditorTableDialog *dialog)
{
- gchar *color;
+ EHTMLEditor *editor;
+ EContentEditor *cnt_editor;
GdkRGBA rgba;
- g_return_if_fail (dialog->priv->table_element);
+ editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
+ cnt_editor = e_html_editor_get_content_editor (editor);
e_color_combo_get_current_color (
- E_COLOR_COMBO (dialog->priv->background_color_button), &rgba);
-
- if (rgba.alpha != 0.0)
- color = g_strdup_printf ("#%06x", e_rgba_to_value (&rgba));
- else
- color = g_strdup ("");
-
- webkit_dom_html_table_element_set_bg_color (
- dialog->priv->table_element, color);
-
- g_free (color);
+ E_COLOR_COMBO (dialog->priv->background_color_picker), &rgba);
+ e_content_editor_table_set_background_color (cnt_editor, &rgba);
}
static void
html_editor_table_dialog_get_background_color (EHTMLEditorTableDialog *dialog)
{
- gchar *color;
+ EHTMLEditor *editor;
+ EContentEditor *cnt_editor;
GdkRGBA rgba;
- g_return_if_fail (dialog->priv->table_element);
-
- color = webkit_dom_html_table_element_get_bg_color (
- dialog->priv->table_element);
-
- if (color && *color) {
- gdk_rgba_parse (&rgba, color);
-
- e_color_combo_set_current_color (
- E_COLOR_COMBO (dialog->priv->background_color_button), &rgba);
- } else {
- e_color_combo_set_current_color (
- E_COLOR_COMBO (dialog->priv->background_color_button), &transparent);
- }
+ editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
+ cnt_editor = e_html_editor_get_content_editor (editor);
- g_free (color);
+ e_content_editor_table_get_background_color (cnt_editor, &rgba);
+ e_color_combo_set_current_color (
+ E_COLOR_COMBO (dialog->priv->background_color_picker), &rgba);
}
static void
html_editor_table_dialog_set_background_image (EHTMLEditorTableDialog *dialog)
{
EHTMLEditor *editor;
- EHTMLEditorView *view;
+ EContentEditor *cnt_editor;
gchar *uri;
- g_return_if_fail (dialog->priv->table_element);
-
editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
- view = e_html_editor_get_view (editor);
+ cnt_editor = e_html_editor_get_content_editor (editor);
uri = gtk_file_chooser_get_uri (
- GTK_FILE_CHOOSER (dialog->priv->background_image_button));
+ GTK_FILE_CHOOSER (dialog->priv->background_image_chooser));
- if (uri && *uri)
- e_html_editor_selection_replace_image_src (
- e_html_editor_view_get_selection (view),
- WEBKIT_DOM_ELEMENT (dialog->priv->table_element),
- uri);
- else
- remove_image_attributes_from_element (
- WEBKIT_DOM_ELEMENT (dialog->priv->table_element));
+ e_content_editor_table_set_background_image_uri (cnt_editor, uri);
gtk_widget_set_sensitive (dialog->priv->remove_image_button, uri && *uri);
@@ -547,27 +362,22 @@ html_editor_table_dialog_set_background_image (EHTMLEditorTableDialog *dialog)
static void
html_editor_table_dialog_get_background_image (EHTMLEditorTableDialog *dialog)
{
- g_return_if_fail (dialog->priv->table_element);
-
-
- if (!webkit_dom_element_has_attribute (
- WEBKIT_DOM_ELEMENT (dialog->priv->table_element), "background")) {
-
- gtk_file_chooser_unselect_all (
- GTK_FILE_CHOOSER (dialog->priv->background_image_button));
- return;
- } else {
- gchar *value;
+ EHTMLEditor *editor;
+ EContentEditor *cnt_editor;
+ gchar *uri;
- value = webkit_dom_element_get_attribute (
- WEBKIT_DOM_ELEMENT (dialog->priv->table_element), "data-uri");
+ editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ uri = e_content_editor_table_get_background_image_uri (cnt_editor);
+ if (uri && *uri)
gtk_file_chooser_set_uri (
- GTK_FILE_CHOOSER (dialog->priv->background_image_button),
- value);
+ GTK_FILE_CHOOSER (dialog->priv->background_image_chooser), uri);
+ else
+ gtk_file_chooser_unselect_all (
+ GTK_FILE_CHOOSER (dialog->priv->background_image_chooser));
- g_free (value);
- }
+ g_free (uri);
}
static void
@@ -609,10 +419,10 @@ html_editor_table_dialog_reset_values (EHTMLEditorTableDialog *dialog)
GTK_SPIN_BUTTON (dialog->priv->border_edit), 1);
e_color_combo_set_current_color (
- E_COLOR_COMBO (dialog->priv->background_color_button), &transparent);
+ E_COLOR_COMBO (dialog->priv->background_color_picker), &transparent);
gtk_file_chooser_unselect_all (
- GTK_FILE_CHOOSER (dialog->priv->background_image_button));
+ GTK_FILE_CHOOSER (dialog->priv->background_image_chooser));
html_editor_table_dialog_set_row_count (dialog);
html_editor_table_dialog_set_column_count (dialog);
@@ -630,56 +440,16 @@ html_editor_table_dialog_show (GtkWidget *widget)
{
EHTMLEditorTableDialog *dialog;
EHTMLEditor *editor;
- EHTMLEditorView *view;
- WebKitDOMDocument *document;
- WebKitDOMDOMWindow *dom_window;
- WebKitDOMDOMSelection *dom_selection;
+ EContentEditor *cnt_editor;
dialog = E_HTML_EDITOR_TABLE_DIALOG (widget);
editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
- view = e_html_editor_get_view (editor);
-
- document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (view));
- dom_window = webkit_dom_document_get_default_view (document);
- dom_selection = webkit_dom_dom_window_get_selection (dom_window);
- g_object_unref (dom_window);
- if (dom_selection && (webkit_dom_dom_selection_get_range_count (dom_selection) > 0)) {
- WebKitDOMElement *table;
- WebKitDOMRange *range;
-
- range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
- table = e_html_editor_dom_node_find_parent_element (
- webkit_dom_range_get_start_container (range, NULL), "TABLE");
- g_object_unref (range);
-
- if (!table) {
- dialog->priv->table_element = WEBKIT_DOM_HTML_TABLE_ELEMENT (
- html_editor_table_dialog_create_table (dialog));
- html_editor_table_dialog_reset_values (dialog);
- } else {
- dialog->priv->table_element =
- WEBKIT_DOM_HTML_TABLE_ELEMENT (table);
- html_editor_table_dialog_get_values (dialog);
- }
-
- if (!e_html_editor_view_is_undo_redo_in_progress (view)) {
- EHTMLEditorViewHistoryEvent *ev;
-
- ev = g_new0 (EHTMLEditorViewHistoryEvent, 1);
- ev->type = HISTORY_TABLE_DIALOG;
-
- e_html_editor_selection_get_selection_coordinates (
- e_html_editor_view_get_selection (view),
- &ev->before.start.x, &ev->before.start.y,
- &ev->before.end.x, &ev->before.end.y);
- if (table)
- ev->data.dom.from = webkit_dom_node_clone_node (
- WEBKIT_DOM_NODE (table), TRUE);
- dialog->priv->history_event = ev;
- }
- }
+ cnt_editor = e_html_editor_get_content_editor (editor);
- g_object_unref (dom_selection);
+ if (e_content_editor_on_table_dialog_open (cnt_editor))
+ html_editor_table_dialog_reset_values (dialog);
+ else
+ html_editor_table_dialog_get_values (dialog);
/* Chain up to parent implementation */
GTK_WIDGET_CLASS (e_html_editor_table_dialog_parent_class)->show (widget);
@@ -688,11 +458,16 @@ html_editor_table_dialog_show (GtkWidget *widget)
static void
html_editor_table_dialog_remove_image (EHTMLEditorTableDialog *dialog)
{
- remove_image_attributes_from_element (
- WEBKIT_DOM_ELEMENT (dialog->priv->table_element));
+ EHTMLEditor *editor;
+ EContentEditor *cnt_editor;
+
+ editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
+ cnt_editor = e_html_editor_get_content_editor (editor);
+
+ e_content_editor_table_set_background_image_uri (cnt_editor, NULL);
gtk_file_chooser_unselect_all (
- GTK_FILE_CHOOSER (dialog->priv->background_image_button));
+ GTK_FILE_CHOOSER (dialog->priv->background_image_chooser));
gtk_widget_set_sensitive (dialog->priv->remove_image_button, FALSE);
}
@@ -700,39 +475,15 @@ html_editor_table_dialog_remove_image (EHTMLEditorTableDialog *dialog)
static void
html_editor_table_dialog_hide (GtkWidget *widget)
{
- EHTMLEditorTableDialogPrivate *priv;
- EHTMLEditorViewHistoryEvent *ev;
-
- priv = E_HTML_EDITOR_TABLE_DIALOG_GET_PRIVATE (widget);
- ev = priv->history_event;
-
- if (ev) {
- EHTMLEditorTableDialog *dialog;
- EHTMLEditor *editor;
- EHTMLEditorSelection *selection;
- EHTMLEditorView *view;
-
- dialog = E_HTML_EDITOR_TABLE_DIALOG (widget);
- editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
- view = e_html_editor_get_view (editor);
- selection = e_html_editor_view_get_selection (view);
-
- ev->data.dom.to = webkit_dom_node_clone_node (
- WEBKIT_DOM_NODE (priv->table_element), TRUE);
-
- if (!webkit_dom_node_is_equal_node (ev->data.dom.from, ev->data.dom.to)) {
- e_html_editor_selection_get_selection_coordinates (
- selection, &ev->after.start.x, &ev->after.start.y, &ev->after.end.x,
&ev->after.end.y);
- e_html_editor_view_insert_new_history_event (view, ev);
- } else {
- g_object_unref (ev->data.dom.from);
- g_object_unref (ev->data.dom.to);
- g_free (ev);
- }
- }
+ EHTMLEditorTableDialog *dialog;
+ EHTMLEditor *editor;
+ EContentEditor *cnt_editor;
+
+ dialog = E_HTML_EDITOR_TABLE_DIALOG (widget);
+ editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
+ cnt_editor = e_html_editor_get_content_editor (editor);
- g_object_unref (priv->table_element);
- priv->table_element = NULL;
+ e_content_editor_on_table_dialog_close (cnt_editor);
GTK_WIDGET_CLASS (e_html_editor_table_dialog_parent_class)->hide (widget);
}
@@ -839,9 +590,9 @@ e_html_editor_table_dialog_init (EHTMLEditorTableDialog *dialog)
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (widget), "units-px", "px");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (widget), "units-percent", "%");
gtk_grid_attach (grid, widget, 2, 0, 1, 1);
- g_signal_connect_swapped (
+ g_signal_connect (
widget, "changed",
- G_CALLBACK (html_editor_table_dialog_set_width), dialog);
+ G_CALLBACK (html_editor_table_dialog_width_units_changed), dialog);
dialog->priv->width_units = widget;
/* Spacing */
@@ -932,12 +683,12 @@ e_html_editor_table_dialog_init (EHTMLEditorTableDialog *dialog)
g_signal_connect_swapped (
widget, "notify::current-color",
G_CALLBACK (html_editor_table_dialog_set_background_color), dialog);
- dialog->priv->background_color_button = widget;
+ dialog->priv->background_color_picker = widget;
widget = gtk_label_new_with_mnemonic (_("_Color:"));
gtk_label_set_justify (GTK_LABEL (widget), GTK_JUSTIFY_RIGHT);
gtk_label_set_mnemonic_widget (
- GTK_LABEL (widget), dialog->priv->background_color_button);
+ GTK_LABEL (widget), dialog->priv->background_color_picker);
gtk_grid_attach (grid, widget, 0, 0, 1, 1);
/* Image */
@@ -958,12 +709,12 @@ e_html_editor_table_dialog_init (EHTMLEditorTableDialog *dialog)
g_signal_connect_swapped (
widget, "file-set",
G_CALLBACK (html_editor_table_dialog_set_background_image), dialog);
- dialog->priv->background_image_button = widget;
+ dialog->priv->background_image_chooser = widget;
widget =gtk_label_new_with_mnemonic (_("Image:"));
gtk_label_set_justify (GTK_LABEL (widget), GTK_JUSTIFY_RIGHT);
gtk_label_set_mnemonic_widget (
- GTK_LABEL (widget), dialog->priv->background_image_button);
+ GTK_LABEL (widget), dialog->priv->background_image_chooser);
gtk_grid_attach (grid, widget, 0, 1, 1, 1);
box = e_html_editor_dialog_get_button_box (E_HTML_EDITOR_DIALOG (dialog));
@@ -990,4 +741,3 @@ e_html_editor_table_dialog_new (EHTMLEditor *editor)
"title", _("Table Properties"),
NULL));
}
-
diff --git a/e-util/e-html-editor-text-dialog.c b/e-util/e-html-editor-text-dialog.c
index 9edb8e5..f944338 100644
--- a/e-util/e-html-editor-text-dialog.c
+++ b/e-util/e-html-editor-text-dialog.c
@@ -51,15 +51,13 @@ static void
html_editor_text_dialog_set_bold (EHTMLEditorTextDialog *dialog)
{
EHTMLEditor *editor;
- EHTMLEditorView *view;
- EHTMLEditorSelection *selection;
+ EContentEditor *cnt_editor;
editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
- view = e_html_editor_get_view (editor);
- selection = e_html_editor_view_get_selection (view);
+ cnt_editor = e_html_editor_get_content_editor (editor);
- e_html_editor_selection_set_bold (
- selection,
+ e_content_editor_set_bold (
+ cnt_editor,
gtk_toggle_button_get_active (
GTK_TOGGLE_BUTTON (dialog->priv->bold_check)));
}
@@ -68,15 +66,13 @@ static void
html_editor_text_dialog_set_italic (EHTMLEditorTextDialog *dialog)
{
EHTMLEditor *editor;
- EHTMLEditorView *view;
- EHTMLEditorSelection *selection;
+ EContentEditor *cnt_editor;
editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
- view = e_html_editor_get_view (editor);
- selection = e_html_editor_view_get_selection (view);
+ cnt_editor = e_html_editor_get_content_editor (editor);
- e_html_editor_selection_set_italic (
- selection,
+ e_content_editor_set_italic (
+ cnt_editor,
gtk_toggle_button_get_active (
GTK_TOGGLE_BUTTON (dialog->priv->italic_check)));
}
@@ -85,15 +81,13 @@ static void
html_editor_text_dialog_set_underline (EHTMLEditorTextDialog *dialog)
{
EHTMLEditor *editor;
- EHTMLEditorView *view;
- EHTMLEditorSelection *selection;
+ EContentEditor *cnt_editor;
editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
- view = e_html_editor_get_view (editor);
- selection = e_html_editor_view_get_selection (view);
+ cnt_editor = e_html_editor_get_content_editor (editor);
- e_html_editor_selection_set_underline (
- selection,
+ e_content_editor_set_underline (
+ cnt_editor,
gtk_toggle_button_get_active (
GTK_TOGGLE_BUTTON (dialog->priv->underline_check)));
}
@@ -102,15 +96,13 @@ static void
html_editor_text_dialog_set_strikethrough (EHTMLEditorTextDialog *dialog)
{
EHTMLEditor *editor;
- EHTMLEditorView *view;
- EHTMLEditorSelection *selection;
+ EContentEditor *cnt_editor;
editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
- view = e_html_editor_get_view (editor);
- selection = e_html_editor_view_get_selection (view);
+ cnt_editor = e_html_editor_get_content_editor (editor);
- e_html_editor_selection_set_strikethrough (
- selection,
+ e_content_editor_set_strikethrough (
+ cnt_editor,
gtk_toggle_button_get_active (
GTK_TOGGLE_BUTTON (dialog->priv->strikethrough_check)));
}
@@ -119,33 +111,29 @@ static void
html_editor_text_dialog_set_color (EHTMLEditorTextDialog *dialog)
{
EHTMLEditor *editor;
- EHTMLEditorView *view;
- EHTMLEditorSelection *selection;
+ EContentEditor *cnt_editor;
GdkRGBA rgba;
editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
- view = e_html_editor_get_view (editor);
- selection = e_html_editor_view_get_selection (view);
+ cnt_editor = e_html_editor_get_content_editor (editor);
e_color_combo_get_current_color (
E_COLOR_COMBO (dialog->priv->color_check), &rgba);
- e_html_editor_selection_set_font_color (selection, &rgba);
+ e_content_editor_set_font_color (cnt_editor, &rgba);
}
static void
html_editor_text_dialog_set_size (EHTMLEditorTextDialog *dialog)
{
EHTMLEditor *editor;
- EHTMLEditorView *view;
- EHTMLEditorSelection *selection;
+ EContentEditor *cnt_editor;
gint size;
editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
- view = e_html_editor_get_view (editor);
- selection = e_html_editor_view_get_selection (view);
+ cnt_editor = e_html_editor_get_content_editor (editor);
size = gtk_combo_box_get_active (GTK_COMBO_BOX (dialog->priv->size_check));
- e_html_editor_selection_set_font_size (selection, size + 1);
+ e_content_editor_set_font_size (cnt_editor, size + 1);
}
static void
@@ -153,35 +141,36 @@ html_editor_text_dialog_show (GtkWidget *widget)
{
EHTMLEditorTextDialog *dialog;
EHTMLEditor *editor;
- EHTMLEditorView *view;
- EHTMLEditorSelection *selection;
- GdkRGBA rgba;
+ EContentEditor *cnt_editor;
+ GdkRGBA *rgba;
dialog = E_HTML_EDITOR_TEXT_DIALOG (widget);
editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
- view = e_html_editor_get_view (editor);
- selection = e_html_editor_view_get_selection (view);
+ cnt_editor = e_html_editor_get_content_editor (editor);
gtk_toggle_button_set_active (
GTK_TOGGLE_BUTTON (dialog->priv->bold_check),
- e_html_editor_selection_is_bold (selection));
+ e_content_editor_is_bold (cnt_editor));
gtk_toggle_button_set_active (
GTK_TOGGLE_BUTTON (dialog->priv->italic_check),
- e_html_editor_selection_is_italic (selection));
+ e_content_editor_is_italic (cnt_editor));
gtk_toggle_button_set_active (
GTK_TOGGLE_BUTTON (dialog->priv->underline_check),
- e_html_editor_selection_is_underline (selection));
+ e_content_editor_is_underline (cnt_editor));
gtk_toggle_button_set_active (
GTK_TOGGLE_BUTTON (dialog->priv->strikethrough_check),
- e_html_editor_selection_is_strikethrough (selection));
+ e_content_editor_is_strikethrough (cnt_editor));
gtk_combo_box_set_active (
GTK_COMBO_BOX (dialog->priv->size_check),
- e_html_editor_selection_get_font_size (selection) - 1);
-
- e_html_editor_selection_get_font_color (selection, &rgba);
- e_color_combo_set_current_color (
- E_COLOR_COMBO (dialog->priv->color_check), &rgba);
+ e_content_editor_get_font_size (cnt_editor) - 1);
+
+ rgba = e_content_editor_dup_font_color (cnt_editor);
+ if (rgba) {
+ e_color_combo_set_current_color (
+ E_COLOR_COMBO (dialog->priv->color_check), rgba);
+ gdk_rgba_free (rgba);
+ }
GTK_WIDGET_CLASS (e_html_editor_text_dialog_parent_class)->show (widget);
}
diff --git a/e-util/e-html-editor.c b/e-util/e-html-editor.c
index 90c8069..bb6af69 100644
--- a/e-util/e-html-editor.c
+++ b/e-util/e-html-editor.c
@@ -32,8 +32,9 @@
#include "e-alert-dialog.h"
#include "e-alert-sink.h"
#include "e-html-editor-private.h"
-#include "e-html-editor-utils.h"
-#include "e-html-editor-selection.h"
+#include "e-content-editor.h"
+#include "e-misc-utils.h"
+#include "e-simple-async-result.h"
#define E_HTML_EDITOR_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE \
@@ -42,8 +43,8 @@
/**
* EHTMLEditor:
*
- * #EHTMLEditor provides GUI for manipulating with properties of #EHTMLEditorView and
- * its #EHTMLEditorSelection - i.e. toolbars and actions.
+ * #EHTMLEditor provides GUI for manipulating with properties of
+ * #EContentEditor i.e. toolbars and actions.
*/
/* This controls how spelling suggestions are divided between the primary
@@ -88,6 +89,8 @@ G_DEFINE_TYPE_WITH_CODE (
e_html_editor,
GTK_TYPE_GRID,
G_IMPLEMENT_INTERFACE (
+ E_TYPE_EXTENSIBLE, NULL)
+ G_IMPLEMENT_INTERFACE (
E_TYPE_ALERT_SINK,
e_html_editor_alert_sink_init))
@@ -97,25 +100,21 @@ static void
action_context_spell_suggest_cb (GtkAction *action,
EHTMLEditor *editor)
{
- EHTMLEditorView *view;
- EHTMLEditorSelection *selection;
+ EContentEditor *cnt_editor;
const gchar *word;
word = g_object_get_data (G_OBJECT (action), "word");
g_return_if_fail (word != NULL);
- view = e_html_editor_get_view (editor);
- selection = e_html_editor_view_get_selection (view);
-
- e_html_editor_selection_replace_caret_word (selection, word);
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ e_content_editor_replace_caret_word (cnt_editor, word);
}
static void
html_editor_inline_spelling_suggestions (EHTMLEditor *editor)
{
- EHTMLEditorView *view;
- EHTMLEditorSelection *selection;
- WebKitSpellChecker *checker;
+ EContentEditor *cnt_editor;
+ ESpellChecker *spell_checker;
GtkActionGroup *action_group;
GtkUIManager *manager;
gchar **suggestions;
@@ -127,15 +126,13 @@ html_editor_inline_spelling_suggestions (EHTMLEditor *editor)
guint threshold;
gint ii;
- view = e_html_editor_get_view (editor);
- selection = e_html_editor_view_get_selection (view);
- checker = WEBKIT_SPELL_CHECKER (webkit_get_text_checker ());
-
- word = e_html_editor_selection_get_caret_word (selection);
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ word = e_content_editor_get_caret_word (cnt_editor);
if (word == NULL || *word == '\0')
return;
- suggestions = webkit_spell_checker_get_guesses_for_word (checker, word, NULL);
+ spell_checker = e_content_editor_ref_spell_checker (cnt_editor);
+ suggestions = e_spell_checker_get_guesses_for_word (spell_checker, word);
path = "/context-menu/context-spell-suggest/";
manager = e_html_editor_get_ui_manager (editor);
@@ -205,6 +202,7 @@ html_editor_inline_spelling_suggestions (EHTMLEditor *editor)
g_free (word);
g_strfreev (suggestions);
+ g_clear_object (&spell_checker);
}
/* Helper for html_editor_update_actions() */
@@ -212,10 +210,9 @@ static void
html_editor_spell_checkers_foreach (EHTMLEditor *editor,
const gchar *language_code)
{
- EHTMLEditorView *view;
- EHTMLEditorSelection *selection;
+ EContentEditor *cnt_editor;
ESpellChecker *spell_checker;
- ESpellDictionary *dictionary;
+ ESpellDictionary *dictionary = NULL;
GtkActionGroup *action_group;
GtkUIManager *manager;
GList *list, *link;
@@ -224,14 +221,13 @@ html_editor_spell_checkers_foreach (EHTMLEditor *editor,
gint ii = 0;
guint merge_id;
- view = e_html_editor_get_view (editor);
- selection = e_html_editor_view_get_selection (view);
- spell_checker = e_html_editor_view_get_spell_checker (view);
-
- word = e_html_editor_selection_get_caret_word (selection);
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ word = e_content_editor_get_caret_word (cnt_editor);
if (word == NULL || *word == '\0')
return;
+ spell_checker = e_content_editor_ref_spell_checker (cnt_editor);
+
dictionary = e_spell_checker_ref_dictionary (
spell_checker, language_code);
if (dictionary != NULL) {
@@ -298,7 +294,7 @@ html_editor_spell_checkers_foreach (EHTMLEditor *editor,
}
g_list_free_full (list, (GDestroyNotify) g_free);
-
+ g_clear_object (&spell_checker);
g_free (path);
g_free (word);
}
@@ -306,124 +302,100 @@ html_editor_spell_checkers_foreach (EHTMLEditor *editor,
void
e_html_editor_update_spell_actions (EHTMLEditor *editor)
{
- ESpellChecker *checker;
- EHTMLEditorView *view;
+ ESpellChecker *spell_checker;
+ EContentEditor *cnt_editor;
guint count;
- view = e_html_editor_get_view (editor);
- checker = e_html_editor_view_get_spell_checker (view);
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ spell_checker = e_content_editor_ref_spell_checker (cnt_editor);
- count = e_spell_checker_count_active_languages (checker);
+ count = e_spell_checker_count_active_languages (spell_checker);
gtk_action_set_visible (ACTION (CONTEXT_SPELL_ADD), count == 1);
gtk_action_set_visible (ACTION (CONTEXT_SPELL_ADD_MENU), count > 1);
gtk_action_set_visible (ACTION (CONTEXT_SPELL_IGNORE), count > 0);
- gtk_action_set_visible (ACTION (SPELL_CHECK), count > 0);
- gtk_action_set_visible (ACTION (LANGUAGE_MENU), count > 0);
+ gtk_action_set_sensitive (ACTION (SPELL_CHECK), count > 0);
+ gtk_action_set_sensitive (ACTION (LANGUAGE_MENU), e_spell_checker_count_available_dicts
(spell_checker) > 0);
+
+ g_clear_object (&spell_checker);
}
static void
-html_editor_update_actions (EHTMLEditor *editor,
- GdkEventButton *event)
+action_set_visible_and_sensitive (GtkAction *action,
+ gboolean value)
{
- WebKitWebView *web_view;
- WebKitSpellChecker *checker;
- WebKitHitTestResult *hit_test;
- WebKitHitTestResultContext context;
- WebKitDOMNode *node;
- EHTMLEditorSelection *selection;
- EHTMLEditorView *view;
+ gtk_action_set_visible (action, value);
+ gtk_action_set_sensitive (action, value);
+}
+
+static void
+html_editor_update_actions (EHTMLEditor *editor)
+{
+ EContentEditor *cnt_editor;
+ EContentEditorNodeFlags flags = editor->priv->node_flags;
ESpellChecker *spell_checker;
GtkUIManager *manager;
GtkActionGroup *action_group;
GList *list;
- gchar **languages;
+ gchar **languages = NULL;
guint ii, n_languages;
gboolean visible;
guint merge_id;
- gint loc, len;
- view = e_html_editor_get_view (editor);
- selection = e_html_editor_view_get_selection (view);
- spell_checker = e_html_editor_view_get_spell_checker (view);
+ cnt_editor = e_html_editor_get_content_editor (editor);
- web_view = WEBKIT_WEB_VIEW (view);
- manager = e_html_editor_get_ui_manager (editor);
+ if (camel_debug ("wex"))
+ printf ("%s: flags:%d(%x)\n", G_STRFUNC, flags, flags);
- g_clear_object (&editor->priv->table_cell);
- g_clear_object (&editor->priv->image);
- g_clear_object (&editor->priv->current_node);
-
- /* Update context menu item visibility. */
- hit_test = webkit_web_view_get_hit_test_result (web_view, event);
- g_object_get (
- G_OBJECT (hit_test),
- "context", &context,
- "inner-node", &node, NULL);
- g_object_unref (hit_test);
-
- editor->priv->current_node = g_object_ref (node);
- visible = (context & WEBKIT_HIT_TEST_RESULT_CONTEXT_IMAGE);
- gtk_action_set_visible (ACTION (CONTEXT_PROPERTIES_IMAGE), visible);
- if (visible)
- editor->priv->image = g_object_ref (node);
+ visible = (flags & E_CONTENT_EDITOR_NODE_IS_IMAGE);
+ action_set_visible_and_sensitive (ACTION (CONTEXT_PROPERTIES_IMAGE), visible);
- visible = (context & WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK);
- if (visible) {
- g_object_unref (editor->priv->current_node);
- editor->priv->current_node = webkit_dom_node_get_parent_node (node);
- gtk_action_set_visible (ACTION (CONTEXT_INSERT_LINK), FALSE);
- }
- gtk_action_set_visible (ACTION (CONTEXT_PROPERTIES_LINK), visible);
+ visible = (flags & E_CONTENT_EDITOR_NODE_IS_ANCHOR);
+ if (visible)
+ action_set_visible_and_sensitive (ACTION (CONTEXT_INSERT_LINK), visible);
+ action_set_visible_and_sensitive (ACTION (CONTEXT_PROPERTIES_LINK), visible);
- visible = (WEBKIT_DOM_IS_HTMLHR_ELEMENT (node));
- gtk_action_set_visible (ACTION (CONTEXT_PROPERTIES_RULE), visible);
+ visible = (flags & E_CONTENT_EDITOR_NODE_IS_H_RULE);
+ action_set_visible_and_sensitive (ACTION (CONTEXT_PROPERTIES_RULE), visible);
- visible = (WEBKIT_DOM_IS_TEXT (node));
+ visible = (flags & E_CONTENT_EDITOR_NODE_IS_TEXT);
/* Only display the text properties dialog when some text is selected. */
- gtk_action_set_visible (
+ action_set_visible_and_sensitive (
ACTION (CONTEXT_PROPERTIES_TEXT),
- visible && !e_html_editor_selection_is_collapsed (selection));
+ visible && !(flags & E_CONTENT_EDITOR_NODE_IS_TEXT_COLLAPSED));
visible =
gtk_action_get_visible (ACTION (CONTEXT_PROPERTIES_IMAGE)) ||
gtk_action_get_visible (ACTION (CONTEXT_PROPERTIES_LINK)) ||
visible; /* text node under caret */
- gtk_action_set_visible (ACTION (CONTEXT_PROPERTIES_PARAGRAPH), visible);
+ action_set_visible_and_sensitive (ACTION (CONTEXT_PROPERTIES_PARAGRAPH), visible);
/* Set to visible if any of these are true:
* - Selection is active and contains a link.
* - Cursor is on a link.
* - Cursor is on an image that has a URL or target.
*/
- visible = (WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (node) ||
- (e_html_editor_dom_node_find_parent_element (node, "A") != NULL));
- gtk_action_set_visible (ACTION (CONTEXT_REMOVE_LINK), visible);
-
- visible = (WEBKIT_DOM_IS_HTML_TABLE_CELL_ELEMENT (node) ||
- (e_html_editor_dom_node_find_parent_element (node, "TD") != NULL) ||
- (e_html_editor_dom_node_find_parent_element (node, "TH") != NULL));
- gtk_action_set_visible (ACTION (CONTEXT_DELETE_CELL), visible);
- gtk_action_set_visible (ACTION (CONTEXT_DELETE_COLUMN), visible);
- gtk_action_set_visible (ACTION (CONTEXT_DELETE_ROW), visible);
- gtk_action_set_visible (ACTION (CONTEXT_DELETE_TABLE), visible);
- gtk_action_set_visible (ACTION (CONTEXT_INSERT_COLUMN_AFTER), visible);
- gtk_action_set_visible (ACTION (CONTEXT_INSERT_COLUMN_BEFORE), visible);
- gtk_action_set_visible (ACTION (CONTEXT_INSERT_ROW_ABOVE), visible);
- gtk_action_set_visible (ACTION (CONTEXT_INSERT_ROW_BELOW), visible);
- gtk_action_set_visible (ACTION (CONTEXT_INSERT_TABLE), visible);
- gtk_action_set_visible (ACTION (CONTEXT_PROPERTIES_CELL), visible);
- if (visible)
- editor->priv->table_cell = g_object_ref (node);
-
- /* Note the |= (cursor must be in a table cell). */
- visible |= (WEBKIT_DOM_IS_HTML_TABLE_ELEMENT (node) ||
- (e_html_editor_dom_node_find_parent_element (node, "TABLE") != NULL));
- gtk_action_set_visible (ACTION (CONTEXT_PROPERTIES_TABLE), visible);
+ visible = (flags & E_CONTENT_EDITOR_NODE_IS_ANCHOR);
+ action_set_visible_and_sensitive (ACTION (CONTEXT_REMOVE_LINK), visible);
+
+ visible = (flags & E_CONTENT_EDITOR_NODE_IS_TABLE_CELL);
+ action_set_visible_and_sensitive (ACTION (CONTEXT_DELETE_CELL), visible);
+ action_set_visible_and_sensitive (ACTION (CONTEXT_DELETE_COLUMN), visible);
+ action_set_visible_and_sensitive (ACTION (CONTEXT_DELETE_ROW), visible);
+ action_set_visible_and_sensitive (ACTION (CONTEXT_DELETE_TABLE), visible);
+ action_set_visible_and_sensitive (ACTION (CONTEXT_INSERT_COLUMN_AFTER), visible);
+ action_set_visible_and_sensitive (ACTION (CONTEXT_INSERT_COLUMN_BEFORE), visible);
+ action_set_visible_and_sensitive (ACTION (CONTEXT_INSERT_ROW_ABOVE), visible);
+ action_set_visible_and_sensitive (ACTION (CONTEXT_INSERT_ROW_BELOW), visible);
+ action_set_visible_and_sensitive (ACTION (CONTEXT_PROPERTIES_CELL), visible);
+
+ visible = (flags & E_CONTENT_EDITOR_NODE_IS_TABLE);
+ action_set_visible_and_sensitive (ACTION (CONTEXT_PROPERTIES_TABLE), visible);
/********************** Spell Check Suggestions **********************/
+ manager = e_html_editor_get_ui_manager (editor);
action_group = editor->priv->suggestion_actions;
/* Remove the old content from the context menu. */
@@ -442,18 +414,16 @@ html_editor_update_actions (EHTMLEditor *editor,
list = g_list_delete_link (list, list);
}
+ spell_checker = e_content_editor_ref_spell_checker (cnt_editor);
languages = e_spell_checker_list_active_languages (
spell_checker, &n_languages);
/* Decide if we should show spell checking items. */
- checker = WEBKIT_SPELL_CHECKER (webkit_get_text_checker ());
visible = FALSE;
if (n_languages > 0) {
- gchar *word = e_html_editor_selection_get_caret_word (selection);
+ gchar *word = e_content_editor_get_caret_word (cnt_editor);
if (word && *word) {
- webkit_spell_checker_check_spelling_of_string (
- checker, word, &loc, &len);
- visible = (loc > -1);
+ visible = !e_spell_checker_check_word (spell_checker, word, -1);
} else {
visible = FALSE;
}
@@ -463,6 +433,8 @@ html_editor_update_actions (EHTMLEditor *editor,
action_group = editor->priv->spell_check_actions;
gtk_action_group_set_visible (action_group, visible);
+ g_clear_object (&spell_checker);
+
/* Exit early if spell checking items are invisible. */
if (!visible) {
g_strfreev (languages);
@@ -493,64 +465,60 @@ html_editor_update_actions (EHTMLEditor *editor,
static void
html_editor_spell_languages_changed (EHTMLEditor *editor)
{
- EHTMLEditorView *view;
+ EContentEditor *cnt_editor;
ESpellChecker *spell_checker;
- WebKitWebSettings *settings;
- gchar *comma_separated;
gchar **languages;
- view = e_html_editor_get_view (editor);
- spell_checker = e_html_editor_view_get_spell_checker (view);
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ spell_checker = e_content_editor_ref_spell_checker (cnt_editor);
languages = e_spell_checker_list_active_languages (spell_checker, NULL);
- comma_separated = g_strjoinv (",", languages);
- g_strfreev (languages);
/* Set the languages for webview to highlight misspelled words */
- settings = webkit_web_view_get_settings (
- WEBKIT_WEB_VIEW (editor->priv->html_editor_view));
-
- g_object_set (
- G_OBJECT (settings),
- "spell-checking-languages", comma_separated,
- NULL);
+ e_content_editor_set_spell_checking_languages (cnt_editor, (const gchar **) languages);
if (editor->priv->spell_check_dialog != NULL)
e_html_editor_spell_check_dialog_update_dictionaries (
E_HTML_EDITOR_SPELL_CHECK_DIALOG (
editor->priv->spell_check_dialog));
- if (*comma_separated)
- e_html_editor_view_force_spell_check (editor->priv->html_editor_view);
- else
- e_html_editor_view_turn_spell_check_off (editor->priv->html_editor_view);
+ e_content_editor_set_spell_check_enabled (cnt_editor, languages && *languages);
- g_free (comma_separated);
+ g_clear_object (&spell_checker);
+ g_strfreev (languages);
}
static gboolean
-html_editor_show_popup (EHTMLEditor *editor,
- GdkEventButton *event,
- gpointer user_data)
+html_editor_context_menu_requested_cb (EContentEditor *cnt_editor,
+ EContentEditorNodeFlags flags,
+ GdkEvent *event,
+ EHTMLEditor *editor)
{
GtkWidget *menu;
+ /* COUNT FLAGS */
menu = e_html_editor_get_managed_widget (editor, "/context-menu");
- g_signal_emit (editor, signals[UPDATE_ACTIONS], 0, event);
+ editor->priv->node_flags = flags;
+ g_signal_emit (editor, signals[UPDATE_ACTIONS], 0, flags);
if (!gtk_menu_get_attach_widget (GTK_MENU (menu)))
gtk_menu_attach_to_widget (GTK_MENU (menu),
GTK_WIDGET (editor),
NULL);
- if (event != NULL)
+
+ if (event)
gtk_menu_popup (
GTK_MENU (menu), NULL, NULL, NULL,
- user_data, event->button, event->time);
+ GTK_WIDGET (cnt_editor),
+ ((GdkEventButton*) event)->button,
+ ((GdkEventButton*) event)->time);
else
gtk_menu_popup (
GTK_MENU (menu), NULL, NULL, NULL,
- user_data, 0, gtk_get_current_event_time ());
+ GTK_WIDGET (cnt_editor),
+ 0,
+ gtk_get_current_event_time ());
return TRUE;
}
@@ -635,7 +603,6 @@ html_editor_constructed (GObject *object)
{
EHTMLEditor *editor = E_HTML_EDITOR (object);
EHTMLEditorPrivate *priv = editor->priv;
- GtkIMMulticontext *im_context;
GtkWidget *widget;
GtkToolbar *toolbar;
GtkToolItem *tool_item;
@@ -643,6 +610,17 @@ html_editor_constructed (GObject *object)
/* Chain up to parent's method. */
G_OBJECT_CLASS (e_html_editor_parent_class)->constructed (object);
+ e_extensible_load_extensions (E_EXTENSIBLE (object));
+
+ editor_actions_init (editor);
+ priv->editor_layout_row = 2;
+
+ /* Tweak the main-toolbar style. */
+ widget = e_html_editor_get_managed_widget (editor, "/main-toolbar");
+ gtk_style_context_add_class (
+ gtk_widget_get_style_context (widget),
+ GTK_STYLE_CLASS_PRIMARY_TOOLBAR);
+
/* Construct the editing toolbars. */
widget = e_html_editor_get_managed_widget (editor, "/edit-toolbar");
@@ -675,25 +653,29 @@ html_editor_constructed (GObject *object)
/* EAlertBar controls its own visibility. */
/* Construct the main editing area. */
+ widget = GTK_WIDGET (e_html_editor_get_content_editor (editor));
- widget = gtk_scrolled_window_new (NULL, NULL);
- gtk_scrolled_window_set_policy (
- GTK_SCROLLED_WINDOW (widget),
- GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
- gtk_scrolled_window_set_shadow_type (
- GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
- gtk_widget_set_hexpand (widget, TRUE);
- gtk_widget_set_vexpand (widget, TRUE);
- gtk_grid_attach (GTK_GRID (editor), widget, 0, 4, 1, 1);
- priv->scrolled_window = g_object_ref (widget);
- gtk_widget_show (widget);
+ /* Pack editors which implement GtkScrollable in a scrolled window */
+ if (GTK_IS_SCROLLABLE (widget)) {
+ GtkWidget *scrolled_window;
+
+ scrolled_window = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_widget_show (scrolled_window);
+
+ gtk_grid_attach (GTK_GRID (editor), scrolled_window, 0, 4, 1, 1);
+
+ gtk_container_add (GTK_CONTAINER (scrolled_window), widget);
+ } else {
+ gtk_grid_attach (GTK_GRID (editor), widget, 0, 4, 1, 1);
+ }
- widget = GTK_WIDGET (e_html_editor_get_view (editor));
- gtk_container_add (GTK_CONTAINER (priv->scrolled_window), widget);
gtk_widget_show (widget);
- g_signal_connect_swapped (
- widget, "popup-event",
- G_CALLBACK (html_editor_show_popup), editor);
+
+ g_signal_connect (
+ widget, "context-menu-requested",
+ G_CALLBACK (html_editor_context_menu_requested_cb), editor);
/* Add some combo boxes to the "edit" toolbar. */
@@ -734,14 +716,6 @@ html_editor_constructed (GObject *object)
gtk_toolbar_insert (toolbar, tool_item, 0);
priv->color_combo_box = g_object_ref (widget);
gtk_widget_show_all (GTK_WIDGET (tool_item));
- e_binding_bind_property (
- priv->color_combo_box, "current-color",
- priv->selection, "font-color",
- G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
- e_binding_bind_property (
- priv->html_editor_view, "editable",
- priv->color_combo_box, "sensitive",
- G_BINDING_SYNC_CREATE);
tool_item = gtk_tool_item_new ();
widget = e_action_combo_box_new_with_action (
@@ -752,16 +726,6 @@ html_editor_constructed (GObject *object)
gtk_toolbar_insert (toolbar, tool_item, 0);
priv->size_combo_box = g_object_ref (widget);
gtk_widget_show_all (GTK_WIDGET (tool_item));
-
- /* Add input methods to the context menu. */
- widget = e_html_editor_get_managed_widget (
- editor, "/context-menu/context-input-methods-menu");
- widget = gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget));
- g_object_get (
- G_OBJECT (priv->html_editor_view), "im-context", &im_context, NULL);
- gtk_im_multicontext_append_menuitems (
- GTK_IM_MULTICONTEXT (im_context),
- GTK_MENU_SHELL (widget));
}
static void
@@ -793,19 +757,23 @@ html_editor_dispose (GObject *object)
g_clear_object (&priv->mode_combo_box);
g_clear_object (&priv->size_combo_box);
g_clear_object (&priv->style_combo_box);
- g_clear_object (&priv->scrolled_window);
-
- g_clear_object (&priv->table_cell);
- g_clear_object (&priv->current_node);
- g_clear_object (&priv->image);
-
- g_clear_object (&priv->html_editor_view);
/* Chain up to parent's dispose() method. */
G_OBJECT_CLASS (e_html_editor_parent_class)->dispose (object);
}
static void
+html_editor_finalize (GObject *object)
+{
+ EHTMLEditor *editor = E_HTML_EDITOR (object);
+
+ g_hash_table_destroy (editor->priv->content_editors);
+
+ /* Chain up to parent's method. */
+ G_OBJECT_CLASS (e_html_editor_parent_class)->finalize (object);
+}
+
+static void
html_editor_submit_alert (EAlertSink *alert_sink,
EAlert *alert)
{
@@ -851,6 +819,7 @@ e_html_editor_class_init (EHTMLEditorClass *class)
object_class->get_property = html_editor_get_property;
object_class->constructed = html_editor_constructed;
object_class->dispose = html_editor_dispose;
+ object_class->finalize = html_editor_finalize;
widget_class = GTK_WIDGET_CLASS (class);
widget_class->parent_set = html_editor_parent_changed;
@@ -877,7 +846,7 @@ e_html_editor_class_init (EHTMLEditorClass *class)
NULL, NULL,
g_cclosure_marshal_VOID__BOXED,
G_TYPE_NONE, 1,
- GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
+ G_TYPE_UINT);
signals[SPELL_LANGUAGES_CHANGED] = g_signal_new (
"spell-languages-changed",
@@ -899,7 +868,6 @@ static void
e_html_editor_init (EHTMLEditor *editor)
{
EHTMLEditorPrivate *priv;
- GtkWidget *widget;
gchar *filename;
GError *error = NULL;
@@ -916,8 +884,7 @@ e_html_editor_init (EHTMLEditor *editor)
priv->language_actions = gtk_action_group_new ("language");
priv->spell_check_actions = gtk_action_group_new ("spell-check");
priv->suggestion_actions = gtk_action_group_new ("suggestion");
- priv->html_editor_view = g_object_ref_sink (e_html_editor_view_new ());
- priv->selection = e_html_editor_view_get_selection (priv->html_editor_view);
+ priv->content_editors = g_hash_table_new_full (camel_strcase_hash, camel_strcase_equal, g_free, NULL);
filename = html_editor_find_ui_file ("e-html-editor-manager.ui");
if (!gtk_ui_manager_add_ui_from_file (priv->manager, filename, &error)) {
@@ -925,42 +892,186 @@ e_html_editor_init (EHTMLEditor *editor)
g_clear_error (&error);
}
g_free (filename);
+}
- editor_actions_init (editor);
- priv->editor_layout_row = 2;
+static void
+e_html_editor_content_editor_initialized (EContentEditor *content_editor,
+ gpointer user_data)
+{
+ ESimpleAsyncResult *async_result = user_data;
+ EHTMLEditor *html_editor;
- /* Tweak the main-toolbar style. */
- widget = e_html_editor_get_managed_widget (editor, "/main-toolbar");
- gtk_style_context_add_class (
- gtk_widget_get_style_context (widget),
- GTK_STYLE_CLASS_PRIMARY_TOOLBAR);
+ g_return_if_fail (E_IS_SIMPLE_ASYNC_RESULT (async_result));
+
+ html_editor = e_simple_async_result_get_user_data (async_result);
+ g_return_if_fail (E_IS_HTML_EDITOR (html_editor));
+ g_return_if_fail (content_editor == e_html_editor_get_content_editor (html_editor));
+
+ e_binding_bind_property (
+ html_editor->priv->color_combo_box, "current-color",
+ content_editor, "font-color",
+ G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
+ e_binding_bind_property (
+ content_editor, "editable",
+ html_editor->priv->color_combo_box, "sensitive",
+ G_BINDING_SYNC_CREATE);
+ editor_actions_bind (html_editor);
+
+ g_object_set (G_OBJECT (content_editor),
+ "halign", GTK_ALIGN_FILL,
+ "hexpand", TRUE,
+ "valign", GTK_ALIGN_FILL,
+ "vexpand", TRUE,
+ "changed", FALSE,
+ NULL);
+
+ e_simple_async_result_complete (async_result);
+
+ g_object_unref (async_result);
}
/**
* e_html_editor_new:
+ * @callback: a callback to be called when the editor is ready
+ * @user_data: a used data passed into the @callback
*
- * Constructs a new #EHTMLEditor.
+ * Constructs a new #EHTMLEditor asynchronously. The result is returned
+ * by e_html_editor_new_finish(), which should be called inside @callback.
*
- * Returns: A newly created widget. [transfer-full]
- */
+ * Since: 3.22
+ **/
+void
+e_html_editor_new (GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ EHTMLEditor *html_editor;
+ EContentEditor *content_editor;
+ ESimpleAsyncResult *async_result;
+
+ g_return_if_fail (callback != NULL);
+
+ html_editor = g_object_new (E_TYPE_HTML_EDITOR, NULL);
+ async_result = e_simple_async_result_new (NULL, callback, user_data, e_html_editor_new);
+ e_simple_async_result_set_user_data (async_result, html_editor, g_object_unref);
+
+ content_editor = e_html_editor_get_content_editor (html_editor);
+ e_content_editor_initialize (content_editor, e_html_editor_content_editor_initialized, async_result);
+}
+
+/**
+ * e_html_editor_new_finish:
+ * @result: a #GAsyncResult passed to callback from e_html_editor_new()
+ * @error: an optional #GError
+ *
+ * Finishes the call of e_html_editor_new().
+ *
+ * Returns: (transfer-full): A newly created #EHTMLEditor.
+ *
+ * Since: 3.22
+ **/
GtkWidget *
-e_html_editor_new (void)
+e_html_editor_new_finish (GAsyncResult *result,
+ GError **error)
{
- return g_object_new (E_TYPE_HTML_EDITOR, NULL);
+ ESimpleAsyncResult *eresult;
+
+ g_return_val_if_fail (E_IS_SIMPLE_ASYNC_RESULT (result), NULL);
+ g_return_val_if_fail (g_async_result_is_tagged (result, e_html_editor_new), NULL);
+
+ eresult = E_SIMPLE_ASYNC_RESULT (result);
+
+ return e_simple_async_result_steal_user_data (eresult);
}
/**
- * e_html_editor_get_view:
+ * e_html_editor_get_content_editor:
* @editor: an #EHTMLEditor
*
- * Returns instance of #EHTMLEditorView used in the @editor.
+ * Returns instance of #EContentEditor used in the @editor.
*/
-EHTMLEditorView *
-e_html_editor_get_view (EHTMLEditor *editor)
+EContentEditor *
+e_html_editor_get_content_editor (EHTMLEditor *editor)
{
g_return_val_if_fail (E_IS_HTML_EDITOR (editor), NULL);
- return editor->priv->html_editor_view;
+ if (!editor->priv->use_content_editor) {
+ GSettings *settings;
+ gchar *name;
+
+ if (!g_hash_table_size (editor->priv->content_editors))
+ return NULL;
+
+ settings = e_util_ref_settings ("org.gnome.evolution.mail");
+ name = g_settings_get_string (settings, "composer-editor");
+ g_clear_object (&settings);
+
+ if (name)
+ editor->priv->use_content_editor = g_hash_table_lookup
(editor->priv->content_editors, name);
+
+ g_free (name);
+
+ if (!editor->priv->use_content_editor)
+ editor->priv->use_content_editor = g_hash_table_lookup
(editor->priv->content_editors, DEFAULT_CONTENT_EDITOR_NAME);
+
+ if (!editor->priv->use_content_editor) {
+ GHashTableIter iter;
+ gpointer key, value;
+
+ g_hash_table_iter_init (&iter, editor->priv->content_editors);
+ if (g_hash_table_iter_next (&iter, &key, &value)) {
+ editor->priv->use_content_editor = value;
+ }
+ }
+
+ if (editor->priv->use_content_editor)
+ e_content_editor_setup_editor (editor->priv->use_content_editor, editor);
+ }
+
+ return editor->priv->use_content_editor;
+}
+
+/* Private function */
+const gchar *
+e_html_editor_get_content_editor_name (EHTMLEditor *editor)
+{
+ EContentEditor *cnt_editor;
+ GHashTableIter iter;
+ gpointer key, value;
+
+ g_return_val_if_fail (E_IS_HTML_EDITOR (editor), NULL);
+
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ if (!cnt_editor)
+ return NULL;
+
+ g_hash_table_iter_init (&iter, editor->priv->content_editors);
+ if (g_hash_table_iter_next (&iter, &key, &value)) {
+ if (value == cnt_editor)
+ return key;
+ }
+
+ return NULL;
+}
+
+void
+e_html_editor_register_content_editor (EHTMLEditor *editor,
+ const gchar *name,
+ EContentEditor *cnt_editor)
+{
+ EContentEditor *already_taken;
+
+ g_return_if_fail (E_IS_HTML_EDITOR (editor));
+ g_return_if_fail (name != NULL);
+ g_return_if_fail (E_IS_CONTENT_EDITOR (cnt_editor));
+
+ already_taken = g_hash_table_lookup (editor->priv->content_editors, name);
+
+ if (already_taken) {
+ g_warning ("%s: Cannot register %s with name '%s', because it's already taken by %s",
+ G_STRFUNC, G_OBJECT_TYPE_NAME (cnt_editor), name, G_OBJECT_TYPE_NAME (already_taken));
+ } else {
+ g_hash_table_insert (editor->priv->content_editors, g_strdup (name), cnt_editor);
+ }
}
/**
@@ -1175,7 +1286,7 @@ e_html_editor_pack_above (EHTMLEditor *editor,
* @as_html: whether the content should be saved as HTML or plain text
* @error:[out] a #GError
*
- * Saves current content of the #EHTMLEditorView into given file. When @as_html
+ * Saves current content of the #EContentEditor into given file. When @as_html
* is @FALSE, the content is first converted into plain text.
*
* Returns: @TRUE when content is succesfully saved, @FALSE otherwise.
@@ -1186,6 +1297,7 @@ e_html_editor_save (EHTMLEditor *editor,
gboolean as_html,
GError **error)
{
+ EContentEditor *cnt_editor;
GFile *file;
GFileOutputStream *stream;
gchar *content;
@@ -1197,12 +1309,20 @@ e_html_editor_save (EHTMLEditor *editor,
if ((error && *error) || !stream)
return FALSE;
+ cnt_editor = e_html_editor_get_content_editor (editor);
+
if (as_html)
- content = e_html_editor_view_get_text_html (
- E_HTML_EDITOR_VIEW (editor), NULL, NULL);
+ content = e_content_editor_get_content (
+ cnt_editor,
+ E_CONTENT_EDITOR_GET_TEXT_HTML |
+ E_CONTENT_EDITOR_GET_PROCESSED,
+ NULL, NULL);
else
- content = e_html_editor_view_get_text_plain (
- E_HTML_EDITOR_VIEW (editor));
+ content = e_content_editor_get_content (
+ cnt_editor,
+ E_CONTENT_EDITOR_GET_TEXT_PLAIN |
+ E_CONTENT_EDITOR_GET_PROCESSED,
+ NULL, NULL);
if (!content || !*content) {
g_set_error (
diff --git a/e-util/e-html-editor.h b/e-util/e-html-editor.h
index c78d33d..e1381da 100644
--- a/e-util/e-html-editor.h
+++ b/e-util/e-html-editor.h
@@ -28,7 +28,7 @@
#include <gtk/gtk.h>
#include <e-util/e-activity.h>
#include <e-util/e-activity-bar.h>
-#include <e-util/e-html-editor-view.h>
+#include <e-util/e-content-editor.h>
/* Standard GObject macros */
#define E_TYPE_HTML_EDITOR \
@@ -63,16 +63,24 @@ struct _EHTMLEditor {
struct _EHTMLEditorClass {
GtkGridClass parent_class;
- void (*update_actions) (EHTMLEditor *editor,
- GdkEventButton *event);
+ void (*update_actions) (EHTMLEditor *editor);
+
void (*spell_languages_changed)
(EHTMLEditor *editor);
};
GType e_html_editor_get_type (void) G_GNUC_CONST;
-GtkWidget * e_html_editor_new (void);
-EHTMLEditorView *
- e_html_editor_get_view (EHTMLEditor *editor);
+void e_html_editor_new (GAsyncReadyCallback callback,
+ gpointer user_data);
+GtkWidget * e_html_editor_new_finish (GAsyncResult *result,
+ GError **error);
+EContentEditor *
+ e_html_editor_get_content_editor
+ (EHTMLEditor *editor);
+void e_html_editor_register_content_editor
+ (EHTMLEditor *editor,
+ const gchar *name,
+ EContentEditor *cnt_editor);
GtkBuilder * e_html_editor_get_builder (EHTMLEditor *editor);
GtkUIManager * e_html_editor_get_ui_manager (EHTMLEditor *editor);
GtkAction * e_html_editor_get_action (EHTMLEditor *editor,
diff --git a/e-util/e-mail-signature-editor.c b/e-util/e-mail-signature-editor.c
index ae67296..45c5f7a 100644
--- a/e-util/e-mail-signature-editor.c
+++ b/e-util/e-mail-signature-editor.c
@@ -24,6 +24,7 @@
#include "e-alert-dialog.h"
#include "e-alert-sink.h"
#include "e-alert-bar.h"
+#include "e-simple-async-result.h"
#define E_MAIL_SIGNATURE_EDITOR_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE \
@@ -101,7 +102,7 @@ mail_signature_editor_loaded_cb (GObject *object,
gpointer user_data)
{
EHTMLEditor *editor;
- EHTMLEditorView *view;
+ EContentEditor *cnt_editor;
ESource *source;
EMailSignatureEditor *window;
ESourceMailSignature *extension;
@@ -144,17 +145,24 @@ mail_signature_editor_loaded_cb (GObject *object,
is_html = (g_strcmp0 (mime_type, "text/html") == 0);
editor = e_mail_signature_editor_get_editor (window);
- view = e_html_editor_get_view (editor);
- e_html_editor_view_set_html_mode (view, is_html);
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ e_content_editor_set_html_mode (cnt_editor, is_html);
if (is_html) {
- if (strstr (contents, "data-evo-signature-plain-text-mode")) {
- e_html_editor_view_set_html_mode (view, FALSE);
- e_html_editor_view_set_is_message_from_draft (view, TRUE);
- }
- e_html_editor_view_set_text_html (view, contents);
+ if (strstr (contents, "data-evo-signature-plain-text-mode"))
+ e_content_editor_set_html_mode (cnt_editor, FALSE);
+
+ e_content_editor_insert_content (
+ cnt_editor,
+ contents,
+ E_CONTENT_EDITOR_INSERT_TEXT_HTML |
+ E_CONTENT_EDITOR_INSERT_REPLACE_ALL);
} else
- e_html_editor_view_set_text_plain (view, contents);
+ e_content_editor_insert_content (
+ cnt_editor,
+ contents,
+ E_CONTENT_EDITOR_INSERT_TEXT_PLAIN |
+ E_CONTENT_EDITOR_INSERT_REPLACE_ALL);
g_free (contents);
@@ -180,18 +188,18 @@ action_close_cb (GtkAction *action,
EMailSignatureEditor *window)
{
EHTMLEditor *editor;
- EHTMLEditorView *view;
+ EContentEditor *cnt_editor;
gboolean something_changed = FALSE;
const gchar *original_name;
const gchar *signature_name;
+ editor = e_mail_signature_editor_get_editor (window);
+ cnt_editor = e_html_editor_get_content_editor (editor);
+
original_name = window->priv->original_name;
signature_name = gtk_entry_get_text (GTK_ENTRY (window->priv->entry));
- editor = e_mail_signature_editor_get_editor (window);
- view = e_html_editor_get_view (editor);
-
- something_changed |= e_html_editor_view_can_undo (view);
+ something_changed |= e_content_editor_can_undo (cnt_editor);
something_changed |= (strcmp (signature_name, original_name) != 0);
if (something_changed) {
@@ -202,6 +210,7 @@ action_close_cb (GtkAction *action,
"widgets:ask-signature-changed", NULL);
if (response == GTK_RESPONSE_YES) {
GtkActionGroup *action_group;
+ GtkAction *action;
action_group = window->priv->action_group;
action = gtk_action_group_get_action (
@@ -317,6 +326,16 @@ static GtkActionEntry entries[] = {
};
static void
+mail_signature_editor_set_editor (EMailSignatureEditor *editor,
+ EHTMLEditor *html_editor)
+{
+ g_return_if_fail (E_IS_HTML_EDITOR (html_editor));
+ g_return_if_fail (editor->priv->editor == NULL);
+
+ editor->priv->editor = g_object_ref (html_editor);
+}
+
+static void
mail_signature_editor_set_registry (EMailSignatureEditor *editor,
ESourceRegistry *registry)
{
@@ -366,6 +385,12 @@ mail_signature_editor_set_property (GObject *object,
GParamSpec *pspec)
{
switch (property_id) {
+ case PROP_EDITOR:
+ mail_signature_editor_set_editor (
+ E_MAIL_SIGNATURE_EDITOR (object),
+ g_value_get_object (value));
+ return;
+
case PROP_REGISTRY:
mail_signature_editor_set_registry (
E_MAIL_SIGNATURE_EDITOR (object),
@@ -485,7 +510,7 @@ mail_signature_editor_constructed (GObject *object)
GtkActionGroup *action_group;
EFocusTracker *focus_tracker;
EHTMLEditor *editor;
- EHTMLEditorView *view;
+ EContentEditor *cnt_editor;
GtkUIManager *ui_manager;
GDBusObject *dbus_object;
ESource *source;
@@ -501,7 +526,7 @@ mail_signature_editor_constructed (GObject *object)
window = E_MAIL_SIGNATURE_EDITOR (object);
editor = e_mail_signature_editor_get_editor (window);
- view = e_html_editor_get_view (editor);
+ cnt_editor = e_html_editor_get_content_editor (editor);
ui_manager = e_html_editor_get_ui_manager (editor);
@@ -612,7 +637,7 @@ mail_signature_editor_constructed (GObject *object)
if (source == NULL) {
gtk_widget_grab_focus (window->priv->entry);
} else {
- gtk_widget_grab_focus (GTK_WIDGET (view));
+ gtk_widget_grab_focus (GTK_WIDGET (cnt_editor));
}
/* Load file content only for an existing signature.
@@ -659,7 +684,8 @@ e_mail_signature_editor_class_init (EMailSignatureEditorClass *class)
NULL,
NULL,
E_TYPE_HTML_EDITOR,
- G_PARAM_READABLE |
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property (
@@ -702,23 +728,95 @@ static void
e_mail_signature_editor_init (EMailSignatureEditor *editor)
{
editor->priv = E_MAIL_SIGNATURE_EDITOR_GET_PRIVATE (editor);
+}
- editor->priv->editor = g_object_ref_sink (e_html_editor_new ());
+typedef struct _CreateEditorData {
+ ESourceRegistry *registry;
+ ESource *source;
+} CreateEditorData;
+
+static void
+create_editor_data_free (gpointer ptr)
+{
+ CreateEditorData *ced = ptr;
+
+ if (ced) {
+ g_clear_object (&ced->registry);
+ g_clear_object (&ced->source);
+ g_free (ced);
+ }
}
-GtkWidget *
+static void
+mail_signature_editor_html_editor_created_cb (GObject *source_object,
+ GAsyncResult *async_result,
+ gpointer user_data)
+{
+ GtkWidget *html_editor, *signature_editor;
+ ESimpleAsyncResult *eresult = user_data;
+ CreateEditorData *ced;
+ GError *error = NULL;
+
+ g_return_if_fail (E_IS_SIMPLE_ASYNC_RESULT (eresult));
+
+ ced = e_simple_async_result_get_user_data (eresult);
+ g_return_if_fail (ced != NULL);
+
+ html_editor = e_html_editor_new_finish (async_result, &error);
+ if (error) {
+ g_warning ("%s: Failed to create HTML editor: %s", G_STRFUNC, error->message);
+ g_clear_error (&error);
+ }
+
+ signature_editor = g_object_new (E_TYPE_MAIL_SIGNATURE_EDITOR,
+ "registry", ced->registry,
+ "source", ced->source,
+ "editor", html_editor,
+ NULL);
+
+ e_simple_async_result_set_op_pointer (eresult, signature_editor);
+
+ e_simple_async_result_complete (eresult);
+
+ g_object_unref (eresult);
+}
+
+void
e_mail_signature_editor_new (ESourceRegistry *registry,
- ESource *source)
+ ESource *source,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
- g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
+ ESimpleAsyncResult *eresult;
+ CreateEditorData *ced;
+
+ g_return_if_fail (E_IS_SOURCE_REGISTRY (registry));
if (source != NULL)
- g_return_val_if_fail (E_IS_SOURCE (source), NULL);
+ g_return_if_fail (E_IS_SOURCE (source));
+
+ ced = g_new0 (CreateEditorData, 1);
+ ced->registry = g_object_ref (registry);
+ ced->source = source ? g_object_ref (source) : NULL;
+
+ eresult = e_simple_async_result_new (NULL, callback, user_data, e_mail_signature_editor_new);
+ e_simple_async_result_set_user_data (eresult, ced, create_editor_data_free);
+
+ e_html_editor_new (mail_signature_editor_html_editor_created_cb, eresult);
+}
+
+GtkWidget *
+e_mail_signature_editor_new_finish (GAsyncResult *result,
+ GError **error)
+{
+ ESimpleAsyncResult *eresult;
+
+ g_return_val_if_fail (E_IS_SIMPLE_ASYNC_RESULT (result), NULL);
+ g_return_val_if_fail (g_async_result_is_tagged (result, e_mail_signature_editor_new), NULL);
+
+ eresult = E_SIMPLE_ASYNC_RESULT (result);
- return g_object_new (
- E_TYPE_MAIL_SIGNATURE_EDITOR,
- "registry", registry,
- "source", source, NULL);
+ return e_simple_async_result_get_op_pointer (eresult);
}
EHTMLEditor *
@@ -825,7 +923,7 @@ e_mail_signature_editor_commit (EMailSignatureEditor *window,
const gchar *mime_type;
gchar *contents;
EHTMLEditor *editor;
- EHTMLEditorView *view;
+ EContentEditor *cnt_editor;
g_return_if_fail (E_IS_MAIL_SIGNATURE_EDITOR (window));
@@ -833,10 +931,14 @@ e_mail_signature_editor_commit (EMailSignatureEditor *window,
source = e_mail_signature_editor_get_source (window);
editor = e_mail_signature_editor_get_editor (window);
- view = e_html_editor_get_view (editor);
+ cnt_editor = e_html_editor_get_content_editor (editor);
mime_type = "text/html";
- contents = e_html_editor_view_get_body_text_html_for_drafts (view);
+ contents = e_content_editor_get_content (
+ cnt_editor,
+ E_CONTENT_EDITOR_GET_TEXT_HTML |
+ E_CONTENT_EDITOR_GET_BODY,
+ NULL, NULL);
extension_name = E_SOURCE_EXTENSION_MAIL_SIGNATURE;
extension = e_source_get_extension (source, extension_name);
diff --git a/e-util/e-mail-signature-editor.h b/e-util/e-mail-signature-editor.h
index 1b8622d..5cb4b72 100644
--- a/e-util/e-mail-signature-editor.h
+++ b/e-util/e-mail-signature-editor.h
@@ -63,8 +63,13 @@ struct _EMailSignatureEditorClass {
GType e_mail_signature_editor_get_type
(void) G_GNUC_CONST;
-GtkWidget * e_mail_signature_editor_new (ESourceRegistry *registry,
- ESource *source);
+void e_mail_signature_editor_new (ESourceRegistry *registry,
+ ESource *source,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+GtkWidget * e_mail_signature_editor_new_finish
+ (GAsyncResult *result,
+ GError **error);
EHTMLEditor * e_mail_signature_editor_get_editor
(EMailSignatureEditor *editor);
EFocusTracker * e_mail_signature_editor_get_focus_tracker
diff --git a/e-util/e-mail-signature-manager.c b/e-util/e-mail-signature-manager.c
index 1ebb9a5..e202039 100644
--- a/e-util/e-mail-signature-manager.c
+++ b/e-util/e-mail-signature-manager.c
@@ -44,6 +44,7 @@ struct _EMailSignatureManagerPrivate {
GtkWidget *edit_button; /* not referenced */
GtkWidget *remove_button; /* not referenced */
GtkWidget *preview; /* not referenced */
+ GtkWidget *preview_frame; /* not referenced */
gboolean prefer_html;
};
@@ -376,13 +377,10 @@ mail_signature_manager_constructed (GObject *object)
container = GTK_WIDGET (manager);
- widget = gtk_scrolled_window_new (NULL, NULL);
- gtk_scrolled_window_set_policy (
- GTK_SCROLLED_WINDOW (widget),
- GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
- gtk_scrolled_window_set_shadow_type (
- GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
+ widget = gtk_frame_new (NULL);
+ gtk_frame_set_shadow_type (GTK_FRAME (widget), GTK_SHADOW_IN);
gtk_paned_pack2 (GTK_PANED (container), widget, FALSE, FALSE);
+ manager->priv->preview_frame = widget; /* not referenced */
gtk_widget_show (widget);
container = widget;
@@ -396,26 +394,46 @@ mail_signature_manager_constructed (GObject *object)
}
static void
-mail_signature_manager_add_signature (EMailSignatureManager *manager)
+mail_signature_manager_editor_created_add_signature_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
{
+ EMailSignatureManager *manager = user_data;
EHTMLEditor *editor;
- EHTMLEditorView *view;
- ESourceRegistry *registry;
+ EContentEditor *cnt_editor;
GtkWidget *widget;
+ GError *error = NULL;
- registry = e_mail_signature_manager_get_registry (manager);
+ g_return_if_fail (E_IS_MAIL_SIGNATURE_MANAGER (manager));
- widget = e_mail_signature_editor_new (registry, NULL);
+ widget = e_mail_signature_editor_new_finish (result, &error);
+ if (error) {
+ g_warning ("%s: Failed to create signature editor: %s", G_STRFUNC, error->message);
+ g_clear_error (&error);
+ g_clear_object (&manager);
+ return;
+ }
- editor = e_mail_signature_editor_get_editor (
- E_MAIL_SIGNATURE_EDITOR (widget));
- view = e_html_editor_get_view (editor);
- e_html_editor_view_set_html_mode (
- view, manager->priv->prefer_html);
+ editor = e_mail_signature_editor_get_editor (E_MAIL_SIGNATURE_EDITOR (widget));
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ e_content_editor_set_html_mode (cnt_editor, manager->priv->prefer_html);
mail_signature_manager_emit_editor_created (manager, widget);
gtk_widget_grab_focus (manager->priv->tree_view);
+
+ g_clear_object (&manager);
+}
+
+static void
+mail_signature_manager_add_signature (EMailSignatureManager *manager)
+{
+ ESourceRegistry *registry;
+
+ registry = e_mail_signature_manager_get_registry (manager);
+
+ e_mail_signature_editor_new (registry, NULL,
+ mail_signature_manager_editor_created_add_signature_cb, g_object_ref (manager));
}
static void
@@ -447,12 +465,35 @@ mail_signature_manager_editor_created (EMailSignatureManager *manager,
}
static void
+mail_signature_manager_editor_created_edit_signature_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ EMailSignatureManager *manager = user_data;
+ GtkWidget *widget;
+ GError *error = NULL;
+
+ g_return_if_fail (E_IS_MAIL_SIGNATURE_MANAGER (manager));
+
+ widget = e_mail_signature_editor_new_finish (result, &error);
+ if (error) {
+ g_warning ("%s: Failed to create signature editor: %s", G_STRFUNC, error->message);
+ g_clear_error (&error);
+ g_clear_object (&manager);
+ return;
+ }
+
+ mail_signature_manager_emit_editor_created (manager, widget);
+
+ g_clear_object (&manager);
+}
+
+static void
mail_signature_manager_edit_signature (EMailSignatureManager *manager)
{
EMailSignatureTreeView *tree_view;
ESourceMailSignature *extension;
ESourceRegistry *registry;
- GtkWidget *editor;
ESource *source;
GFileInfo *file_info;
GFile *file;
@@ -488,8 +529,8 @@ mail_signature_manager_edit_signature (EMailSignatureManager *manager)
if (g_file_info_get_attribute_boolean (file_info, attribute))
goto script;
- editor = e_mail_signature_editor_new (registry, source);
- mail_signature_manager_emit_editor_created (manager, editor);
+ e_mail_signature_editor_new (registry, source,
+ mail_signature_manager_editor_created_edit_signature_cb, g_object_ref (manager));
goto exit;
diff --git a/e-util/e-mail-signature-preview.c b/e-util/e-mail-signature-preview.c
index 32acfb0..d8e4553 100644
--- a/e-util/e-mail-signature-preview.c
+++ b/e-util/e-mail-signature-preview.c
@@ -56,78 +56,6 @@ G_DEFINE_TYPE (
E_TYPE_WEB_VIEW)
static void
-replace_local_image_links (WebKitDOMDocument *document)
-{
- gint ii, length;
- WebKitDOMNodeList *list;
-
- list = webkit_dom_document_query_selector_all (
- document, "img[src^=\"file://\"]", NULL);
- length = webkit_dom_node_list_get_length (list);
-
- for (ii = 0; ii < length; ii++) {
- gchar *src, *new_src;
- WebKitDOMHTMLImageElement *img;
-
- img = WEBKIT_DOM_HTML_IMAGE_ELEMENT (
- webkit_dom_node_list_item (list, ii));
- src = webkit_dom_html_image_element_get_src (img);
-
- /* this forms "evo-file://", which can be loaded,
- * while "file://" cannot be, due to WebKit policy */
- new_src = g_strconcat ("evo-", src, NULL);
- webkit_dom_html_image_element_set_src (img, new_src);
- g_free (new_src);
- g_free (src);
- g_object_unref (img);
- }
- g_object_unref (list);
-
- list = webkit_dom_document_get_elements_by_tag_name ( document, "iframe");
- length = webkit_dom_node_list_get_length (list);
- for (ii = 0; ii < length; ii++) {
- WebKitDOMDocument *content_document;
- WebKitDOMHTMLIFrameElement *iframe;
-
- iframe = WEBKIT_DOM_HTML_IFRAME_ELEMENT (
- webkit_dom_node_list_item (list, ii));
-
- content_document =
- webkit_dom_html_iframe_element_get_content_document (iframe);
-
- if (content_document && WEBKIT_DOM_IS_DOCUMENT (content_document))
- replace_local_image_links (content_document);
- g_object_unref (iframe);
- }
- g_object_unref (list);
-}
-
-static void
-signature_preview_document_loaded_cb (WebKitWebView *web_view,
- WebKitWebFrame *web_frame,
- gpointer user_data)
-{
- WebKitDOMDocument *document;
-
- document = webkit_web_view_get_dom_document (web_view);
- replace_local_image_links (document);
-
- if ((webkit_dom_document_query_selector (
- document, "[data-evo-signature-plain-text-mode]", NULL))) {
-
- WebKitDOMHTMLElement *body;
-
- body = webkit_dom_document_get_body (document);
-
- webkit_dom_element_set_attribute (
- WEBKIT_DOM_ELEMENT (body),
- "style",
- "font-family: Monospace;",
- NULL);
- }
-}
-
-static void
mail_signature_preview_load_cb (ESource *source,
GAsyncResult *result,
EMailSignaturePreview *preview)
@@ -166,16 +94,14 @@ mail_signature_preview_load_cb (ESource *source,
mime_type = e_source_mail_signature_get_mime_type (extension);
if (g_strcmp0 (mime_type, "text/html") == 0) {
- webkit_web_view_load_string (
- WEBKIT_WEB_VIEW (preview), contents,
- "text/html", "UTF-8", "file:///");
+ webkit_web_view_load_html (
+ WEBKIT_WEB_VIEW (preview), contents, "file:///");
} else {
gchar *string;
string = g_markup_printf_escaped ("<pre>%s</pre>", contents);
- webkit_web_view_load_string (
- WEBKIT_WEB_VIEW (preview), string,
- "text/html", "UTF-8", "file:///");
+ webkit_web_view_load_html (
+ WEBKIT_WEB_VIEW (preview), string, "file:///");
g_free (string);
}
@@ -378,10 +304,6 @@ static void
e_mail_signature_preview_init (EMailSignaturePreview *preview)
{
preview->priv = E_MAIL_SIGNATURE_PREVIEW_GET_PRIVATE (preview);
-
- g_signal_connect (
- preview, "document-load-finished",
- G_CALLBACK (signature_preview_document_loaded_cb), NULL);
}
GtkWidget *
diff --git a/e-util/e-marshal.list b/e-util/e-marshal.list
index ee2106f..1ccafed 100644
--- a/e-util/e-marshal.list
+++ b/e-util/e-marshal.list
@@ -1,6 +1,7 @@
BOOLEAN:BOXED
BOOLEAN:BOXED,STRING
BOOLEAN:INT,INT,BOXED
+BOOLEAN:INT,BOXED
BOOLEAN:INT,INT,OBJECT,INT,INT,UINT
BOOLEAN:INT,POINTER,INT,BOXED
BOOLEAN:INT,POINTER,INT,OBJECT,INT,INT,UINT
diff --git a/e-util/e-misc-utils.c b/e-util/e-misc-utils.c
index df04561..3dcc7f0 100644
--- a/e-util/e-misc-utils.c
+++ b/e-util/e-misc-utils.c
@@ -3202,6 +3202,42 @@ e_util_cleanup_settings (void)
g_mutex_unlock (&settings_hash_lock);
}
+static gdouble
+get_screen_dpi (GdkScreen *screen)
+{
+ gdouble dpi;
+ gdouble dp, di;
+
+ dpi = gdk_screen_get_resolution (screen);
+ if (dpi != -1)
+ return dpi;
+
+ dp = hypot (gdk_screen_get_width (screen), gdk_screen_get_height (screen));
+ di = hypot (gdk_screen_get_width_mm (screen), gdk_screen_get_height_mm (screen)) / 25.4;
+
+ return dp / di;
+}
+
+guint
+e_util_normalize_font_size (GtkWidget *widget,
+ gdouble font_size)
+{
+ /* WebKit2 uses font sizes in pixels. */
+ GdkScreen *screen;
+ gdouble dpi;
+
+ if (widget) {
+ screen = gtk_widget_has_screen (widget) ?
+ gtk_widget_get_screen (widget) : gdk_screen_get_default ();
+ } else {
+ screen = gdk_screen_get_default ();
+ }
+
+ dpi = screen ? get_screen_dpi (screen) : 96;
+
+ return font_size / 72.0 * dpi;
+}
+
/**
* e_util_prompt_user:
* @parent: parent window
@@ -3405,6 +3441,22 @@ e_util_set_entry_issue_hint (GtkWidget *entry,
}
}
+static GThread *main_thread = NULL;
+
+void
+e_util_init_main_thread (GThread *thread)
+{
+ g_return_if_fail (main_thread == NULL);
+
+ main_thread = thread ? thread : g_thread_self ();
+}
+
+gboolean
+e_util_is_main_thread (GThread *thread)
+{
+ return thread ? thread == main_thread : g_thread_self () == main_thread;
+}
+
/**
* e_util_save_image_from_clipboard:
* @clipboard: a #GtkClipboard
@@ -3446,7 +3498,7 @@ e_util_save_image_from_clipboard (GtkClipboard *clipboard)
/* Convert the filename to a URI. */
uri = g_filename_to_uri (filename, NULL, &error);
-exit:
+ exit:
if (error != NULL) {
g_warning ("%s", error->message);
g_error_free (error);
diff --git a/e-util/e-misc-utils.h b/e-util/e-misc-utils.h
index bde194a..9afe95c 100644
--- a/e-util/e-misc-utils.h
+++ b/e-util/e-misc-utils.h
@@ -287,9 +287,13 @@ void e_util_run_simple_async_result_in_thread
GSimpleAsyncThreadFunc func,
GCancellable *cancellable);
gboolean e_util_is_running_gnome (void);
-
void e_util_set_entry_issue_hint (GtkWidget *entry,
const gchar *hint);
+
+guint e_util_normalize_font_size (GtkWidget *widget,
+ gdouble font_size);
+void e_util_init_main_thread (GThread *thread);
+gboolean e_util_is_main_thread (GThread *thread);
gchar * e_util_save_image_from_clipboard
(GtkClipboard *clipboard);
diff --git a/e-util/e-search-bar.c b/e-util/e-search-bar.c
index 759956a..b5ebdde 100644
--- a/e-util/e-search-bar.c
+++ b/e-util/e-search-bar.c
@@ -44,9 +44,11 @@ struct _ESearchBarPrivate {
GtkWidget *prev_button;
GtkWidget *next_button;
+ WebKitFindController *find_controller;
+
gchar *active_search;
- guint rerun_search : 1;
+ gboolean search_forward;
};
enum {
@@ -77,7 +79,6 @@ search_bar_update_matches (ESearchBar *search_bar,
GtkWidget *matches_label;
gchar *text;
- search_bar->priv->rerun_search = FALSE;
matches_label = search_bar->priv->matches_label;
text = g_strdup_printf (_("Matches: %u"), matches);
@@ -86,14 +87,88 @@ search_bar_update_matches (ESearchBar *search_bar,
g_free (text);
}
+ static void
+webkit_find_controller_found_text_cb (WebKitFindController *find_controller,
+ guint match_count,
+ ESearchBar *search_bar)
+{
+ GtkWidget *widget;
+ WebKitFindOptions options;
+ gboolean wrapped = FALSE;
+
+ search_bar_update_matches (search_bar, match_count);
+
+ g_free (search_bar->priv->active_search);
+ search_bar->priv->active_search =
+ g_strdup (webkit_find_controller_get_search_text (find_controller));
+
+ gtk_widget_set_sensitive (search_bar->priv->next_button, TRUE);
+ gtk_widget_set_sensitive (search_bar->priv->prev_button, TRUE);
+
+ g_object_notify (G_OBJECT (search_bar), "active-search");
+
+ options = webkit_find_controller_get_options (find_controller);
+
+ if (options & WEBKIT_FIND_OPTIONS_WRAP_AROUND)
+ wrapped = TRUE;
+
+ /* Update wrapped label visibility. */
+ widget = search_bar->priv->wrapped_next_box;
+
+ if (wrapped && search_bar->priv->search_forward)
+ gtk_widget_show (widget);
+ else
+ gtk_widget_hide (widget);
+
+ widget = search_bar->priv->wrapped_prev_box;
+
+ if (wrapped && !search_bar->priv->search_forward)
+ gtk_widget_show (widget);
+ else
+ gtk_widget_hide (widget);
+}
+
static void
-search_bar_update_highlights (ESearchBar *search_bar)
+webkit_find_controller_failed_to_found_text_cb (WebKitFindController *find_controller,
+ ESearchBar *search_bar)
{
- EWebView *web_view;
+ WebKitFindOptions options;
+ GtkWidget *widget;
+
+ options = webkit_find_controller_get_options (find_controller);
+
+ /* If we didn't find anything, try from the beggining with WRAP_AROUND option */
+ if (!(options & WEBKIT_FIND_OPTIONS_WRAP_AROUND)) {
+ webkit_find_controller_search (
+ find_controller,
+ webkit_find_controller_get_search_text (find_controller),
+ options | WEBKIT_FIND_OPTIONS_WRAP_AROUND,
+ G_MAXUINT);
+ }
+
+ search_bar_update_matches (search_bar, 0);
+
+ g_free (search_bar->priv->active_search);
+ search_bar->priv->active_search =
+ g_strdup (webkit_find_controller_get_search_text (find_controller));
- web_view = e_search_bar_get_web_view (search_bar);
+ gtk_widget_set_sensitive (search_bar->priv->next_button, FALSE);
+ gtk_widget_set_sensitive (search_bar->priv->prev_button, FALSE);
- webkit_web_view_unmark_text_matches (WEBKIT_WEB_VIEW (web_view));
+ g_object_notify (G_OBJECT (search_bar), "active-search");
+
+ /* Update wrapped label visibility. */
+ widget = search_bar->priv->wrapped_next_box;
+ gtk_widget_hide (widget);
+
+ widget = search_bar->priv->wrapped_prev_box;
+ gtk_widget_hide (widget);
+}
+
+static void
+search_bar_update_highlights (ESearchBar *search_bar)
+{
+ webkit_find_controller_search_finish (search_bar->priv->find_controller);
e_search_bar_changed (search_bar);
}
@@ -102,15 +177,13 @@ static void
search_bar_find (ESearchBar *search_bar,
gboolean search_forward)
{
- EWebView *web_view;
- GtkWidget *widget;
+ WebKitFindController *find_controller;
gboolean case_sensitive;
- gboolean wrapped = FALSE;
- gboolean success;
gchar *text;
- guint matches;
- web_view = e_search_bar_get_web_view (search_bar);
+ find_controller = search_bar->priv->find_controller;
+ search_bar->priv->search_forward = search_forward;
+
case_sensitive = e_search_bar_get_case_sensitive (search_bar);
text = e_search_bar_get_text (search_bar);
@@ -120,46 +193,14 @@ search_bar_find (ESearchBar *search_bar,
return;
}
- webkit_web_view_unmark_text_matches (
- WEBKIT_WEB_VIEW (web_view));
- matches = webkit_web_view_mark_text_matches (
- WEBKIT_WEB_VIEW (web_view),
- text, case_sensitive, 0);
- webkit_web_view_set_highlight_text_matches (
- WEBKIT_WEB_VIEW (web_view), TRUE);
- search_bar_update_matches (search_bar, matches);
-
- success = webkit_web_view_search_text (
- WEBKIT_WEB_VIEW (web_view),
- text, case_sensitive, search_forward, FALSE);
-
- if (!success)
- wrapped = webkit_web_view_search_text (
- WEBKIT_WEB_VIEW (web_view),
- text, case_sensitive, search_forward, TRUE);
-
- g_free (search_bar->priv->active_search);
- search_bar->priv->active_search = text;
-
- gtk_widget_set_sensitive (search_bar->priv->next_button, matches != 0);
- gtk_widget_set_sensitive (search_bar->priv->prev_button, matches != 0);
-
- g_object_notify (G_OBJECT (search_bar), "active-search");
-
- /* Update wrapped label visibility. */
- widget = search_bar->priv->wrapped_next_box;
-
- if (wrapped && search_forward)
- gtk_widget_show (widget);
- else
- gtk_widget_hide (widget);
-
- widget = search_bar->priv->wrapped_prev_box;
+ webkit_find_controller_search_finish (find_controller);
+ webkit_find_controller_search (
+ find_controller,
+ text,
+ case_sensitive ? WEBKIT_FIND_OPTIONS_NONE : WEBKIT_FIND_OPTIONS_CASE_INSENSITIVE,
+ G_MAXUINT);
- if (wrapped && !search_forward)
- gtk_widget_show (widget);
- else
- gtk_widget_hide (widget);
+ g_free (text);
}
static void
@@ -205,43 +246,48 @@ search_bar_toggled_cb (ESearchBar *search_bar)
}
static void
-web_view_load_status_changed_cb (WebKitWebView *webkit_web_view,
- GParamSpec *pspec,
- gpointer user_data)
+web_view_load_changed_cb (WebKitWebView *webkit_web_view,
+ WebKitLoadEvent load_event,
+ ESearchBar *search_bar)
{
- WebKitLoadStatus status;
- ESearchBar *search_bar;
-
- status = webkit_web_view_get_load_status (webkit_web_view);
- if (status != WEBKIT_LOAD_FINISHED)
- return;
-
- if (!user_data)
+ if (load_event != WEBKIT_LOAD_FINISHED)
return;
- search_bar = E_SEARCH_BAR (user_data);
-
if (gtk_widget_get_visible (GTK_WIDGET (search_bar))) {
if (search_bar->priv->active_search != NULL) {
search_bar_find (search_bar, TRUE);
}
- } else {
+ } else
e_web_view_update_highlights (search_bar->priv->web_view);
- }
}
static void
search_bar_set_web_view (ESearchBar *search_bar,
EWebView *web_view)
{
+ WebKitFindController *find_controller;
+
g_return_if_fail (E_IS_WEB_VIEW (web_view));
g_return_if_fail (search_bar->priv->web_view == NULL);
search_bar->priv->web_view = g_object_ref (web_view);
- e_signal_connect_notify (
- web_view, "notify::load-status",
- G_CALLBACK (web_view_load_status_changed_cb), search_bar);
+ find_controller =
+ webkit_web_view_get_find_controller (WEBKIT_WEB_VIEW (web_view));
+
+ search_bar->priv->find_controller = find_controller;
+
+ g_signal_connect (
+ web_view, "load-changed",
+ G_CALLBACK (web_view_load_changed_cb), search_bar);
+
+ g_signal_connect (
+ find_controller, "found-text",
+ G_CALLBACK (webkit_find_controller_found_text_cb), search_bar);
+
+ g_signal_connect (
+ find_controller, "failed-to-find-text",
+ G_CALLBACK (webkit_find_controller_failed_to_found_text_cb), search_bar);
}
static void
@@ -393,7 +439,6 @@ static void
search_bar_show (GtkWidget *widget)
{
ESearchBar *search_bar;
- EWebView *web_view;
search_bar = E_SEARCH_BAR (widget);
@@ -402,8 +447,7 @@ search_bar_show (GtkWidget *widget)
gtk_widget_grab_focus (search_bar->priv->entry);
- web_view = e_search_bar_get_web_view (search_bar);
- webkit_web_view_unmark_text_matches (WEBKIT_WEB_VIEW (web_view));
+ webkit_find_controller_search_finish (search_bar->priv->find_controller);
search_bar_find (search_bar, TRUE);
}
@@ -442,8 +486,6 @@ search_bar_key_press_event (GtkWidget *widget,
static void
search_bar_clear (ESearchBar *search_bar)
{
- WebKitWebView *web_view;
-
g_free (search_bar->priv->active_search);
search_bar->priv->active_search = NULL;
@@ -455,9 +497,6 @@ search_bar_clear (ESearchBar *search_bar)
search_bar_update_highlights (search_bar);
- web_view = WEBKIT_WEB_VIEW (search_bar->priv->web_view);
- webkit_web_view_unmark_text_matches (web_view);
-
g_object_notify (G_OBJECT (search_bar), "active-search");
}
diff --git a/e-util/e-simple-async-result.c b/e-util/e-simple-async-result.c
new file mode 100644
index 0000000..76e6cf6
--- /dev/null
+++ b/e-util/e-simple-async-result.c
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2016 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library 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.
+ *
+ * This library 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 this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <gio/gio.h>
+
+#include "e-simple-async-result.h"
+
+struct _ESimpleAsyncResultPrivate {
+ GObject *source_object;
+ GAsyncReadyCallback callback;
+ gpointer callback_user_data;
+ gpointer source_tag;
+
+ gpointer user_data;
+ GDestroyNotify destroy_user_data;
+
+ gpointer op_pointer;
+};
+
+static void e_simple_async_result_iface_init (GAsyncResultIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (ESimpleAsyncResult, e_simple_async_result, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_RESULT, e_simple_async_result_iface_init))
+
+static gpointer
+e_simple_async_result_iface_get_user_data (GAsyncResult *result)
+{
+ ESimpleAsyncResult *eresult;
+
+ g_return_val_if_fail (E_IS_SIMPLE_ASYNC_RESULT (result), NULL);
+
+ eresult = E_SIMPLE_ASYNC_RESULT (result);
+
+ return eresult->priv->callback_user_data;
+}
+
+static GObject *
+e_simple_async_result_iface_get_source_object (GAsyncResult *result)
+{
+ ESimpleAsyncResult *eresult;
+
+ g_return_val_if_fail (E_IS_SIMPLE_ASYNC_RESULT (result), NULL);
+
+ eresult = E_SIMPLE_ASYNC_RESULT (result);
+
+ return eresult->priv->source_object;
+}
+
+static gboolean
+e_simple_async_result_iface_is_tagged (GAsyncResult *result,
+ gpointer source_tag)
+{
+ ESimpleAsyncResult *eresult;
+
+ g_return_val_if_fail (E_IS_SIMPLE_ASYNC_RESULT (result), FALSE);
+
+ eresult = E_SIMPLE_ASYNC_RESULT (result);
+
+ return eresult && eresult->priv->source_tag == source_tag;
+}
+
+static void
+e_simple_async_result_iface_init (GAsyncResultIface *iface)
+{
+ iface->get_user_data = e_simple_async_result_iface_get_user_data;
+ iface->get_source_object = e_simple_async_result_iface_get_source_object;
+ iface->is_tagged = e_simple_async_result_iface_is_tagged;
+}
+
+static void
+e_simple_async_result_finalize (GObject *object)
+{
+ ESimpleAsyncResult *result = E_SIMPLE_ASYNC_RESULT (object);
+
+ if (result->priv->user_data && result->priv->destroy_user_data)
+ result->priv->destroy_user_data (result->priv->user_data);
+
+ result->priv->destroy_user_data = NULL;
+ result->priv->user_data = NULL;
+
+ g_clear_object (&result->priv->source_object);
+
+ /* Chain up to parent's method */
+ G_OBJECT_CLASS (e_simple_async_result_parent_class)->finalize (object);
+}
+
+static void
+e_simple_async_result_class_init (ESimpleAsyncResultClass *class)
+{
+ GObjectClass *object_class;
+
+ g_type_class_add_private (class, sizeof (ESimpleAsyncResultPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->finalize = e_simple_async_result_finalize;
+}
+
+static void
+e_simple_async_result_init (ESimpleAsyncResult *result)
+{
+ result->priv = G_TYPE_INSTANCE_GET_PRIVATE (result, E_TYPE_SIMPLE_ASYNC_RESULT,
ESimpleAsyncResultPrivate);
+}
+
+ESimpleAsyncResult *
+e_simple_async_result_new (GObject *source_object,
+ GAsyncReadyCallback callback,
+ gpointer user_data,
+ gpointer source_tag)
+{
+ ESimpleAsyncResult *result;
+
+ g_return_val_if_fail (callback != NULL, NULL);
+ if (source_object)
+ g_return_val_if_fail (G_IS_OBJECT (source_object), NULL);
+
+ result = g_object_new (E_TYPE_SIMPLE_ASYNC_RESULT, NULL);
+
+ result->priv->source_object = source_object ? g_object_ref (source_object) : NULL;
+ result->priv->callback = callback;
+ result->priv->callback_user_data = user_data;
+ result->priv->source_tag = source_tag;
+
+ return result;
+}
+
+void
+e_simple_async_result_set_user_data (ESimpleAsyncResult *result,
+ gpointer user_data,
+ GDestroyNotify destroy_user_data)
+{
+ ESimpleAsyncResult *eresult;
+
+ g_return_if_fail (E_IS_SIMPLE_ASYNC_RESULT (result));
+
+ eresult = E_SIMPLE_ASYNC_RESULT (result);
+
+ if (eresult->priv->user_data == user_data)
+ return;
+
+ if (eresult->priv->user_data && eresult->priv->destroy_user_data)
+ eresult->priv->destroy_user_data (eresult->priv->user_data);
+
+ eresult->priv->user_data = user_data;
+ eresult->priv->destroy_user_data = destroy_user_data;
+}
+
+gpointer
+e_simple_async_result_get_user_data (ESimpleAsyncResult *result)
+{
+ ESimpleAsyncResult *eresult;
+
+ g_return_val_if_fail (E_IS_SIMPLE_ASYNC_RESULT (result), NULL);
+
+ eresult = E_SIMPLE_ASYNC_RESULT (result);
+
+ return eresult->priv->user_data;
+}
+
+gpointer
+e_simple_async_result_steal_user_data (ESimpleAsyncResult *result)
+{
+ ESimpleAsyncResult *eresult;
+ gpointer user_data;
+
+ g_return_val_if_fail (E_IS_SIMPLE_ASYNC_RESULT (result), NULL);
+
+ eresult = E_SIMPLE_ASYNC_RESULT (result);
+
+ user_data = eresult->priv->user_data;
+
+ eresult->priv->user_data = NULL;
+ eresult->priv->destroy_user_data = NULL;
+
+ return user_data;
+}
+
+void
+e_simple_async_result_set_op_pointer (ESimpleAsyncResult *result,
+ gpointer ptr)
+{
+ g_return_if_fail (E_IS_SIMPLE_ASYNC_RESULT (result));
+
+ result->priv->op_pointer = ptr;
+}
+
+gpointer
+e_simple_async_result_get_op_pointer (ESimpleAsyncResult *result)
+{
+ g_return_val_if_fail (E_IS_SIMPLE_ASYNC_RESULT (result), NULL);
+
+ return result->priv->op_pointer;
+}
+
+void
+e_simple_async_result_complete (ESimpleAsyncResult *result)
+{
+ g_return_if_fail (E_IS_SIMPLE_ASYNC_RESULT (result));
+
+ g_object_ref (result);
+
+ result->priv->callback (result->priv->source_object, G_ASYNC_RESULT (result),
result->priv->callback_user_data);
+
+ g_object_unref (result);
+}
diff --git a/e-util/e-simple-async-result.h b/e-util/e-simple-async-result.h
new file mode 100644
index 0000000..3800de1
--- /dev/null
+++ b/e-util/e-simple-async-result.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2016 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library 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.
+ *
+ * This library 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 this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#if !defined (__E_UTIL_H_INSIDE__) && !defined (LIBEUTIL_COMPILATION)
+#error "Only <e-util/e-util.h> should be included directly."
+#endif
+
+#ifndef E_SIMPLE_ASYNC_RESULT_H
+#define E_SIMPLE_ASYNC_RESULT_H
+
+#include <gio/gio.h>
+
+/* Standard GObject macros */
+#define E_TYPE_SIMPLE_ASYNC_RESULT \
+ (e_simple_async_result_get_type ())
+#define E_SIMPLE_ASYNC_RESULT(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_SIMPLE_ASYNC_RESULT, ESimpleAsyncResult))
+#define E_SIMPLE_ASYNC_RESULT_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_SIMPLE_ASYNC_RESULT, ESimpleAsyncResultClass))
+#define E_IS_SIMPLE_ASYNC_RESULT(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_SIMPLE_ASYNC_RESULT))
+#define E_IS_SIMPLE_ASYNC_RESULT_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_SIMPLE_ASYNC_RESULT))
+#define E_SIMPLE_ASYNC_RESULT_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_SIMPLE_ASYNC_RESULT, ESimpleAsyncResultClass))
+
+G_BEGIN_DECLS
+
+typedef struct _ESimpleAsyncResult ESimpleAsyncResult;
+typedef struct _ESimpleAsyncResultClass ESimpleAsyncResultClass;
+typedef struct _ESimpleAsyncResultPrivate ESimpleAsyncResultPrivate;
+
+/**
+ * ESimpleAsyncResult:
+ *
+ * Contains only private data that should be read and manipulated using the
+ * functions below.
+ **/
+struct _ESimpleAsyncResult {
+ GObject parent;
+
+ ESimpleAsyncResultPrivate *priv;
+};
+
+struct _ESimpleAsyncResultClass {
+ GObjectClass parent_class;
+};
+
+GType e_simple_async_result_get_type (void) G_GNUC_CONST;
+ESimpleAsyncResult *
+ e_simple_async_result_new (GObject *source_object,
+ GAsyncReadyCallback callback,
+ gpointer user_data,
+ gpointer source_tag);
+void e_simple_async_result_set_user_data
+ (ESimpleAsyncResult *result,
+ gpointer user_data,
+ GDestroyNotify destroy_user_data);
+gpointer e_simple_async_result_get_user_data
+ (ESimpleAsyncResult *result);
+gpointer e_simple_async_result_steal_user_data
+ (ESimpleAsyncResult *result);
+void e_simple_async_result_set_op_pointer
+ (ESimpleAsyncResult *result,
+ gpointer ptr);
+gpointer e_simple_async_result_get_op_pointer
+ (ESimpleAsyncResult *result);
+void e_simple_async_result_complete (ESimpleAsyncResult *result);
+
+G_END_DECLS
+
+#endif /* E_SIMPLE_ASYNC_RESULT_H */
diff --git a/e-util/e-spell-checker.c b/e-util/e-spell-checker.c
index 6cfccf6..dbdd895 100644
--- a/e-util/e-spell-checker.c
+++ b/e-util/e-spell-checker.c
@@ -24,7 +24,6 @@
#include "e-spell-dictionary.h"
#include <libebackend/libebackend.h>
-#include <webkit/webkitspellchecker.h>
#include <pango/pango.h>
#include <gtk/gtk.h>
#include <string.h>
@@ -45,27 +44,19 @@ enum {
PROP_ACTIVE_LANGUAGES
};
-/* Forward Declarations */
-static void e_spell_checker_init_webkit_checker
- (WebKitSpellCheckerInterface *interface);
-
G_DEFINE_TYPE_EXTENDED (
ESpellChecker,
e_spell_checker,
G_TYPE_OBJECT,
0,
G_IMPLEMENT_INTERFACE (
- E_TYPE_EXTENSIBLE, NULL)
- G_IMPLEMENT_INTERFACE (
- WEBKIT_TYPE_SPELL_CHECKER,
- e_spell_checker_init_webkit_checker))
+ E_TYPE_EXTENSIBLE, NULL))
/**
* ESpellChecker:
*
* #ESpellChecker represents a spellchecker in Evolution. It can be used as a
- * provider for dictionaries. It also implements #WebKitSpellCheckerInterface,
- * so it can be set as a default spell-checker to WebKit editors
+ * provider for dictionaries.
*/
@@ -92,237 +83,6 @@ spell_checker_enchant_dicts_foreach_cb (gpointer key,
}
static void
-wksc_check_spelling (WebKitSpellChecker *webkit_checker,
- const gchar *word,
- gint *misspelling_location,
- gint *misspelling_length)
-{
- ESpellChecker *checker = E_SPELL_CHECKER (webkit_checker);
- GHashTable *active_dictionaries;
- PangoLanguage *language;
- PangoLogAttr *attrs;
- gint length, ii;
-
- active_dictionaries = checker->priv->active_dictionaries;
- if (g_hash_table_size (active_dictionaries) == 0)
- return;
-
- length = g_utf8_strlen (word, -1);
-
- language = pango_language_get_default ();
- attrs = g_new (PangoLogAttr, length + 1);
-
- pango_get_log_attrs (word, -1, -1, language, attrs, length + 1);
-
- for (ii = 0; ii < length + 1; ii++) {
- /* We go through each character until we find an is_word_start,
- * then we get into an inner loop to find the is_word_end
- * corresponding */
- if (attrs[ii].is_word_start) {
- gboolean word_recognized;
- gint start = ii;
- gint end = ii;
- gint word_length;
- gchar *cstart;
- gint bytes;
- gchar *new_word;
-
- while (attrs[end].is_word_end < 1)
- end++;
-
- word_length = end - start;
- /* Set the iterator to be at the current word
- * end, so we don't check characters twice. */
- ii = end;
-
- cstart = g_utf8_offset_to_pointer (word, start);
- bytes = g_utf8_offset_to_pointer (word, end) - cstart;
- new_word = g_new0 (gchar, bytes + 1);
-
- g_utf8_strncpy (new_word, cstart, word_length);
-
- word_recognized = e_spell_checker_check_word (
- checker, new_word, strlen (new_word));
-
- if (word_recognized) {
- if (misspelling_location != NULL)
- *misspelling_location = -1;
- if (misspelling_length != NULL)
- *misspelling_length = 0;
- } else {
- if (misspelling_location != NULL)
- *misspelling_location = start;
- if (misspelling_length != NULL)
- *misspelling_length = word_length;
- }
-
- g_free (new_word);
- }
- }
-
- g_free (attrs);
-}
-
-static gchar **
-wksc_get_guesses (WebKitSpellChecker *webkit_checker,
- const gchar *word,
- const gchar *context)
-{
- ESpellChecker *checker = E_SPELL_CHECKER (webkit_checker);
- GHashTable *active_dictionaries;
- GList *list, *link;
- gchar ** guesses;
- gint ii = 0;
-
- guesses = g_new0 (gchar *, MAX_SUGGESTIONS + 1);
-
- active_dictionaries = checker->priv->active_dictionaries;
- list = g_hash_table_get_keys (active_dictionaries);
-
- for (link = list; link != NULL; link = g_list_next (link)) {
- ESpellDictionary *dictionary;
- GList *suggestions;
-
- dictionary = E_SPELL_DICTIONARY (link->data);
- suggestions = e_spell_dictionary_get_suggestions (
- dictionary, word, -1);
-
- while (suggestions != NULL && ii < MAX_SUGGESTIONS) {
- guesses[ii++] = suggestions->data;
- suggestions->data = NULL;
-
- suggestions = g_list_delete_link (
- suggestions, suggestions);
- }
-
- g_list_free_full (suggestions, (GDestroyNotify) g_free);
-
- if (ii >= MAX_SUGGESTIONS)
- break;
- }
-
- g_list_free (list);
-
- return guesses;
-}
-
-static gchar *
-wksc_get_autocorrect_suggestions (WebKitSpellChecker *webkit_checker,
- const gchar *word)
-{
- /* Not supported/needed */
- return NULL;
-}
-
-static void
-spell_checker_learn_word (WebKitSpellChecker *webkit_checker,
- const gchar *word)
-{
- /* Carefully, this will add the word to all active dictionaries! */
-
- ESpellChecker *checker;
- GHashTable *active_dictionaries;
- GList *list, *link;
-
- checker = E_SPELL_CHECKER (webkit_checker);
- active_dictionaries = checker->priv->active_dictionaries;
- list = g_hash_table_get_keys (active_dictionaries);
-
- for (link = list; link != NULL; link = g_list_next (link)) {
- ESpellDictionary *dictionary;
-
- dictionary = E_SPELL_DICTIONARY (link->data);
- e_spell_dictionary_learn_word (dictionary, word, -1);
- }
-
- g_list_free (list);
-}
-
-static void
-spell_checker_ignore_word (WebKitSpellChecker *webkit_checker,
- const gchar *word)
-{
- /* Carefully, this will add the word to all active dictionaries */
-
- ESpellChecker *checker;
- GHashTable *active_dictionaries;
- GList *list, *link;
-
- checker = E_SPELL_CHECKER (webkit_checker);
- active_dictionaries = checker->priv->active_dictionaries;
- list = g_hash_table_get_keys (active_dictionaries);
-
- for (link = list; link != NULL; link = g_list_next (link)) {
- ESpellDictionary *dictionary;
-
- dictionary = E_SPELL_DICTIONARY (link->data);
- e_spell_dictionary_ignore_word (dictionary, word, -1);
- }
-
- g_list_free (list);
-}
-
-static void
-wksc_update_languages (WebKitSpellChecker *webkit_checker,
- const gchar *languages)
-{
- ESpellChecker *checker;
- GHashTable *active_dictionaries;
- GQueue queue = G_QUEUE_INIT;
-
- checker = E_SPELL_CHECKER (webkit_checker);
- active_dictionaries = checker->priv->active_dictionaries;
-
- if (languages != NULL) {
- gchar **langs;
- gint ii;
-
- langs = g_strsplit (languages, ",", -1);
- for (ii = 0; langs[ii] != NULL; ii++) {
- ESpellDictionary *dictionary;
-
- dictionary = e_spell_checker_ref_dictionary (
- checker, langs[ii]);
- if (dictionary != NULL)
- g_queue_push_tail (&queue, dictionary);
- }
- g_strfreev (langs);
- } else {
- ESpellDictionary *dictionary;
- PangoLanguage *pango_language;
- const gchar *language;
-
- pango_language = gtk_get_default_language ();
- language = pango_language_to_string (pango_language);
- dictionary = e_spell_checker_ref_dictionary (checker, language);
-
- if (dictionary == NULL) {
- GList *list;
-
- list = e_spell_checker_list_available_dicts (checker);
- if (list != NULL) {
- dictionary = g_object_ref (list->data);
- g_list_free (list);
- }
- }
-
- if (dictionary != NULL)
- g_queue_push_tail (&queue, dictionary);
- }
-
- g_hash_table_remove_all (active_dictionaries);
-
- while (!g_queue_is_empty (&queue)) {
- ESpellDictionary *dictionary;
-
- dictionary = g_queue_pop_head (&queue);
- g_hash_table_add (active_dictionaries, dictionary);
- }
-
- g_object_notify (G_OBJECT (checker), "active-languages");
-}
-
-static void
spell_checker_get_property (GObject *object,
guint property_id,
GValue *value,
@@ -403,18 +163,6 @@ e_spell_checker_class_init (ESpellCheckerClass *class)
}
static void
-e_spell_checker_init_webkit_checker (WebKitSpellCheckerInterface *interface)
-{
- interface->check_spelling_of_string = wksc_check_spelling;
- interface->get_autocorrect_suggestions_for_misspelled_word =
- wksc_get_autocorrect_suggestions;
- interface->get_guesses_for_word = wksc_get_guesses;
- interface->ignore_word = spell_checker_ignore_word;
- interface->learn_word = spell_checker_learn_word;
- interface->update_spell_checking_languages = wksc_update_languages;
-}
-
-static void
e_spell_checker_init (ESpellChecker *checker)
{
GHashTable *active_dictionaries;
@@ -573,6 +321,25 @@ e_spell_checker_list_available_dicts (ESpellChecker *checker)
}
/**
+ * e_spell_checker_count_available_dicts:
+ * @checker: An #ESpellChecker
+ *
+ * Returns: Count of available dictionaries.
+ **/
+guint
+e_spell_checker_count_available_dicts (ESpellChecker *checker)
+{
+ g_return_val_if_fail (E_IS_SPELL_CHECKER (checker), 0);
+
+ if (g_hash_table_size (checker->priv->dictionaries_cache) == 0) {
+ e_spell_checker_init_global_memory ();
+ g_hash_table_foreach (global_language_tags, copy_enchant_dicts, checker);
+ }
+
+ return g_hash_table_size (checker->priv->dictionaries_cache);
+}
+
+/**
* e_spell_checker_ref_dictionary:
* @checker: an #ESpellChecker
* @language_code: (allow-none): language code of a dictionary, or %NULL
@@ -703,6 +470,42 @@ e_spell_checker_set_language_active (ESpellChecker *checker,
}
/**
+ * e_spell_checker_set_active_languages:
+ * @checker: An #ESpellChecker
+ * @languages: A list of languages to have activated
+ *
+ * Activates only the languages from @languages, all others will
+ * be deactivated after this function is finished.
+ **/
+void
+e_spell_checker_set_active_languages (ESpellChecker *checker,
+ const gchar * const *languages)
+{
+ gint ii;
+
+ g_return_if_fail (E_IS_SPELL_CHECKER (checker));
+
+ g_object_freeze_notify (G_OBJECT (checker));
+
+ for (ii = 0; languages && languages[ii]; ii++) {
+ e_spell_checker_set_language_active (checker, languages[ii], TRUE);
+ }
+
+ if (ii == g_hash_table_size (checker->priv->active_dictionaries)) {
+ g_object_thaw_notify (G_OBJECT (checker));
+ return;
+ }
+
+ g_hash_table_remove_all (checker->priv->active_dictionaries);
+ for (ii = 0; languages && languages[ii]; ii++) {
+ e_spell_checker_set_language_active (checker, languages[ii], TRUE);
+ }
+
+ g_object_notify (G_OBJECT (checker), "active-languages");
+ g_object_thaw_notify (G_OBJECT (checker));
+}
+
+/**
* e_spell_checker_list_active_languages:
* @checker: an #ESpellChecker
* @n_languages: return location for the number of active languages, or %NULL
@@ -816,12 +619,24 @@ void
e_spell_checker_ignore_word (ESpellChecker *checker,
const gchar *word)
{
- WebKitSpellCheckerInterface *interface;
+ /* Carefully, this will add the word to all active dictionaries */
+
+ GHashTable *active_dictionaries;
+ GList *list, *link;
g_return_if_fail (E_IS_SPELL_CHECKER (checker));
- interface = WEBKIT_SPELL_CHECKER_GET_IFACE (checker);
- interface->ignore_word (WEBKIT_SPELL_CHECKER (checker), word);
+ active_dictionaries = checker->priv->active_dictionaries;
+ list = g_hash_table_get_keys (active_dictionaries);
+
+ for (link = list; link != NULL; link = g_list_next (link)) {
+ ESpellDictionary *dictionary;
+
+ dictionary = E_SPELL_DICTIONARY (link->data);
+ e_spell_dictionary_ignore_word (dictionary, word, -1);
+ }
+
+ g_list_free (list);
}
/**
@@ -836,10 +651,74 @@ void
e_spell_checker_learn_word (ESpellChecker *checker,
const gchar *word)
{
- WebKitSpellCheckerInterface *interface;
+ /* Carefully, this will add the word to all active dictionaries! */
+
+ GHashTable *active_dictionaries;
+ GList *list, *link;
g_return_if_fail (E_IS_SPELL_CHECKER (checker));
- interface = WEBKIT_SPELL_CHECKER_GET_IFACE (checker);
- interface->learn_word (WEBKIT_SPELL_CHECKER (checker), word);
+ active_dictionaries = checker->priv->active_dictionaries;
+ list = g_hash_table_get_keys (active_dictionaries);
+
+ for (link = list; link != NULL; link = g_list_next (link)) {
+ ESpellDictionary *dictionary;
+
+ dictionary = E_SPELL_DICTIONARY (link->data);
+ e_spell_dictionary_learn_word (dictionary, word, -1);
+ }
+
+ g_list_free (list);
+}
+
+/**
+ * e_spell_checker_get_guesses_for_word:
+ * @checker: an #ESpellChecker
+ * @word: word to get guesses for
+ *
+ * Returns: a NULL-terminated array of guesses for the @word. Free the returned
+ * pointer with g_strfreev() when done with it.
+ **/
+gchar **
+e_spell_checker_get_guesses_for_word (ESpellChecker *checker,
+ const gchar *word)
+{
+ GHashTable *active_dictionaries;
+ GList *list, *link;
+ gchar **guesses;
+ gint ii = 0;
+
+ g_return_val_if_fail (E_IS_SPELL_CHECKER (checker), NULL);
+ g_return_val_if_fail (word != NULL, NULL);
+
+ guesses = g_new0 (gchar *, MAX_SUGGESTIONS + 1);
+
+ active_dictionaries = checker->priv->active_dictionaries;
+ list = g_hash_table_get_keys (active_dictionaries);
+
+ for (link = list; link != NULL; link = g_list_next (link)) {
+ ESpellDictionary *dictionary;
+ GList *suggestions;
+
+ dictionary = E_SPELL_DICTIONARY (link->data);
+ suggestions = e_spell_dictionary_get_suggestions (
+ dictionary, word, -1);
+
+ while (suggestions != NULL && ii < MAX_SUGGESTIONS) {
+ guesses[ii++] = suggestions->data;
+ suggestions->data = NULL;
+
+ suggestions = g_list_delete_link (
+ suggestions, suggestions);
+ }
+
+ g_list_free_full (suggestions, (GDestroyNotify) g_free);
+
+ if (ii >= MAX_SUGGESTIONS)
+ break;
+ }
+
+ g_list_free (list);
+
+ return guesses;
}
diff --git a/e-util/e-spell-checker.h b/e-util/e-spell-checker.h
index d986e84..690401b 100644
--- a/e-util/e-spell-checker.h
+++ b/e-util/e-spell-checker.h
@@ -66,6 +66,8 @@ void e_spell_checker_free_global_memory
ESpellChecker * e_spell_checker_new (void);
GList * e_spell_checker_list_available_dicts
(ESpellChecker *checker);
+guint e_spell_checker_count_available_dicts
+ (ESpellChecker *checker);
ESpellDictionary *
e_spell_checker_ref_dictionary (ESpellChecker *checker,
const gchar *language_code);
@@ -79,6 +81,9 @@ void e_spell_checker_set_language_active
(ESpellChecker *checker,
const gchar *language_code,
gboolean active);
+void e_spell_checker_set_active_languages
+ (ESpellChecker *checker,
+ const gchar * const *languages);
gchar ** e_spell_checker_list_active_languages
(ESpellChecker *checker,
guint *n_languages);
@@ -91,6 +96,9 @@ void e_spell_checker_learn_word (ESpellChecker *checker,
const gchar *word);
void e_spell_checker_ignore_word (ESpellChecker *checker,
const gchar *word);
+gchar ** e_spell_checker_get_guesses_for_word
+ (ESpellChecker *checker,
+ const gchar *word);
G_END_DECLS
diff --git a/e-util/e-stock-request.c b/e-util/e-stock-request.c
index 5d70fa3..c550a2c 100644
--- a/e-util/e-stock-request.c
+++ b/e-util/e-stock-request.c
@@ -15,56 +15,87 @@
*
*/
-#define LIBSOUP_USE_UNSTABLE_REQUEST_API
-
-#include "e-stock-request.h"
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
#include <stdlib.h>
+#include <string.h>
+
#include <gtk/gtk.h>
#include <libsoup/soup.h>
-#include <string.h>
+#include <libedataserver/libedataserver.h>
-#define E_STOCK_REQUEST_GET_PRIVATE(obj) \
- (G_TYPE_INSTANCE_GET_PRIVATE \
- ((obj), E_TYPE_STOCK_REQUEST, EStockRequestPrivate))
+#include "e-misc-utils.h"
+#include "e-stock-request.h"
struct _EStockRequestPrivate {
- gchar *content_type;
- gint content_length;
+ gint dummy;
};
-static const gchar *data_schemes[] = { "gtk-stock", NULL };
+static void e_stock_request_content_request_init (EContentRequestInterface *iface);
-G_DEFINE_TYPE (EStockRequest, e_stock_request, SOUP_TYPE_REQUEST)
+G_DEFINE_TYPE_WITH_CODE (EStockRequest, e_stock_request, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (E_TYPE_CONTENT_REQUEST, e_stock_request_content_request_init))
static gboolean
-handle_stock_request_idle_cb (gpointer user_data)
+e_stock_request_can_process_uri (EContentRequest *request,
+ const gchar *uri)
{
- EStockRequestPrivate *priv;
- GSimpleAsyncResult *simple;
- GObject *object;
- SoupURI *uri;
+ g_return_val_if_fail (E_IS_STOCK_REQUEST (request), FALSE);
+ g_return_val_if_fail (uri != NULL, FALSE);
+
+ return g_ascii_strncasecmp (uri, "gtk-stock:", 10) == 0;
+}
+
+typedef struct _StockIdleData
+{
+ EContentRequest *request;
+ const gchar *uri;
+ GObject *requester;
+ GInputStream **out_stream;
+ gint64 *out_stream_length;
+ gchar **out_mime_type;
+ GCancellable *cancellable;
+ GError **error;
+
+ gboolean success;
+ EFlag *flag;
+} StockIdleData;
+
+static gboolean
+process_stock_request_idle_cb (gpointer user_data)
+{
+ StockIdleData *sid = user_data;
+ SoupURI *suri;
GHashTable *query = NULL;
GtkStyleContext *context;
GtkWidgetPath *path;
GtkIconSet *icon_set;
gssize size = GTK_ICON_SIZE_BUTTON;
gchar *a_size;
- gchar *buffer = NULL;
+ gchar *buffer = NULL, *mime_type = NULL;
gsize buff_len = 0;
GError *local_error = NULL;
- simple = G_SIMPLE_ASYNC_RESULT (user_data);
+ g_return_val_if_fail (sid != NULL, FALSE);
+ g_return_val_if_fail (E_IS_STOCK_REQUEST (sid->request), FALSE);
+ g_return_val_if_fail (sid->uri != NULL, FALSE);
+ g_return_val_if_fail (sid->flag != NULL, FALSE);
- /* This returns a new reference. */
- object = g_async_result_get_source_object (G_ASYNC_RESULT (simple));
+ if (g_cancellable_set_error_if_cancelled (sid->cancellable, sid->error)) {
+ sid->success = FALSE;
+ e_flag_set (sid->flag);
- priv = E_STOCK_REQUEST_GET_PRIVATE (object);
+ return FALSE;
+ }
+
+ suri = soup_uri_new (sid->uri);
+ g_return_val_if_fail (suri != NULL, FALSE);
- uri = soup_request_get_uri (SOUP_REQUEST (object));
- if (uri->query != NULL)
- query = soup_form_decode (uri->query);
+ if (suri->query != NULL)
+ query = soup_form_decode (suri->query);
if (query != NULL) {
a_size = g_hash_table_lookup (query, "size");
@@ -81,7 +112,7 @@ handle_stock_request_idle_cb (gpointer user_data)
gtk_style_context_set_path (context, path);
gtk_widget_path_free (path);
- icon_set = gtk_style_context_lookup_icon_set (context, uri->host);
+ icon_set = gtk_style_context_lookup_icon_set (context, suri->host);
if (icon_set != NULL) {
GdkPixbuf *pixbuf;
@@ -97,11 +128,19 @@ handle_stock_request_idle_cb (gpointer user_data)
GtkIconTheme *icon_theme;
GtkIconInfo *icon_info;
const gchar *filename;
+ gint icon_width, icon_height;
+
+ if (!gtk_icon_size_lookup (size, &icon_width, &icon_height)) {
+ icon_width = size;
+ icon_height = size;
+ }
+
+ size = MAX (icon_width, icon_height);
icon_theme = gtk_icon_theme_get_default ();
icon_info = gtk_icon_theme_lookup_icon (
- icon_theme, uri->host, size,
+ icon_theme, suri->host, size,
GTK_ICON_LOOKUP_USE_BUILTIN);
/* Some icons can be missing in the theme */
@@ -113,9 +152,7 @@ handle_stock_request_idle_cb (gpointer user_data)
buffer = NULL;
buff_len = 0;
}
- priv->content_type =
- g_content_type_guess (filename, NULL, 0, NULL);
-
+ mime_type = g_content_type_guess (filename, NULL, 0, NULL);
} else {
GdkPixbuf *pixbuf;
@@ -129,156 +166,141 @@ handle_stock_request_idle_cb (gpointer user_data)
}
gtk_icon_info_free (icon_info);
- }
- }
-
- /* Sanity check */
- g_warn_if_fail (
- ((buffer != NULL) && (local_error == NULL)) ||
- ((buffer == NULL) && (local_error != NULL)));
-
- if (priv->content_type == NULL)
- priv->content_type = g_strdup ("image/png");
- priv->content_length = buff_len;
-
- if (buffer != NULL) {
- GInputStream *stream;
-
- stream = g_memory_input_stream_new_from_data (
- buffer, buff_len, (GDestroyNotify) g_free);
- g_simple_async_result_set_op_res_gpointer (
- simple, g_object_ref (stream),
- (GDestroyNotify) g_object_unref);
- g_object_unref (stream);
- }
-
- if (local_error != NULL)
- g_simple_async_result_take_error (simple, local_error);
-
- g_simple_async_result_complete_in_idle (simple);
-
- g_object_unref (context);
- g_object_unref (object);
+ } else if (g_strcmp0 (suri->host, "x-evolution-arrow-down") == 0) {
+ GdkPixbuf *pixbuf;
+ GdkRGBA rgba;
+ guchar *data;
+ gint stride;
+ cairo_surface_t *surface;
+ cairo_t *cr;
- return FALSE;
-}
+ stride = cairo_format_stride_for_width (CAIRO_FORMAT_RGB24, size);
+ buff_len = stride * size;
+ data = g_malloc0 (buff_len);
+ surface = cairo_image_surface_create_for_data (data, CAIRO_FORMAT_RGB24, size, size,
stride);
-static void
-stock_request_finalize (GObject *object)
-{
- EStockRequestPrivate *priv;
+ cr = cairo_create (surface);
- priv = E_STOCK_REQUEST_GET_PRIVATE (object);
+ if (gtk_style_context_lookup_color (context, "color", &rgba))
+ gdk_cairo_set_source_rgba (cr, &rgba);
+ else
+ cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 1.0);
- g_free (priv->content_type);
+ gtk_render_background (context, cr, 0, 0, size, size);
+ gtk_render_arrow (context, cr, G_PI, 0, 0, size);
- /* Chain up to parent's finalize() method. */
- G_OBJECT_CLASS (e_stock_request_parent_class)->finalize (object);
-}
+ cairo_destroy (cr);
-static gboolean
-stock_request_check_uri (SoupRequest *request,
- SoupURI *uri,
- GError **error)
-{
- return (strcmp (uri->scheme, "gtk-stock") == 0);
-}
+ cairo_surface_flush (surface);
-static void
-stock_request_send_async (SoupRequest *request,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- GSimpleAsyncResult *simple;
+ pixbuf = gdk_pixbuf_new_from_data (data, GDK_COLORSPACE_RGB, TRUE, 8, size, size,
stride, NULL, NULL);
+ gdk_pixbuf_save_to_buffer (
+ pixbuf, &buffer, &buff_len,
+ "png", &local_error, NULL);
+ g_object_unref (pixbuf);
- simple = g_simple_async_result_new (
- G_OBJECT (request), callback, user_data,
- stock_request_send_async);
+ cairo_surface_destroy (surface);
+ g_free (data);
+ }
+ }
- g_simple_async_result_set_check_cancellable (simple, cancellable);
+ /* Sanity check */
+ g_warn_if_fail (
+ ((buffer != NULL) && (local_error == NULL)) ||
+ ((buffer == NULL) && (local_error != NULL)));
- /* Need to run this operation in an idle callback rather
- * than a worker thread, since we're making all kinds of
- * GdkPixbuf/GTK+ calls. */
- g_idle_add_full (
- G_PRIORITY_HIGH_IDLE,
- handle_stock_request_idle_cb,
- g_object_ref (simple),
- (GDestroyNotify) g_object_unref);
+ if (!mime_type)
+ mime_type = g_strdup ("image/png");
- g_object_unref (simple);
-}
+ if (buffer != NULL) {
+ *sid->out_stream = g_memory_input_stream_new_from_data (buffer, buff_len, g_free);;
+ *sid->out_stream_length = buff_len;
+ *sid->out_mime_type = mime_type;
-static GInputStream *
-stock_request_send_finish (SoupRequest *request,
- GAsyncResult *result,
- GError **error)
-{
- GSimpleAsyncResult *simple;
- GInputStream *stream;
+ sid->success = TRUE;
+ } else {
+ g_free (mime_type);
- simple = G_SIMPLE_ASYNC_RESULT (result);
- stream = g_simple_async_result_get_op_res_gpointer (simple);
+ if (local_error)
+ g_propagate_error (sid->error, local_error);
- if (g_simple_async_result_propagate_error (simple, error))
- return NULL;
+ sid->success = FALSE;
+ }
- /* Reset the stream before passing it back to WebKit. */
- if (G_IS_SEEKABLE (stream))
- g_seekable_seek (
- G_SEEKABLE (stream), 0,
- G_SEEK_SET, NULL, NULL);
+ soup_uri_free (suri);
+ g_object_unref (context);
- if (stream != NULL)
- return g_object_ref (stream);
+ e_flag_set (sid->flag);
- return g_memory_input_stream_new ();
+ return FALSE;
}
-static goffset
-stock_request_get_content_length (SoupRequest *request)
+static gboolean
+e_stock_request_process_sync (EContentRequest *request,
+ const gchar *uri,
+ GObject *requester,
+ GInputStream **out_stream,
+ gint64 *out_stream_length,
+ gchar **out_mime_type,
+ GCancellable *cancellable,
+ GError **error)
{
- EStockRequestPrivate *priv;
+ StockIdleData sid;
+
+ g_return_val_if_fail (E_IS_STOCK_REQUEST (request), FALSE);
+ g_return_val_if_fail (uri != NULL, FALSE);
+
+ sid.request = request;
+ sid.uri = uri;
+ sid.requester = requester;
+ sid.out_stream = out_stream;
+ sid.out_stream_length = out_stream_length;
+ sid.out_mime_type = out_mime_type;
+ sid.cancellable = cancellable;
+ sid.error = error;
+ sid.flag = e_flag_new ();
+ sid.success = FALSE;
+
+ if (e_util_is_main_thread (NULL)) {
+ process_stock_request_idle_cb (&sid);
+ } else {
+ /* Need to run this operation in an idle callback rather
+ * than a worker thread, since we're making all kinds of
+ * GdkPixbuf/GTK+ calls. */
+ g_idle_add_full (
+ G_PRIORITY_HIGH_IDLE,
+ process_stock_request_idle_cb,
+ &sid, NULL);
+
+ e_flag_wait (sid.flag);
+ }
- priv = E_STOCK_REQUEST_GET_PRIVATE (request);
+ e_flag_free (sid.flag);
- return priv->content_length;
+ return sid.success;
}
-static const gchar *
-stock_request_get_content_type (SoupRequest *request)
+static void
+e_stock_request_content_request_init (EContentRequestInterface *iface)
{
- EStockRequestPrivate *priv;
-
- priv = E_STOCK_REQUEST_GET_PRIVATE (request);
-
- return priv->content_type;
+ iface->can_process_uri = e_stock_request_can_process_uri;
+ iface->process_sync = e_stock_request_process_sync;
}
static void
e_stock_request_class_init (EStockRequestClass *class)
{
- GObjectClass *object_class;
- SoupRequestClass *request_class;
-
g_type_class_add_private (class, sizeof (EStockRequestPrivate));
-
- object_class = G_OBJECT_CLASS (class);
- object_class->finalize = stock_request_finalize;
-
- request_class = SOUP_REQUEST_CLASS (class);
- request_class->schemes = data_schemes;
- request_class->check_uri = stock_request_check_uri;
- request_class->send_async = stock_request_send_async;
- request_class->send_finish = stock_request_send_finish;
- request_class->get_content_length = stock_request_get_content_length;
- request_class->get_content_type = stock_request_get_content_type;
}
static void
e_stock_request_init (EStockRequest *request)
{
- request->priv = E_STOCK_REQUEST_GET_PRIVATE (request);
+ request->priv = G_TYPE_INSTANCE_GET_PRIVATE (request, E_TYPE_STOCK_REQUEST, EStockRequestPrivate);
}
+EContentRequest *
+e_stock_request_new (void)
+{
+ return g_object_new (E_TYPE_STOCK_REQUEST, NULL);
+}
diff --git a/e-util/e-stock-request.h b/e-util/e-stock-request.h
index be6222b..09800d0 100644
--- a/e-util/e-stock-request.h
+++ b/e-util/e-stock-request.h
@@ -22,10 +22,7 @@
#ifndef E_STOCK_REQUEST_H
#define E_STOCK_REQUEST_H
-#define LIBSOUP_USE_UNSTABLE_REQUEST_API
-
-#include <libsoup/soup.h>
-#include <libsoup/soup-request.h>
+#include <e-util/e-content-request.h>
/* Standard GObject macros */
#define E_TYPE_STOCK_REQUEST \
@@ -53,15 +50,17 @@ typedef struct _EStockRequestClass EStockRequestClass;
typedef struct _EStockRequestPrivate EStockRequestPrivate;
struct _EStockRequest {
- SoupRequest parent;
+ GObject parent;
EStockRequestPrivate *priv;
};
struct _EStockRequestClass {
- SoupRequestClass parent;
+ GObjectClass parent;
};
GType e_stock_request_get_type (void) G_GNUC_CONST;
+EContentRequest *
+ e_stock_request_new (void);
G_END_DECLS
diff --git a/e-util/e-util-enums.h b/e-util/e-util-enums.h
index d24aebd..884c041 100644
--- a/e-util/e-util-enums.h
+++ b/e-util/e-util-enums.h
@@ -124,226 +124,415 @@ typedef enum {
E_DURATION_DAYS
} EDurationType;
+/**
+ * EImageLoadingPolicy:
+ * @E_IMAGE_LOADING_POLICY_NEVER:
+ * Never load images from a remote server.
+ * @E_IMAGE_LOADING_POLICY_SOMETIMES:
+ * Only load images from a remote server if the sender is a known contact.
+ * @E_IMAGE_LOADING_POLICY_ALWAYS:
+ * Always load images from a remote server.
+ *
+ * Policy for loading remote image URLs in email. Allowing images to be
+ * loaded from a remote server may have privacy implications.
+ **/
+typedef enum {
+ E_IMAGE_LOADING_POLICY_NEVER,
+ E_IMAGE_LOADING_POLICY_SOMETIMES,
+ E_IMAGE_LOADING_POLICY_ALWAYS
+} EImageLoadingPolicy;
+
+/**
+ * EContentEditorInsertContentFlags:
+ * @E_CONTENT_EDITOR_INSERT_NONE:
+ * @E_CONTENT_EDITOR_INSERT_CONVERT:
+ * @E_CONTENT_EDITOR_INSERT_QUOTE_CONTENT:
+ * @E_CONTENT_EDITOR_INSERT_REPLACE_ALL:
+ * @E_CONTENT_EDITOR_INSERT_TEXT_HTML:
+ * @E_CONTENT_EDITOR_INSERT_TEXT_PLAIN:
+ *
+ * Since: 3.22
+ **/
+typedef enum {
+ E_CONTENT_EDITOR_INSERT_NONE = 0,
+ E_CONTENT_EDITOR_INSERT_CONVERT = 1 << 0,
+ E_CONTENT_EDITOR_INSERT_QUOTE_CONTENT = 1 << 1,
+ E_CONTENT_EDITOR_INSERT_REPLACE_ALL = 1 << 2,
+ E_CONTENT_EDITOR_INSERT_TEXT_HTML = 1 << 3,
+ E_CONTENT_EDITOR_INSERT_TEXT_PLAIN = 1 << 4,
+} EContentEditorInsertContentFlags;
+
+/**
+ * EContentEditorGetContentFlags:
+ * @E_CONTENT_EDITOR_GET_BODY:
+ * @E_CONTENT_EDITOR_GET_INLINE_IMAGES:
+ * @E_CONTENT_EDITOR_GET_PROCESSED: raw or processed
+ * @E_CONTENT_EDITOR_GET_TEXT_HTML:
+ * @E_CONTENT_EDITOR_GET_TEXT_PLAIN:
+ * @E_CONTENT_EDITOR_GET_EXCLUDE_SIGNATURE:
+ *
+ * Since: 3.22
+ **/
+typedef enum {
+ E_CONTENT_EDITOR_GET_BODY = 1 << 0,
+ E_CONTENT_EDITOR_GET_INLINE_IMAGES = 1 << 1,
+ E_CONTENT_EDITOR_GET_PROCESSED = 1 << 2, /* raw or processed */
+ E_CONTENT_EDITOR_GET_TEXT_HTML = 1 << 3,
+ E_CONTENT_EDITOR_GET_TEXT_PLAIN = 1 << 4,
+ E_CONTENT_EDITOR_GET_EXCLUDE_SIGNATURE = 1 << 5
+} EContentEditorGetContentFlags;
+
+/**
+ * EContentEditorNodeFlags:
+ * @E_CONTENT_EDITOR_NODE_UNKNOWN: None from the below, aka when cannot determine.
+ * @E_CONTENT_EDITOR_NODE_IS_ANCHOR:
+ * @E_CONTENT_EDITOR_NODE_IS_H_RULE:
+ * @E_CONTENT_EDITOR_NODE_IS_IMAGE:
+ * @E_CONTENT_EDITOR_NODE_IS_TABLE:
+ * @E_CONTENT_EDITOR_NODE_IS_TABLE_CELL:
+ * @E_CONTENT_EDITOR_NODE_IS_TEXT:
+ * @E_CONTENT_EDITOR_NODE_IS_TEXT_COLLAPSED:
+ *
+ * Since: 3.22
+ **/
+typedef enum {
+ E_CONTENT_EDITOR_NODE_UNKNOWN = 0,
+ E_CONTENT_EDITOR_NODE_IS_ANCHOR = 1 << 0,
+ E_CONTENT_EDITOR_NODE_IS_H_RULE = 1 << 1,
+ E_CONTENT_EDITOR_NODE_IS_IMAGE = 1 << 2,
+ E_CONTENT_EDITOR_NODE_IS_TABLE = 1 << 3,
+ E_CONTENT_EDITOR_NODE_IS_TABLE_CELL = 1 << 4,
+ E_CONTENT_EDITOR_NODE_IS_TEXT = 1 << 5,
+ E_CONTENT_EDITOR_NODE_IS_TEXT_COLLAPSED = 1 << 6
+} EContentEditorNodeFlags;
+
+/**
+ * EContentEditorStyleFlags:
+ * @E_CONTENT_EDITOR_STYLE_NONE: None from the below.
+ * @E_CONTENT_EDITOR_STYLE_IS_BOLD:
+ * @E_CONTENT_EDITOR_STYLE_IS_ITALIC:
+ * @E_CONTENT_EDITOR_STYLE_IS_UNDERLINE:
+ * @E_CONTENT_EDITOR_STYLE_IS_STRIKETHROUGH:
+ * @E_CONTENT_EDITOR_STYLE_IS_MONOSPACE:
+ * @E_CONTENT_EDITOR_STYLE_IS_SUBSCRIPT:
+ * @E_CONTENT_EDITOR_STYLE_IS_SUPERSCRIPT:
+ *
+ * Since: 3.22
+ **/
+typedef enum {
+ E_CONTENT_EDITOR_STYLE_NONE = 0,
+ E_CONTENT_EDITOR_STYLE_IS_BOLD = 1 << 0,
+ E_CONTENT_EDITOR_STYLE_IS_ITALIC = 1 << 1,
+ E_CONTENT_EDITOR_STYLE_IS_UNDERLINE = 1 << 2,
+ E_CONTENT_EDITOR_STYLE_IS_STRIKETHROUGH = 1 << 3,
+ E_CONTENT_EDITOR_STYLE_IS_MONOSPACE = 1 << 4,
+ E_CONTENT_EDITOR_STYLE_IS_SUBSCRIPT = 1 << 5,
+ E_CONTENT_EDITOR_STYLE_IS_SUPERSCRIPT = 1 << 6
+} EContentEditorStyleFlags;
+
+/**
+ * EContentEditorBlockFormat:
+ * @E_CONTENT_EDITOR_BLOCK_FORMAT_NONE:
+ * @E_CONTENT_EDITOR_BLOCK_FORMAT_PARAGRAPH:
+ * @E_CONTENT_EDITOR_BLOCK_FORMAT_PRE:
+ * @E_CONTENT_EDITOR_BLOCK_FORMAT_ADDRESS:
+ * @E_CONTENT_EDITOR_BLOCK_FORMAT_H1:
+ * @E_CONTENT_EDITOR_BLOCK_FORMAT_H2:
+ * @E_CONTENT_EDITOR_BLOCK_FORMAT_H3:
+ * @E_CONTENT_EDITOR_BLOCK_FORMAT_H4:
+ * @E_CONTENT_EDITOR_BLOCK_FORMAT_H5:
+ * @E_CONTENT_EDITOR_BLOCK_FORMAT_H6:
+ * @E_CONTENT_EDITOR_BLOCK_FORMAT_UNORDERED_LIST:
+ * @E_CONTENT_EDITOR_BLOCK_FORMAT_ORDERED_LIST:
+ * @E_CONTENT_EDITOR_BLOCK_FORMAT_ORDERED_LIST_ROMAN:
+ * @E_CONTENT_EDITOR_BLOCK_FORMAT_ORDERED_LIST_ALPHA:
+ *
+ * Since: 3.22
+ **/
typedef enum {
- E_HTML_EDITOR_SELECTION_BLOCK_FORMAT_NONE = 0,
- E_HTML_EDITOR_SELECTION_BLOCK_FORMAT_PARAGRAPH,
- E_HTML_EDITOR_SELECTION_BLOCK_FORMAT_PRE,
- E_HTML_EDITOR_SELECTION_BLOCK_FORMAT_ADDRESS,
- E_HTML_EDITOR_SELECTION_BLOCK_FORMAT_BLOCKQUOTE,
- E_HTML_EDITOR_SELECTION_BLOCK_FORMAT_H1,
- E_HTML_EDITOR_SELECTION_BLOCK_FORMAT_H2,
- E_HTML_EDITOR_SELECTION_BLOCK_FORMAT_H3,
- E_HTML_EDITOR_SELECTION_BLOCK_FORMAT_H4,
- E_HTML_EDITOR_SELECTION_BLOCK_FORMAT_H5,
- E_HTML_EDITOR_SELECTION_BLOCK_FORMAT_H6,
- E_HTML_EDITOR_SELECTION_BLOCK_FORMAT_UNORDERED_LIST,
- E_HTML_EDITOR_SELECTION_BLOCK_FORMAT_ORDERED_LIST,
- E_HTML_EDITOR_SELECTION_BLOCK_FORMAT_ORDERED_LIST_ROMAN,
- E_HTML_EDITOR_SELECTION_BLOCK_FORMAT_ORDERED_LIST_ALPHA
-} EHTMLEditorSelectionBlockFormat;
+ E_CONTENT_EDITOR_BLOCK_FORMAT_NONE = 0,
+ E_CONTENT_EDITOR_BLOCK_FORMAT_PARAGRAPH,
+ E_CONTENT_EDITOR_BLOCK_FORMAT_PRE,
+ E_CONTENT_EDITOR_BLOCK_FORMAT_ADDRESS,
+ E_CONTENT_EDITOR_BLOCK_FORMAT_H1,
+ E_CONTENT_EDITOR_BLOCK_FORMAT_H2,
+ E_CONTENT_EDITOR_BLOCK_FORMAT_H3,
+ E_CONTENT_EDITOR_BLOCK_FORMAT_H4,
+ E_CONTENT_EDITOR_BLOCK_FORMAT_H5,
+ E_CONTENT_EDITOR_BLOCK_FORMAT_H6,
+ E_CONTENT_EDITOR_BLOCK_FORMAT_UNORDERED_LIST,
+ E_CONTENT_EDITOR_BLOCK_FORMAT_ORDERED_LIST,
+ E_CONTENT_EDITOR_BLOCK_FORMAT_ORDERED_LIST_ROMAN,
+ E_CONTENT_EDITOR_BLOCK_FORMAT_ORDERED_LIST_ALPHA
+} EContentEditorBlockFormat;
-/* The values match the actual size in <font size="n"> */
+/**
+ * EContentEditorFontSize:
+ * @E_CONTENT_EDITOR_FONT_SIZE_TINY:
+ * @E_CONTENT_EDITOR_FONT_SIZE_SMALL:
+ * @E_CONTENT_EDITOR_FONT_SIZE_NORMAL:
+ * @E_CONTENT_EDITOR_FONT_SIZE_BIG:
+ * @E_CONTENT_EDITOR_FONT_SIZE_BIGGER:
+ * @E_CONTENT_EDITOR_FONT_SIZE_LARGE:
+ * @E_CONTENT_EDITOR_FONT_SIZE_VERY_LARGE:
+ *
+ * Note: The values match the actual size in <font size="n">
+ *
+ * Since: 3.22
+ **/
typedef enum {
- E_HTML_EDITOR_SELECTION_FONT_SIZE_TINY = 1,
- E_HTML_EDITOR_SELECTION_FONT_SIZE_SMALL = 2,
- E_HTML_EDITOR_SELECTION_FONT_SIZE_NORMAL = 3,
- E_HTML_EDITOR_SELECTION_FONT_SIZE_BIG = 4,
- E_HTML_EDITOR_SELECTION_FONT_SIZE_BIGGER = 5,
- E_HTML_EDITOR_SELECTION_FONT_SIZE_LARGE = 6,
- E_HTML_EDITOR_SELECTION_FONT_SIZE_VERY_LARGE = 7
-} EHTMLEditorSelectionFontSize;
+ E_CONTENT_EDITOR_FONT_SIZE_TINY = 1,
+ E_CONTENT_EDITOR_FONT_SIZE_SMALL = 2,
+ E_CONTENT_EDITOR_FONT_SIZE_NORMAL = 3,
+ E_CONTENT_EDITOR_FONT_SIZE_BIG = 4,
+ E_CONTENT_EDITOR_FONT_SIZE_BIGGER = 5,
+ E_CONTENT_EDITOR_FONT_SIZE_LARGE = 6,
+ E_CONTENT_EDITOR_FONT_SIZE_VERY_LARGE = 7
+} EContentEditorFontSize;
+/**
+ * EContentEditorAlignment:
+ * @E_CONTENT_EDITOR_ALIGNMENT_LEFT:
+ * @E_CONTENT_EDITOR_ALIGNMENT_CENTER:
+ * @E_CONTENT_EDITOR_ALIGNMENT_RIGHT:
+ *
+ * Since: 3.22
+ **/
typedef enum {
- E_HTML_EDITOR_SELECTION_ALIGNMENT_LEFT,
- E_HTML_EDITOR_SELECTION_ALIGNMENT_CENTER,
- E_HTML_EDITOR_SELECTION_ALIGNMENT_RIGHT
-} EHTMLEditorSelectionAlignment;
+ E_CONTENT_EDITOR_ALIGNMENT_LEFT = 0,
+ E_CONTENT_EDITOR_ALIGNMENT_CENTER,
+ E_CONTENT_EDITOR_ALIGNMENT_RIGHT
+} EContentEditorAlignment;
+/**
+ * EContentEditorGranularity:
+ * @E_CONTENT_EDITOR_GRANULARITY_CHARACTER:
+ * @E_CONTENT_EDITOR_GRANULARITY_WORD:
+ *
+ * Since: 3.22
+ **/
typedef enum {
- E_HTML_EDITOR_SELECTION_GRANULARITY_CHARACTER,
- E_HTML_EDITOR_SELECTION_GRANULARITY_WORD
-} EHTMLEditorSelectionGranularity;
+ E_CONTENT_EDITOR_GRANULARITY_CHARACTER = 0,
+ E_CONTENT_EDITOR_GRANULARITY_WORD
+} EContentEditorGranularity;
/**
- * EHTMLEditorViewCommand:
- * @E_HTML_EDITOR_VIEW_COMMAND_BACKGROUND_COLOR:
+ * EContentEditorCommand:
+ * @E_CONTENT_EDITOR_COMMAND_BACKGROUND_COLOR:
* Sets background color to given value.
- * @E_HTML_EDITOR_VIEW_COMMAND_BOLD:
+ * @E_CONTENT_EDITOR_COMMAND_BOLD:
* Toggles bold formatting of current selection.
- * @E_HTML_EDITOR_VIEW_COMMAND_COPY:
+ * @E_CONTENT_EDITOR_COMMAND_COPY:
* Copies current selection to clipboard.
- * @E_HTML_EDITOR_VIEW_COMMAND_CREATE_LINK:
+ * @E_CONTENT_EDITOR_COMMAND_CREATE_LINK:
* Converts current selection to a link that points to URL in value
- * @E_HTML_EDITOR_VIEW_COMMAND_CUT:
+ * @E_CONTENT_EDITOR_COMMAND_CUT:
* Cuts current selection to clipboard.
- * @E_HTML_EDITOR_VIEW_COMMAND_DEFAULT_PARAGRAPH_SEPARATOR:
+ * @E_CONTENT_EDITOR_COMMAND_DEFAULT_PARAGRAPH_SEPARATOR:
* (XXX Explain me!)
- * @E_HTML_EDITOR_VIEW_COMMAND_DELETE:
+ * @E_CONTENT_EDITOR_COMMAND_DELETE:
* Deletes current selection.
- * @E_HTML_EDITOR_VIEW_COMMAND_FIND_STRING:
+ * @E_CONTENT_EDITOR_COMMAND_FIND_STRING:
* Highlights given string.
- * @E_HTML_EDITOR_VIEW_COMMAND_FONT_NAME:
+ * @E_CONTENT_EDITOR_COMMAND_FONT_NAME:
* Sets font name to given value.
- * @E_HTML_EDITOR_VIEW_COMMAND_FONT_SIZE:
+ * @E_CONTENT_EDITOR_COMMAND_FONT_SIZE:
* Sets font point size to given value (no units, just number)
- * @E_HTML_EDITOR_VIEW_COMMAND_FONT_SIZE_DELTA:
+ * @E_CONTENT_EDITOR_COMMAND_FONT_SIZE_DELTA:
* Changes font size by given delta value (no units, just number)
- * @E_HTML_EDITOR_VIEW_COMMAND_FORE_COLOR:
+ * @E_CONTENT_EDITOR_COMMAND_FORE_COLOR:
* Sets font color to given value
- * @E_HTML_EDITOR_VIEW_COMMAND_FORMAT_BLOCK:
+ * @E_CONTENT_EDITOR_COMMAND_FORMAT_BLOCK:
* Sets block type of current paragraph to given format. Allowed formats
* are "BLOCKQUOTE", "H1", "H2", "H3", "H4", "H5", "H6", "P", "PRE" and
* "ADDRESS".
- * @E_HTML_EDITOR_VIEW_COMMAND_FORWARD_DELETE:
+ * @E_CONTENT_EDITOR_COMMAND_FORWARD_DELETE:
* (XXX Explain me!)
- * @E_HTML_EDITOR_VIEW_COMMAND_HILITE_COLOR:
+ * @E_CONTENT_EDITOR_COMMAND_HILITE_COLOR:
* Sets color in which results of "FindString" command should be
* highlighted to given value.
- * @E_HTML_EDITOR_VIEW_COMMAND_INDENT:
+ * @E_CONTENT_EDITOR_COMMAND_INDENT:
* Indents current paragraph by one level.
- * @E_HTML_EDITOR_VIEW_COMMAND_INSERT_HTML:
+ * @E_CONTENT_EDITOR_COMMAND_INSERT_HTML:
* Inserts give HTML code into document.
- * @E_HTML_EDITOR_VIEW_COMMAND_INSERT_HORIZONTAL_RULE:
+ * @E_CONTENT_EDITOR_COMMAND_INSERT_HORIZONTAL_RULE:
* Inserts a horizontal rule (<HR>) on current line.
- * @E_HTML_EDITOR_VIEW_COMMAND_INSERT_IMAGE:
+ * @E_CONTENT_EDITOR_COMMAND_INSERT_IMAGE:
* Inserts an image with given source file.
- * @E_HTML_EDITOR_VIEW_COMMAND_INSERT_LINE_BREAK:
+ * @E_CONTENT_EDITOR_COMMAND_INSERT_LINE_BREAK:
* Breaks line at current cursor position.
- * @E_HTML_EDITOR_VIEW_COMMAND_INSERT_NEW_LINE_IN_QUOTED_CONTENT:
+ * @E_CONTENT_EDITOR_COMMAND_INSERT_NEW_LINE_IN_QUOTED_CONTENT:
* Breaks citation at current cursor position.
- * @E_HTML_EDITOR_VIEW_COMMAND_INSERT_ORDERED_LIST:
+ * @E_CONTENT_EDITOR_COMMAND_INSERT_ORDERED_LIST:
* Creates an ordered list environment at current cursor position.
- * @E_HTML_EDITOR_VIEW_COMMAND_INSERT_PARAGRAPH:
+ * @E_CONTENT_EDITOR_COMMAND_INSERT_PARAGRAPH:
* Inserts a new paragraph at current cursor position.
- * @E_HTML_EDITOR_VIEW_COMMAND_INSERT_TEXT:
+ * @E_CONTENT_EDITOR_COMMAND_INSERT_TEXT:
* Inserts given text at current cursor position.
- * @E_HTML_EDITOR_VIEW_COMMAND_INSERT_UNORDERED_LIST:
+ * @E_CONTENT_EDITOR_COMMAND_INSERT_UNORDERED_LIST:
* Creates an undordered list environment at current cursor position.
- * @E_HTML_EDITOR_VIEW_COMMAND_ITALIC:
+ * @E_CONTENT_EDITOR_COMMAND_ITALIC:
* Toggles italic formatting of current selection.
- * @E_HTML_EDITOR_VIEW_COMMAND_JUSTIFY_CENTER:
+ * @E_CONTENT_EDITOR_COMMAND_JUSTIFY_CENTER:
* Aligns current paragraph to center.
- * @E_HTML_EDITOR_VIEW_COMMAND_JUSTIFY_FULL:
+ * @E_CONTENT_EDITOR_COMMAND_JUSTIFY_FULL:
* Justifies current paragraph to block.
- * @E_HTML_EDITOR_VIEW_COMMAND_JUSTIFY_NONE:
+ * @E_CONTENT_EDITOR_COMMAND_JUSTIFY_NONE:
* Removes any justification or alignment of current paragraph.
- * @E_HTML_EDITOR_VIEW_COMMAND_JUSTIFY_RIGHT:
+ * @E_CONTENT_EDITOR_COMMAND_JUSTIFY_RIGHT:
* Aligns current paragraph to right.
- * @E_HTML_EDITOR_VIEW_COMMAND_OUTDENT:
+ * @E_CONTENT_EDITOR_COMMAND_OUTDENT:
* Outdents current paragraph by one level.
- * @E_HTML_EDITOR_VIEW_COMMAND_PASTE:
+ * @E_CONTENT_EDITOR_COMMAND_PASTE:
* Pastes clipboard content at current cursor position.
- * @E_HTML_EDITOR_VIEW_COMMAND_PASTE_AND_MATCH_STYLE:
+ * @E_CONTENT_EDITOR_COMMAND_PASTE_AND_MATCH_STYLE:
* Pastes clipboard content and matches its style to style at current
* cursor position.
- * @E_HTML_EDITOR_VIEW_COMMAND_PASTE_AS_PLAIN_TEXT:
+ * @E_CONTENT_EDITOR_COMMAND_PASTE_AS_PLAIN_TEXT:
* Pastes clipboard content at current cursor position removing any HTML
* formatting.
- * @E_HTML_EDITOR_VIEW_COMMAND_PRINT:
+ * @E_CONTENT_EDITOR_COMMAND_PRINT:
* Print current document.
- * @E_HTML_EDITOR_VIEW_COMMAND_REDO:
+ * @E_CONTENT_EDITOR_COMMAND_REDO:
* Redoes last action.
- * @E_HTML_EDITOR_VIEW_COMMAND_REMOVE_FORMAT:
+ * @E_CONTENT_EDITOR_COMMAND_REMOVE_FORMAT:
* Removes any formatting of current selection.
- * @E_HTML_EDITOR_VIEW_COMMAND_SELECT_ALL:
+ * @E_CONTENT_EDITOR_COMMAND_SELECT_ALL:
* Extends selects to the entire document.
- * @E_HTML_EDITOR_VIEW_COMMAND_STRIKETHROUGH:
+ * @E_CONTENT_EDITOR_COMMAND_STRIKETHROUGH:
* Toggles strikethrough formatting.
- * @E_HTML_EDITOR_VIEW_COMMAND_STYLE_WITH_CSS:
+ * @E_CONTENT_EDITOR_COMMAND_STYLE_WITH_CSS:
* Toggles whether style should be defined in CSS "style" attribute of
* elements or whether to use deprecated <FONT> tags. Depends on
* whether given value is "true" or "false".
- * @E_HTML_EDITOR_VIEW_COMMAND_SUBSCRIPT:
+ * @E_CONTENT_EDITOR_COMMAND_SUBSCRIPT:
* Toggles subscript of current selection.
- * @E_HTML_EDITOR_VIEW_COMMAND_SUPERSCRIPT:
+ * @E_CONTENT_EDITOR_COMMAND_SUPERSCRIPT:
* Toggles superscript of current selection.
- * @E_HTML_EDITOR_VIEW_COMMAND_TRANSPOSE:
+ * @E_CONTENT_EDITOR_COMMAND_TRANSPOSE:
* (XXX Explain me!)
- * @E_HTML_EDITOR_VIEW_COMMAND_UNDERLINE:
+ * @E_CONTENT_EDITOR_COMMAND_UNDERLINE:
* Toggles underline formatting of current selection.
- * @E_HTML_EDITOR_VIEW_COMMAND_UNDO:
+ * @E_CONTENT_EDITOR_COMMAND_UNDO:
* Undoes last action.
- * @E_HTML_EDITOR_VIEW_COMMAND_UNLINK:
+ * @E_CONTENT_EDITOR_COMMAND_UNLINK:
* Removes active links (<A>) from current selection (if there's any).
- * @E_HTML_EDITOR_VIEW_COMMAND_UNSELECT:
+ * @E_CONTENT_EDITOR_COMMAND_UNSELECT:
* Cancels current selection.
- * @E_HTML_EDITOR_VIEW_COMMAND_USE_CSS:
+ * @E_CONTENT_EDITOR_COMMAND_USE_CSS:
* Whether to allow use of CSS or not depending on whether given value is
* "true" or "false".
*
* Specifies the DOM command to execute in e_editor_widget_exec_command().
* Some commands require value to be passed in, which is always stated in the
* documentation.
- */
+ *
+ * Since: 3.22
+ **/
typedef enum {
- E_HTML_EDITOR_VIEW_COMMAND_BACKGROUND_COLOR,
- E_HTML_EDITOR_VIEW_COMMAND_BOLD,
- E_HTML_EDITOR_VIEW_COMMAND_COPY,
- E_HTML_EDITOR_VIEW_COMMAND_CREATE_LINK,
- E_HTML_EDITOR_VIEW_COMMAND_CUT,
- E_HTML_EDITOR_VIEW_COMMAND_DEFAULT_PARAGRAPH_SEPARATOR,
- E_HTML_EDITOR_VIEW_COMMAND_DELETE,
- E_HTML_EDITOR_VIEW_COMMAND_FIND_STRING,
- E_HTML_EDITOR_VIEW_COMMAND_FONT_NAME,
- E_HTML_EDITOR_VIEW_COMMAND_FONT_SIZE,
- E_HTML_EDITOR_VIEW_COMMAND_FONT_SIZE_DELTA,
- E_HTML_EDITOR_VIEW_COMMAND_FORE_COLOR,
- E_HTML_EDITOR_VIEW_COMMAND_FORMAT_BLOCK,
- E_HTML_EDITOR_VIEW_COMMAND_FORWARD_DELETE,
- E_HTML_EDITOR_VIEW_COMMAND_HILITE_COLOR,
- E_HTML_EDITOR_VIEW_COMMAND_INDENT,
- E_HTML_EDITOR_VIEW_COMMAND_INSERT_HTML,
- E_HTML_EDITOR_VIEW_COMMAND_INSERT_HORIZONTAL_RULE,
- E_HTML_EDITOR_VIEW_COMMAND_INSERT_IMAGE,
- E_HTML_EDITOR_VIEW_COMMAND_INSERT_LINE_BREAK,
- E_HTML_EDITOR_VIEW_COMMAND_INSERT_NEW_LINE_IN_QUOTED_CONTENT,
- E_HTML_EDITOR_VIEW_COMMAND_INSERT_ORDERED_LIST,
- E_HTML_EDITOR_VIEW_COMMAND_INSERT_PARAGRAPH,
- E_HTML_EDITOR_VIEW_COMMAND_INSERT_TEXT,
- E_HTML_EDITOR_VIEW_COMMAND_INSERT_UNORDERED_LIST,
- E_HTML_EDITOR_VIEW_COMMAND_ITALIC,
- E_HTML_EDITOR_VIEW_COMMAND_JUSTIFY_CENTER,
- E_HTML_EDITOR_VIEW_COMMAND_JUSTIFY_FULL,
- E_HTML_EDITOR_VIEW_COMMAND_JUSTIFY_LEFT,
- E_HTML_EDITOR_VIEW_COMMAND_JUSTIFY_NONE,
- E_HTML_EDITOR_VIEW_COMMAND_JUSTIFY_RIGHT,
- E_HTML_EDITOR_VIEW_COMMAND_OUTDENT,
- E_HTML_EDITOR_VIEW_COMMAND_PASTE,
- E_HTML_EDITOR_VIEW_COMMAND_PASTE_AND_MATCH_STYLE,
- E_HTML_EDITOR_VIEW_COMMAND_PASTE_AS_PLAIN_TEXT,
- E_HTML_EDITOR_VIEW_COMMAND_PRINT,
- E_HTML_EDITOR_VIEW_COMMAND_REDO,
- E_HTML_EDITOR_VIEW_COMMAND_REMOVE_FORMAT,
- E_HTML_EDITOR_VIEW_COMMAND_SELECT_ALL,
- E_HTML_EDITOR_VIEW_COMMAND_STRIKETHROUGH,
- E_HTML_EDITOR_VIEW_COMMAND_STYLE_WITH_CSS,
- E_HTML_EDITOR_VIEW_COMMAND_SUBSCRIPT,
- E_HTML_EDITOR_VIEW_COMMAND_SUPERSCRIPT,
- E_HTML_EDITOR_VIEW_COMMAND_TRANSPOSE,
- E_HTML_EDITOR_VIEW_COMMAND_UNDERLINE,
- E_HTML_EDITOR_VIEW_COMMAND_UNDO,
- E_HTML_EDITOR_VIEW_COMMAND_UNLINK,
- E_HTML_EDITOR_VIEW_COMMAND_UNSELECT,
- E_HTML_EDITOR_VIEW_COMMAND_USE_CSS
-} EHTMLEditorViewCommand;
+ E_CONTENT_EDITOR_COMMAND_BACKGROUND_COLOR,
+ E_CONTENT_EDITOR_COMMAND_BOLD,
+ E_CONTENT_EDITOR_COMMAND_COPY,
+ E_CONTENT_EDITOR_COMMAND_CREATE_LINK,
+ E_CONTENT_EDITOR_COMMAND_CUT,
+ E_CONTENT_EDITOR_COMMAND_DEFAULT_PARAGRAPH_SEPARATOR,
+ E_CONTENT_EDITOR_COMMAND_DELETE,
+ E_CONTENT_EDITOR_COMMAND_FIND_STRING,
+ E_CONTENT_EDITOR_COMMAND_FONT_NAME,
+ E_CONTENT_EDITOR_COMMAND_FONT_SIZE,
+ E_CONTENT_EDITOR_COMMAND_FONT_SIZE_DELTA,
+ E_CONTENT_EDITOR_COMMAND_FORE_COLOR,
+ E_CONTENT_EDITOR_COMMAND_FORMAT_BLOCK,
+ E_CONTENT_EDITOR_COMMAND_FORWARD_DELETE,
+ E_CONTENT_EDITOR_COMMAND_HILITE_COLOR,
+ E_CONTENT_EDITOR_COMMAND_INDENT,
+ E_CONTENT_EDITOR_COMMAND_INSERT_HTML,
+ E_CONTENT_EDITOR_COMMAND_INSERT_HORIZONTAL_RULE,
+ E_CONTENT_EDITOR_COMMAND_INSERT_IMAGE,
+ E_CONTENT_EDITOR_COMMAND_INSERT_LINE_BREAK,
+ E_CONTENT_EDITOR_COMMAND_INSERT_NEW_LINE_IN_QUOTED_CONTENT,
+ E_CONTENT_EDITOR_COMMAND_INSERT_ORDERED_LIST,
+ E_CONTENT_EDITOR_COMMAND_INSERT_PARAGRAPH,
+ E_CONTENT_EDITOR_COMMAND_INSERT_TEXT,
+ E_CONTENT_EDITOR_COMMAND_INSERT_UNORDERED_LIST,
+ E_CONTENT_EDITOR_COMMAND_ITALIC,
+ E_CONTENT_EDITOR_COMMAND_JUSTIFY_CENTER,
+ E_CONTENT_EDITOR_COMMAND_JUSTIFY_FULL,
+ E_CONTENT_EDITOR_COMMAND_JUSTIFY_LEFT,
+ E_CONTENT_EDITOR_COMMAND_JUSTIFY_NONE,
+ E_CONTENT_EDITOR_COMMAND_JUSTIFY_RIGHT,
+ E_CONTENT_EDITOR_COMMAND_OUTDENT,
+ E_CONTENT_EDITOR_COMMAND_PASTE,
+ E_CONTENT_EDITOR_COMMAND_PASTE_AND_MATCH_STYLE,
+ E_CONTENT_EDITOR_COMMAND_PASTE_AS_PLAIN_TEXT,
+ E_CONTENT_EDITOR_COMMAND_PRINT,
+ E_CONTENT_EDITOR_COMMAND_REDO,
+ E_CONTENT_EDITOR_COMMAND_REMOVE_FORMAT,
+ E_CONTENT_EDITOR_COMMAND_SELECT_ALL,
+ E_CONTENT_EDITOR_COMMAND_STRIKETHROUGH,
+ E_CONTENT_EDITOR_COMMAND_STYLE_WITH_CSS,
+ E_CONTENT_EDITOR_COMMAND_SUBSCRIPT,
+ E_CONTENT_EDITOR_COMMAND_SUPERSCRIPT,
+ E_CONTENT_EDITOR_COMMAND_TRANSPOSE,
+ E_CONTENT_EDITOR_COMMAND_UNDERLINE,
+ E_CONTENT_EDITOR_COMMAND_UNDO,
+ E_CONTENT_EDITOR_COMMAND_UNLINK,
+ E_CONTENT_EDITOR_COMMAND_UNSELECT,
+ E_CONTENT_EDITOR_COMMAND_USE_CSS
+} EContentEditorCommand;
/**
- * EImageLoadingPolicy:
- * @E_IMAGE_LOADING_POLICY_NEVER:
- * Never load images from a remote server.
- * @E_IMAGE_LOADING_POLICY_SOMETIMES:
- * Only load images from a remote server if the sender is a known contact.
- * @E_IMAGE_LOADING_POLICY_ALWAYS:
- * Always load images from a remote server.
+ * EContentEditorScope:
+ * @E_CONTENT_EDITOR_SCOPE_CELL:
+ * @E_CONTENT_EDITOR_SCOPE_ROW:
+ * @E_CONTENT_EDITOR_SCOPE_COLUMN:
+ * @E_CONTENT_EDITOR_SCOPE_TABLE:
*
- * Policy for loading remote image URLs in email. Allowing images to be
- * loaded from a remote server may have privacy implications.
+ * Since: 3.22
**/
typedef enum {
- E_IMAGE_LOADING_POLICY_NEVER,
- E_IMAGE_LOADING_POLICY_SOMETIMES,
- E_IMAGE_LOADING_POLICY_ALWAYS
-} EImageLoadingPolicy;
+ E_CONTENT_EDITOR_SCOPE_CELL = 0,
+ E_CONTENT_EDITOR_SCOPE_ROW,
+ E_CONTENT_EDITOR_SCOPE_COLUMN,
+ E_CONTENT_EDITOR_SCOPE_TABLE
+} EContentEditorScope;
+
+/**
+ * EContentEditorUnit:
+ * @E_CONTENT_EDITOR_UNIT_AUTO:
+ * @E_CONTENT_EDITOR_UNIT_PIXEL:
+ * @E_CONTENT_EDITOR_UNIT_PERCENTAGE:
+ *
+ * Since: 3.22
+ **/
+typedef enum {
+ E_CONTENT_EDITOR_UNIT_AUTO = 0,
+ E_CONTENT_EDITOR_UNIT_PIXEL,
+ E_CONTENT_EDITOR_UNIT_PERCENTAGE
+} EContentEditorUnit;
+
+/**
+ * EContentEditorCommand:
+ * @E_CONTENT_EDITOR_FIND_NEXT: Search for the next occurrence of the text.
+ * This is the default. It's mutually exclusive with @E_CONTENT_EDITOR_FIND_PREVIOUS.
+ * @E_CONTENT_EDITOR_FIND_PREVIOUS: Search for the previous occurrence of the text.
+ * It's mutually exclusive with @E_CONTENT_EDITOR_FIND_NEXT.
+ * @E_CONTENT_EDITOR_FIND_MODE_BACKWARDS: The search mode is backwards. If not set,
+ * then the mode is forward.
+ * @E_CONTENT_EDITOR_FIND_CASE_INSENSITIVE: Search case insensitively.
+ * @E_CONTENT_EDITOR_FIND_WRAP_AROUND: Wrap around when searching.
+ *
+ * Flags to use to modify behaviour of the search for the text.
+ *
+ * Since: 3.22
+ **/
+typedef enum {
+ E_CONTENT_EDITOR_FIND_NEXT = 1 << 0,
+ E_CONTENT_EDITOR_FIND_PREVIOUS = 1 << 1,
+ E_CONTENT_EDITOR_FIND_MODE_BACKWARDS = 1 << 2,
+ E_CONTENT_EDITOR_FIND_CASE_INSENSITIVE = 1 << 3,
+ E_CONTENT_EDITOR_FIND_WRAP_AROUND = 1 << 4
+} EContentEditorFindFlags;
G_END_DECLS
diff --git a/e-util/e-util.h b/e-util/e-util.h
index aa4bf14..8b3d163 100644
--- a/e-util/e-util.h
+++ b/e-util/e-util.h
@@ -32,7 +32,6 @@
#include <e-util/e-alert-sink.h>
#include <e-util/e-alert.h>
#include <e-util/e-attachment-bar.h>
-#include <e-util/e-attachment-button.h>
#include <e-util/e-attachment-dialog.h>
#include <e-util/e-attachment-handler-image.h>
#include <e-util/e-attachment-handler.h>
@@ -86,6 +85,8 @@
#include <e-util/e-config.h>
#include <e-util/e-conflict-search-selector.h>
#include <e-util/e-contact-store.h>
+#include <e-util/e-content-editor.h>
+#include <e-util/e-content-request.h>
#include <e-util/e-data-capture.h>
#include <e-util/e-dateedit.h>
#include <e-util/e-datetime-format.h>
@@ -111,6 +112,7 @@
#include <e-util/e-filter-part.h>
#include <e-util/e-filter-rule.h>
#include <e-util/e-focus-tracker.h>
+#ifndef E_UTIL_INCLUDE_WITHOUT_WEBKIT
#include <e-util/e-html-editor-actions.h>
#include <e-util/e-html-editor-cell-dialog.h>
#include <e-util/e-html-editor-dialog.h>
@@ -121,13 +123,11 @@
#include <e-util/e-html-editor-page-dialog.h>
#include <e-util/e-html-editor-paragraph-dialog.h>
#include <e-util/e-html-editor-replace-dialog.h>
-#include <e-util/e-html-editor-selection.h>
#include <e-util/e-html-editor-spell-check-dialog.h>
#include <e-util/e-html-editor-table-dialog.h>
#include <e-util/e-html-editor-text-dialog.h>
-#include <e-util/e-html-editor-utils.h>
-#include <e-util/e-html-editor-view.h>
#include <e-util/e-html-editor.h>
+#endif
#include <e-util/e-html-utils.h>
#include <e-util/e-icon-factory.h>
#include <e-util/e-image-chooser.h>
@@ -137,9 +137,11 @@
#include <e-util/e-interval-chooser.h>
#include <e-util/e-mail-identity-combo-box.h>
#include <e-util/e-mail-signature-combo-box.h>
+#ifndef E_UTIL_INCLUDE_WITHOUT_WEBKIT
#include <e-util/e-mail-signature-editor.h>
#include <e-util/e-mail-signature-manager.h>
#include <e-util/e-mail-signature-preview.h>
+#endif
#include <e-util/e-mail-signature-script-dialog.h>
#include <e-util/e-mail-signature-tree-view.h>
#include <e-util/e-map.h>
@@ -165,7 +167,9 @@
#include <e-util/e-popup-menu.h>
#include <e-util/e-port-entry.h>
#include <e-util/e-preferences-window.h>
+#ifndef E_UTIL_INCLUDE_WITHOUT_WEBKIT
#include <e-util/e-preview-pane.h>
+#endif
#include <e-util/e-print.h>
#include <e-util/e-printable.h>
#include <e-util/e-proxy-combo-box.h>
@@ -177,13 +181,16 @@
#include <e-util/e-reflow.h>
#include <e-util/e-rule-context.h>
#include <e-util/e-rule-editor.h>
+#ifndef E_UTIL_INCLUDE_WITHOUT_WEBKIT
#include <e-util/e-search-bar.h>
+#endif
#include <e-util/e-selectable.h>
#include <e-util/e-selection-model-array.h>
#include <e-util/e-selection-model-simple.h>
#include <e-util/e-selection-model.h>
#include <e-util/e-selection.h>
#include <e-util/e-send-options.h>
+#include <e-util/e-simple-async-result.h>
#include <e-util/e-sorter-array.h>
#include <e-util/e-sorter.h>
#include <e-util/e-source-combo-box.h>
@@ -194,6 +201,8 @@
#include <e-util/e-source-selector-dialog.h>
#include <e-util/e-source-selector.h>
#include <e-util/e-source-util.h>
+#include <e-util/e-spell-checker.h>
+#include <e-util/e-spell-dictionary.h>
#include <e-util/e-spell-entry.h>
#include <e-util/e-spell-text-view.h>
#include <e-util/e-spinner.h>
@@ -248,8 +257,10 @@
#include <e-util/e-url-entry.h>
#include <e-util/e-util-enums.h>
#include <e-util/e-util-enumtypes.h>
+#ifndef E_UTIL_INCLUDE_WITHOUT_WEBKIT
#include <e-util/e-web-view-preview.h>
#include <e-util/e-web-view.h>
+#endif
#include <e-util/e-widget-undo.h>
#include <e-util/e-xml-utils.h>
#include <e-util/ea-cell-table.h>
diff --git a/e-util/e-web-view-preview.c b/e-util/e-web-view-preview.c
index 4ad30a0..13fd32d 100644
--- a/e-util/e-web-view-preview.c
+++ b/e-util/e-web-view-preview.c
@@ -173,7 +173,7 @@ in_scrolled_window (GtkWidget *widget)
static void
e_web_view_preview_init (EWebViewPreview *preview)
{
- GtkWidget *tree_view_sw, *web_view_sw;
+ GtkWidget *tree_view_sw, *web_view;
preview->priv = E_WEB_VIEW_PREVIEW_GET_PRIVATE (preview);
preview->priv->escape_values = TRUE;
@@ -181,13 +181,13 @@ e_web_view_preview_init (EWebViewPreview *preview)
gtk_orientable_set_orientation (GTK_ORIENTABLE (preview), GTK_ORIENTATION_VERTICAL);
tree_view_sw = in_scrolled_window (gtk_tree_view_new ());
- web_view_sw = in_scrolled_window (e_web_view_new ());
+ web_view = e_web_view_new ();
gtk_widget_hide (tree_view_sw);
- gtk_widget_show (web_view_sw);
+ gtk_widget_show (web_view);
gtk_paned_pack1 (GTK_PANED (preview), tree_view_sw, FALSE, TRUE);
- gtk_paned_pack2 (GTK_PANED (preview), web_view_sw, TRUE, TRUE);
+ gtk_paned_pack2 (GTK_PANED (preview), web_view, TRUE, TRUE);
/* rawly 3 lines of a text plus a little bit more */
if (gtk_paned_get_position (GTK_PANED (preview)) < 85)
@@ -213,7 +213,7 @@ e_web_view_preview_get_preview (EWebViewPreview *preview)
{
g_return_val_if_fail (E_IS_WEB_VIEW_PREVIEW (preview), NULL);
- return gtk_bin_get_child (GTK_BIN (gtk_paned_get_child2 (GTK_PANED (preview))));
+ return gtk_paned_get_child2 (GTK_PANED (preview));
}
void
@@ -225,7 +225,7 @@ e_web_view_preview_set_preview (EWebViewPreview *preview,
g_return_if_fail (E_IS_WEB_VIEW_PREVIEW (preview));
g_return_if_fail (GTK_IS_WIDGET (preview_widget));
- old_child = gtk_bin_get_child (GTK_BIN (gtk_paned_get_child2 (GTK_PANED (preview))));
+ old_child = gtk_paned_get_child2 (GTK_PANED (preview));
if (old_child) {
g_return_if_fail (old_child != preview_widget);
gtk_widget_destroy (old_child);
diff --git a/e-util/e-web-view.c b/e-util/e-web-view.c
index 42af88f..011ac27 100644
--- a/e-util/e-web-view.c
+++ b/e-util/e-web-view.c
@@ -40,18 +40,19 @@
#include "e-selectable.h"
#include "e-stock-request.h"
+#include <web-extensions/e-web-extension-names.h>
+
#define E_WEB_VIEW_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE \
((obj), E_TYPE_WEB_VIEW, EWebViewPrivate))
-typedef enum {
- E_WEB_VIEW_ZOOM_HACK_STATE_NONE,
- E_WEB_VIEW_ZOOM_HACK_STATE_ZOOMED_IN,
- E_WEB_VIEW_ZOOM_HACK_STATE_ZOOMED_OUT
-} EWebViewZoomHackState;
-
typedef struct _AsyncContext AsyncContext;
+typedef struct _ElementClickedData {
+ EWebViewElementClickedFunc callback;
+ gpointer user_data;
+} ElementClickedData;
+
struct _EWebViewPrivate {
GtkUIManager *ui_manager;
gchar *selected_uri;
@@ -78,17 +79,27 @@ struct _EWebViewPrivate {
GHashTable *old_settings;
- /* To workaround webkit bug:
- * https://bugs.webkit.org/show_bug.cgi?id=89553 */
- EWebViewZoomHackState zoom_hack_state;
+ GDBusProxy *web_extension;
+ guint web_extension_watch_name_id;
+
+ WebKitFindController *find_controller;
+ gulong found_text_handler_id;
+ gulong failed_to_find_text_handler_id;
gboolean has_hover_link;
+
+ GSList *content_requests; /* EContentRequest * */
+
+ GHashTable *element_clicked_cbs; /* gchar *element_class ~> GPtrArray {ElementClickedData} */
+ guint web_extension_element_clicked_signal_id;
};
struct _AsyncContext {
EActivity *activity;
GFile *destination;
GInputStream *input_stream;
+ EContentRequest *content_request;
+ gchar *uri;
};
enum {
@@ -99,6 +110,7 @@ enum {
PROP_DISABLE_PRINTING,
PROP_DISABLE_SAVE_TO_DISK,
PROP_OPEN_PROXY,
+ PROP_PASTE_TARGET_LIST,
PROP_PRINT_PROXY,
PROP_SAVE_AS_PROXY,
PROP_SELECTED_URI
@@ -111,11 +123,11 @@ enum {
STOP_LOADING,
UPDATE_ACTIONS,
PROCESS_MAILTO,
+ URI_REQUESTED,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL];
-static GOnce disable_webkit_3rd_party_plugins_once = G_ONCE_INIT;
static const gchar *ui =
"<ui>"
@@ -161,11 +173,18 @@ G_DEFINE_TYPE_WITH_CODE (
e_web_view_selectable_init))
static void
-async_context_free (AsyncContext *async_context)
+async_context_free (gpointer ptr)
{
+ AsyncContext *async_context = ptr;
+
+ if (!async_context)
+ return;
+
g_clear_object (&async_context->activity);
g_clear_object (&async_context->destination);
g_clear_object (&async_context->input_stream);
+ g_clear_object (&async_context->content_request);
+ g_free (async_context->uri);
g_slice_free (AsyncContext, async_context);
}
@@ -393,38 +412,6 @@ static GtkActionEntry standard_entries[] = {
};
static void
-web_view_init_web_settings (WebKitWebView *web_view)
-{
- WebKitWebSettings *web_settings;
-
- web_settings = webkit_web_settings_new ();
-
- g_object_set (
- G_OBJECT (web_settings),
- "default-encoding", "UTF-8",
- "enable-dns-prefetching", FALSE,
- "enable-frame-flattening", TRUE,
- "enable-java-applet", FALSE,
- "enable-html5-database", FALSE,
- "enable-html5-local-storage", FALSE,
- "enable-offline-web-application-cache", FALSE,
- "enable-site-specific-quirks", TRUE,
- "enable-scripts", FALSE,
- "respect-image-orientation", TRUE,
- NULL);
-
- e_binding_bind_property (
- web_settings, "enable-caret-browsing",
- web_view, "caret-mode",
- G_BINDING_BIDIRECTIONAL |
- G_BINDING_SYNC_CREATE);
-
- webkit_web_view_set_settings (web_view, web_settings);
-
- g_object_unref (web_settings);
-}
-
-static void
web_view_menu_item_select_cb (EWebView *web_view,
GtkWidget *widget)
{
@@ -443,20 +430,51 @@ web_view_menu_item_select_cb (EWebView *web_view,
}
static void
+webkit_find_controller_found_text_cb (WebKitFindController *find_controller,
+ guint match_count,
+ EWebView *web_view)
+{
+}
+
+static void
+webkit_find_controller_failed_to_found_text_cb (WebKitFindController *find_controller,
+ EWebView *web_view)
+{
+}
+
+static void
+web_view_set_find_controller (EWebView *web_view)
+{
+ WebKitFindController *find_controller;
+
+ find_controller =
+ webkit_web_view_get_find_controller (WEBKIT_WEB_VIEW (web_view));
+
+ web_view->priv->found_text_handler_id = g_signal_connect (
+ find_controller, "found-text",
+ G_CALLBACK (webkit_find_controller_found_text_cb), web_view);
+
+ web_view->priv->failed_to_find_text_handler_id = g_signal_connect (
+ find_controller, "failed-to-find-text",
+ G_CALLBACK (webkit_find_controller_failed_to_found_text_cb), web_view);
+
+ web_view->priv->find_controller = find_controller;
+}
+
+static void
web_view_update_document_highlights (EWebView *web_view)
{
- WebKitWebView *webkit_web_view;
GList *head, *link;
- webkit_web_view = WEBKIT_WEB_VIEW (web_view);
-
head = g_queue_peek_head_link (&web_view->priv->highlights);
- for (link = head; link != NULL; link = g_list_next (link))
- webkit_web_view_mark_text_matches (
- webkit_web_view, link->data, FALSE, 0);
-
- webkit_web_view_set_highlight_text_matches (webkit_web_view, TRUE);
+ for (link = head; link != NULL; link = g_list_next (link)) {
+ webkit_find_controller_search (
+ web_view->priv->find_controller,
+ link->data,
+ WEBKIT_FIND_OPTIONS_NONE,
+ G_MAXUINT);
+ }
}
static void
@@ -484,9 +502,10 @@ web_view_connect_proxy_cb (EWebView *web_view,
static gboolean
web_view_context_menu_cb (WebKitWebView *webkit_web_view,
- GtkWidget *default_menu,
+ WebKitContextMenu *context_menu,
+ GdkEvent *event,
WebKitHitTestResult *hit_test_result,
- gboolean triggered_with_keyboard)
+ gpointer user_data)
{
WebKitHitTestResultContext context;
EWebView *web_view;
@@ -501,7 +520,7 @@ web_view_context_menu_cb (WebKitWebView *webkit_web_view,
if (hit_test_result == NULL)
return FALSE;
- g_object_get (hit_test_result, "context", &context, NULL);
+ context = webkit_hit_test_result_get_context (hit_test_result);
if (context & WEBKIT_HIT_TEST_RESULT_CONTEXT_IMAGE) {
gchar *image_uri = NULL;
@@ -527,30 +546,17 @@ web_view_context_menu_cb (WebKitWebView *webkit_web_view,
return event_handled;
}
-static GtkWidget *
-web_view_create_plugin_widget_cb (EWebView *web_view,
- const gchar *mime_type,
- const gchar *uri,
- GHashTable *param)
-{
- EWebViewClass *class;
-
- /* XXX WebKitWebView does not provide a class method for
- * this signal, so we do so we can override the default
- * behavior from subclasses for special URI types. */
-
- class = E_WEB_VIEW_GET_CLASS (web_view);
- g_return_val_if_fail (class->create_plugin_widget != NULL, NULL);
-
- return class->create_plugin_widget (web_view, mime_type, uri, param);
-}
-
static void
-web_view_hovering_over_link_cb (EWebView *web_view,
- const gchar *title,
- const gchar *uri)
+web_view_mouse_target_changed_cb (EWebView *web_view,
+ WebKitHitTestResult *hit_test_result,
+ guint modifiers,
+ gpointer user_data)
{
EWebViewClass *class;
+ const gchar *title, *uri;
+
+ title = webkit_hit_test_result_get_link_title (hit_test_result);
+ uri = webkit_hit_test_result_get_link_uri (hit_test_result);
web_view->priv->has_hover_link = uri && *uri;
@@ -565,55 +571,60 @@ web_view_hovering_over_link_cb (EWebView *web_view,
}
static gboolean
-web_view_navigation_policy_decision_requested_cb (EWebView *web_view,
- WebKitWebFrame *frame,
- WebKitNetworkRequest *request,
- WebKitWebNavigationAction *navigation_action,
- WebKitWebPolicyDecision *policy_decision)
+web_view_decide_policy_cb (EWebView *web_view,
+ WebKitPolicyDecision *decision,
+ WebKitPolicyDecisionType type)
{
EWebViewClass *class;
- WebKitWebNavigationReason reason;
- const gchar *uri, *frame_uri;
+ WebKitNavigationPolicyDecision *navigation_decision;
+ WebKitNavigationAction *navigation_action;
+ WebKitNavigationType navigation_type;
+ WebKitURIRequest *request;
+ const gchar *uri, *view_uri;
+
+ if (type != WEBKIT_POLICY_DECISION_TYPE_NAVIGATION_ACTION &&
+ type != WEBKIT_POLICY_DECISION_TYPE_NEW_WINDOW_ACTION)
+ return FALSE;
+
+ navigation_decision = WEBKIT_NAVIGATION_POLICY_DECISION (decision);
+ navigation_action = webkit_navigation_policy_decision_get_navigation_action (navigation_decision);
+ navigation_type = webkit_navigation_action_get_navigation_type (navigation_action);
- reason = webkit_web_navigation_action_get_reason (navigation_action);
- if (reason != WEBKIT_WEB_NAVIGATION_REASON_LINK_CLICKED)
+ if (navigation_type != WEBKIT_NAVIGATION_TYPE_LINK_CLICKED)
return FALSE;
- uri = webkit_network_request_get_uri (request);
- frame_uri = webkit_web_frame_get_uri (frame);
+ request = webkit_navigation_action_get_request (navigation_action);
+ uri = webkit_uri_request_get_uri (request);
+ view_uri = webkit_web_view_get_uri (WEBKIT_WEB_VIEW (web_view));
/* Allow navigation through fragments in page */
- if (uri && *uri && frame_uri && *frame_uri) {
- SoupURI *uri_link, *uri_frame;
+ if (uri && *uri && view_uri && *view_uri) {
+ SoupURI *uri_link, *uri_view;
uri_link = soup_uri_new (uri);
- uri_frame = soup_uri_new (frame_uri);
- if (uri_link && uri_frame) {
+ uri_view = soup_uri_new (view_uri);
+ if (uri_link && uri_view) {
const gchar *tmp1, *tmp2;
tmp1 = soup_uri_get_scheme (uri_link);
- tmp2 = soup_uri_get_scheme (uri_frame);
+ tmp2 = soup_uri_get_scheme (uri_view);
/* The scheme on both URIs should be the same */
- if (tmp1 && tmp2) {
- if (g_ascii_strcasecmp (tmp1, tmp2) != 0)
- goto free_uris;
- }
+ if (tmp1 && tmp2 && g_ascii_strcasecmp (tmp1, tmp2) != 0)
+ goto free_uris;
tmp1 = soup_uri_get_host (uri_link);
- tmp2 = soup_uri_get_host (uri_frame);
+ tmp2 = soup_uri_get_host (uri_view);
/* The host on both URIs should be the same */
- if (tmp1 && tmp2) {
- if (g_ascii_strcasecmp (tmp1, tmp2) != 0)
- goto free_uris;
- }
+ if (tmp1 && tmp2 && g_ascii_strcasecmp (tmp1, tmp2) != 0)
+ goto free_uris;
/* URI from link should have fragment set - could be empty */
if (soup_uri_get_fragment (uri_link)) {
soup_uri_free (uri_link);
- soup_uri_free (uri_frame);
- webkit_web_policy_decision_use (policy_decision);
+ soup_uri_free (uri_view);
+ webkit_policy_decision_use (decision);
return TRUE;
}
}
@@ -621,8 +632,8 @@ web_view_navigation_policy_decision_requested_cb (EWebView *web_view,
free_uris:
if (uri_link)
soup_uri_free (uri_link);
- if (uri_frame)
- soup_uri_free (uri_frame);
+ if (uri_view)
+ soup_uri_free (uri_view);
}
/* XXX WebKitWebView does not provide a class method for
@@ -632,7 +643,7 @@ web_view_navigation_policy_decision_requested_cb (EWebView *web_view,
class = E_WEB_VIEW_GET_CLASS (web_view);
g_return_val_if_fail (class->link_clicked != NULL, FALSE);
- webkit_web_policy_decision_ignore (policy_decision);
+ webkit_policy_decision_ignore (decision);
class->link_clicked (web_view, uri);
@@ -665,7 +676,7 @@ style_updated_cb (EWebView *web_view)
e_web_view_add_css_rule_into_style_sheet (
web_view,
- "-e-web-view-css-sheet",
+ "-e-web-view-style-sheet",
".-e-web-view-background-color",
style);
@@ -684,7 +695,7 @@ style_updated_cb (EWebView *web_view)
e_web_view_add_css_rule_into_style_sheet (
web_view,
- "-e-web-view-css-sheet",
+ "-e-web-view-style-sheet",
".-e-web-view-text-color",
style);
@@ -693,60 +704,63 @@ style_updated_cb (EWebView *web_view)
}
static void
-web_view_load_status_changed_cb (WebKitWebView *webkit_web_view,
- GParamSpec *pspec,
- gpointer user_data)
+web_view_load_changed_cb (WebKitWebView *webkit_web_view,
+ WebKitLoadEvent load_event,
+ gpointer user_data)
{
- WebKitLoadStatus status;
EWebView *web_view;
web_view = E_WEB_VIEW (webkit_web_view);
- status = webkit_web_view_get_load_status (webkit_web_view);
-
- if (web_view->priv->zoom_hack_state == E_WEB_VIEW_ZOOM_HACK_STATE_NONE &&
- status == WEBKIT_LOAD_COMMITTED) {
- if (webkit_web_view_get_zoom_level (WEBKIT_WEB_VIEW (web_view)) > 0.9999) {
- e_web_view_zoom_out (web_view);
- web_view->priv->zoom_hack_state = E_WEB_VIEW_ZOOM_HACK_STATE_ZOOMED_OUT;
- } else {
- e_web_view_zoom_in (web_view);
- web_view->priv->zoom_hack_state = E_WEB_VIEW_ZOOM_HACK_STATE_ZOOMED_IN;
- }
- } else if (web_view->priv->zoom_hack_state != E_WEB_VIEW_ZOOM_HACK_STATE_NONE &&
- status == WEBKIT_LOAD_FAILED) {
- if (web_view->priv->zoom_hack_state == E_WEB_VIEW_ZOOM_HACK_STATE_ZOOMED_IN)
- e_web_view_zoom_out (web_view);
- else
- e_web_view_zoom_in (web_view);
-
- web_view->priv->zoom_hack_state = E_WEB_VIEW_ZOOM_HACK_STATE_NONE;
- }
+ if (load_event == WEBKIT_LOAD_STARTED)
+ g_hash_table_remove_all (web_view->priv->element_clicked_cbs);
- if (status != WEBKIT_LOAD_FINISHED)
+ if (load_event != WEBKIT_LOAD_FINISHED)
return;
style_updated_cb (web_view);
web_view_update_document_highlights (web_view);
+}
- if (web_view->priv->zoom_hack_state == E_WEB_VIEW_ZOOM_HACK_STATE_NONE) {
- /* This may not happen, but just in case keep it here. */
- if (webkit_web_view_get_zoom_level (WEBKIT_WEB_VIEW (web_view)) > 0.9999) {
- e_web_view_zoom_out (web_view);
- e_web_view_zoom_in (web_view);
- } else {
- e_web_view_zoom_in (web_view);
- e_web_view_zoom_out (web_view);
- }
- } else {
- if (web_view->priv->zoom_hack_state == E_WEB_VIEW_ZOOM_HACK_STATE_ZOOMED_IN)
- e_web_view_zoom_out (web_view);
- else
- e_web_view_zoom_in (web_view);
+static GObjectConstructParam*
+find_property (guint n_properties,
+ GObjectConstructParam* properties,
+ GParamSpec* param_spec)
+{
+ while (n_properties--) {
+ if (properties->pspec == param_spec)
+ return properties;
+ properties++;
+ }
+
+ return NULL;
+}
- web_view->priv->zoom_hack_state = E_WEB_VIEW_ZOOM_HACK_STATE_NONE;
+static GObject*
+web_view_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_properties)
+{
+ GObjectClass* object_class;
+ GParamSpec* param_spec;
+ GObjectConstructParam *param = NULL;
+
+ object_class = G_OBJECT_CLASS (g_type_class_ref(type));
+ g_return_val_if_fail (object_class != NULL, NULL);
+
+ if (construct_properties && n_construct_properties != 0) {
+ param_spec = g_object_class_find_property (object_class, "settings");
+ if ((param = find_property (n_construct_properties, construct_properties, param_spec)))
+ g_value_take_object (param->value, e_web_view_get_default_webkit_settings ());
+ param_spec = g_object_class_find_property(object_class, "user-content-manager");
+ if ((param = find_property (n_construct_properties, construct_properties, param_spec)))
+ g_value_take_object (param->value, webkit_user_content_manager_new ());
}
+
+ g_type_class_unref (object_class);
+
+ return G_OBJECT_CLASS (e_web_view_parent_class)->constructor(type, n_construct_properties,
construct_properties);
}
static void
@@ -762,6 +776,11 @@ web_view_set_property (GObject *object,
g_value_get_boolean (value));
return;
+ case PROP_COPY_TARGET_LIST:
+ /* This is a fake property. */
+ g_warning ("%s: EWebView::copy-target-list not used", G_STRFUNC);
+ return;
+
case PROP_CURSOR_IMAGE_SRC:
e_web_view_set_cursor_image_src (
E_WEB_VIEW (object),
@@ -786,6 +805,11 @@ web_view_set_property (GObject *object,
g_value_get_object (value));
return;
+ case PROP_PASTE_TARGET_LIST:
+ /* This is a fake property. */
+ g_warning ("%s: EWebView::paste-target-list not used", G_STRFUNC);
+ return;
+
case PROP_PRINT_PROXY:
e_web_view_set_print_proxy (
E_WEB_VIEW (object),
@@ -820,6 +844,11 @@ web_view_get_property (GObject *object,
E_WEB_VIEW (object)));
return;
+ case PROP_COPY_TARGET_LIST:
+ /* This is a fake property. */
+ g_value_set_boxed (value, NULL);
+ return;
+
case PROP_CURSOR_IMAGE_SRC:
g_value_set_string (
value, e_web_view_get_cursor_image_src (
@@ -844,6 +873,11 @@ web_view_get_property (GObject *object,
E_WEB_VIEW (object)));
return;
+ case PROP_PASTE_TARGET_LIST:
+ /* This is a fake property. */
+ g_value_set_boxed (value, NULL);
+ return;
+
case PROP_PRINT_PROXY:
g_value_set_object (
value, e_web_view_get_print_proxy (
@@ -895,12 +929,44 @@ web_view_dispose (GObject *object)
priv->antialiasing_changed_handler_id = 0;
}
+ if (priv->web_extension_watch_name_id > 0) {
+ g_bus_unwatch_name (priv->web_extension_watch_name_id);
+ priv->web_extension_watch_name_id = 0;
+ }
+
+ if (priv->found_text_handler_id > 0) {
+ g_signal_handler_disconnect (
+ priv->find_controller,
+ priv->found_text_handler_id);
+ priv->found_text_handler_id = 0;
+ }
+
+ if (priv->failed_to_find_text_handler_id > 0) {
+ g_signal_handler_disconnect (
+ priv->find_controller,
+ priv->failed_to_find_text_handler_id);
+ priv->failed_to_find_text_handler_id = 0;
+ }
+
+ if (priv->web_extension && priv->web_extension_element_clicked_signal_id) {
+ g_dbus_connection_signal_unsubscribe (
+ g_dbus_proxy_get_connection (priv->web_extension),
+ priv->web_extension_element_clicked_signal_id);
+ priv->web_extension_element_clicked_signal_id = 0;
+ }
+
+ g_hash_table_remove_all (priv->element_clicked_cbs);
+
+ g_slist_free_full (priv->content_requests, g_object_unref);
+ priv->content_requests = NULL;
+
g_clear_object (&priv->ui_manager);
g_clear_object (&priv->open_proxy);
g_clear_object (&priv->print_proxy);
g_clear_object (&priv->save_as_proxy);
g_clear_object (&priv->aliasing_settings);
g_clear_object (&priv->font_settings);
+ g_clear_object (&priv->web_extension);
/* Chain up to parent's dispose() method. */
G_OBJECT_CLASS (e_web_view_parent_class)->dispose (object);
@@ -924,13 +990,149 @@ web_view_finalize (GObject *object)
priv->old_settings = NULL;
}
+ g_hash_table_destroy (priv->element_clicked_cbs);
+
/* Chain up to parent's finalize() method. */
G_OBJECT_CLASS (e_web_view_parent_class)->finalize (object);
}
+
+static void
+web_view_uri_request_done_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ WebKitURISchemeRequest *request = user_data;
+ GInputStream *stream = NULL;
+ gint64 stream_length = -1;
+ gchar *mime_type = NULL;
+ GError *error = NULL;
+
+ g_return_if_fail (E_IS_CONTENT_REQUEST (source_object));
+ g_return_if_fail (WEBKIT_IS_URI_SCHEME_REQUEST (request));
+
+ if (!e_content_request_process_finish (E_CONTENT_REQUEST (source_object),
+ result, &stream, &stream_length, &mime_type, &error)) {
+ webkit_uri_scheme_request_finish_error (request, error);
+ } else {
+ webkit_uri_scheme_request_finish (request, stream, stream_length, mime_type);
+
+ g_clear_object (&stream);
+ g_free (mime_type);
+ }
+
+ g_object_unref (request);
+}
+
+static void
+web_view_process_uri_request_cb (WebKitURISchemeRequest *request,
+ gpointer user_data)
+{
+ EContentRequest *content_request = user_data;
+ const gchar *uri;
+ gchar *redirect_to_uri = NULL;
+ GObject *requester;
+
+ g_return_if_fail (WEBKIT_IS_URI_SCHEME_REQUEST (request));
+ g_return_if_fail (E_IS_CONTENT_REQUEST (content_request));
+
+ uri = webkit_uri_scheme_request_get_uri (request);
+ requester = G_OBJECT (webkit_uri_scheme_request_get_web_view (request));
+
+ g_return_if_fail (e_content_request_can_process_uri (content_request, uri));
+
+ if (E_IS_WEB_VIEW (requester)) {
+ /* Expects an empty string to abandon the request,
+ or NULL to keep the passed-in uri,
+ or a new uri to load instead. */
+ g_signal_emit (requester, signals[URI_REQUESTED], 0, uri, &redirect_to_uri);
+
+ if (redirect_to_uri && *redirect_to_uri) {
+ uri = redirect_to_uri;
+ } else if (redirect_to_uri) {
+ GError *error;
+
+ g_free (redirect_to_uri);
+
+ error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_CANCELLED, "Cancelled");
+
+ webkit_uri_scheme_request_finish_error (request, error);
+ return;
+ }
+ }
+
+ e_content_request_process (content_request, uri, requester, NULL,
+ web_view_uri_request_done_cb, g_object_ref (request));
+
+ g_free (redirect_to_uri);
+}
+
+/* 'scheme' is like "file", not "file:" */
+void
+e_web_view_register_content_request_for_scheme (EWebView *web_view,
+ const gchar *scheme,
+ EContentRequest *content_request)
+{
+ WebKitWebContext *web_context;
+
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+ g_return_if_fail (E_IS_CONTENT_REQUEST (content_request));
+ g_return_if_fail (scheme != NULL);
+
+ web_context = webkit_web_view_get_context (WEBKIT_WEB_VIEW (web_view));
+
+ webkit_web_context_register_uri_scheme (web_context, scheme, web_view_process_uri_request_cb,
+ g_object_ref (content_request), g_object_unref);
+
+ if (!g_slist_find (web_view->priv->content_requests, content_request)) {
+ web_view->priv->content_requests = g_slist_prepend (
+ web_view->priv->content_requests,
+ g_object_ref (content_request));
+ }
+}
+
+static void
+web_view_initialize (WebKitWebView *web_view)
+{
+ WebKitWebContext *web_context;
+ EContentRequest *content_request;
+ const gchar *id = "org.gnome.settings-daemon.plugins.xsettings";
+ GSettings *settings = NULL, *font_settings;
+ GSettingsSchema *settings_schema;
+
+ web_context = webkit_web_view_get_context (web_view);
+
+ webkit_web_context_set_cache_model (web_context, WEBKIT_CACHE_MODEL_DOCUMENT_VIEWER);
+
+ content_request = e_file_request_new ();
+ e_web_view_register_content_request_for_scheme (E_WEB_VIEW (web_view), "evo-file", content_request);
+ g_object_unref (content_request);
+
+ content_request = e_stock_request_new ();
+ e_web_view_register_content_request_for_scheme (E_WEB_VIEW (web_view), "gtk-stock", content_request);
+ g_object_unref (content_request);
+
+ /* Optional schema */
+ settings_schema = g_settings_schema_source_lookup (
+ g_settings_schema_source_get_default (), id, FALSE);
+
+ if (settings_schema)
+ settings = e_util_ref_settings (id);
+
+ font_settings = e_util_ref_settings ("org.gnome.desktop.interface");
+ e_web_view_update_fonts_settings (
+ font_settings, settings, NULL, NULL, GTK_WIDGET (web_view));
+
+ g_object_unref (font_settings);
+ if (settings)
+ g_object_unref (settings);
+}
+
+
static void
web_view_constructed (GObject *object)
{
+ WebKitSettings *web_settings;
#ifndef G_OS_WIN32
GSettings *settings;
@@ -953,6 +1155,23 @@ web_view_constructed (GObject *object)
/* Chain up to parent's constructed() method. */
G_OBJECT_CLASS (e_web_view_parent_class)->constructed (object);
+
+ web_settings = webkit_web_view_get_settings (WEBKIT_WEB_VIEW (object));
+
+ g_object_set (
+ G_OBJECT (web_settings),
+ "default-charset", "UTF-8",
+ NULL);
+
+ e_binding_bind_property (
+ web_settings, "enable-caret-browsing",
+ E_WEB_VIEW (object), "caret-mode",
+ G_BINDING_BIDIRECTIONAL |
+ G_BINDING_SYNC_CREATE);
+
+ web_view_initialize (WEBKIT_WEB_VIEW (object));
+
+ web_view_set_find_controller (E_WEB_VIEW (object));
}
static gboolean
@@ -992,7 +1211,8 @@ web_view_scroll_event (GtkWidget *widget,
}
}
- return FALSE;
+ return GTK_WIDGET_CLASS (e_web_view_parent_class)->
+ scroll_event (widget, event);
}
static gboolean
@@ -1146,9 +1366,8 @@ web_view_load_string (EWebView *web_view,
if (string == NULL)
string = "";
- webkit_web_view_load_string (
- WEBKIT_WEB_VIEW (web_view),
- string, "text/html", "UTF-8", "evo-file:///");
+ webkit_web_view_load_html (
+ WEBKIT_WEB_VIEW (web_view), string, "evo-file:///");
}
static void
@@ -1162,13 +1381,6 @@ web_view_load_uri (EWebView *web_view,
}
static gchar *
-web_view_redirect_uri (EWebView *web_view,
- const gchar *uri)
-{
- return g_strdup (uri);
-}
-
-static gchar *
web_view_suggest_filename (EWebView *web_view,
const gchar *uri)
{
@@ -1204,8 +1416,164 @@ web_view_stop_loading (EWebView *web_view)
}
static void
-web_view_update_actions (EWebView *web_view)
+web_view_register_element_clicked_hfunc (gpointer key,
+ gpointer value,
+ gpointer user_data)
+{
+ const gchar *elem_class = key;
+ EWebView *web_view = user_data;
+
+ g_return_if_fail (elem_class && *elem_class);
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+ if (!web_view->priv->web_extension)
+ return;
+
+ g_dbus_proxy_call (
+ web_view->priv->web_extension,
+ "RegisterElementClicked",
+ g_variant_new (
+ "(ts)",
+ webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (web_view)),
+ elem_class),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+}
+
+static void
+web_view_element_clicked_signal_cb (GDBusConnection *connection,
+ const gchar *sender_name,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *signal_name,
+ GVariant *parameters,
+ gpointer user_data)
{
+ EWebView *web_view = user_data;
+ const gchar *elem_class = NULL, *elem_value = NULL;
+ GtkAllocation elem_position;
+ guint64 page_id = 0;
+ gint position_left = 0, position_top = 0, position_width = 0, position_height = 0;
+ GPtrArray *listeners;
+
+ if (g_strcmp0 (signal_name, "ElementClicked") != 0)
+ return;
+
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+ if (!parameters)
+ return;
+
+ g_variant_get (parameters, "(t&s&siiii)", &page_id, &elem_class, &elem_value, &position_left,
&position_top, &position_width, &position_height);
+
+ if (!elem_class || !*elem_class || page_id != webkit_web_view_get_page_id (WEBKIT_WEB_VIEW
(web_view)))
+ return;
+
+ elem_position.x = position_left;
+ elem_position.y = position_top;
+ elem_position.width = position_width;
+ elem_position.height = position_height;
+
+ listeners = g_hash_table_lookup (web_view->priv->element_clicked_cbs, elem_class);
+ if (listeners) {
+ guint ii;
+
+ for (ii = 0; ii <listeners->len; ii++) {
+ ElementClickedData *ecd = g_ptr_array_index (listeners, ii);
+
+ if (ecd && ecd->callback)
+ ecd->callback (web_view, elem_class, elem_value, &elem_position,
ecd->user_data);
+ }
+ }
+}
+
+static void
+web_extension_proxy_created_cb (GDBusProxy *proxy,
+ GAsyncResult *result,
+ EWebView *web_view)
+{
+ GError *error = NULL;
+
+ web_view->priv->web_extension = g_dbus_proxy_new_finish (result, &error);
+ if (!web_view->priv->web_extension) {
+ g_warning ("Error creating web extension proxy: %s\n", error->message);
+ g_error_free (error);
+ } else {
+ web_view->priv->web_extension_element_clicked_signal_id =
+ g_dbus_connection_signal_subscribe (
+ g_dbus_proxy_get_connection (web_view->priv->web_extension),
+ g_dbus_proxy_get_name (web_view->priv->web_extension),
+ E_WEB_EXTENSION_INTERFACE,
+ "ElementClicked",
+ E_WEB_EXTENSION_OBJECT_PATH,
+ NULL,
+ G_DBUS_SIGNAL_FLAGS_NONE,
+ web_view_element_clicked_signal_cb,
+ web_view,
+ NULL);
+
+ g_hash_table_foreach (web_view->priv->element_clicked_cbs,
web_view_register_element_clicked_hfunc, web_view);
+ }
+}
+
+static void
+web_extension_appeared_cb (GDBusConnection *connection,
+ const gchar *name,
+ const gchar *name_owner,
+ EWebView *web_view)
+{
+ g_dbus_proxy_new (
+ connection,
+ G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START |
+ G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
+ NULL,
+ name,
+ E_WEB_EXTENSION_OBJECT_PATH,
+ E_WEB_EXTENSION_INTERFACE,
+ NULL,
+ (GAsyncReadyCallback) web_extension_proxy_created_cb,
+ web_view);
+}
+
+static void
+web_extension_vanished_cb (GDBusConnection *connection,
+ const gchar *name,
+ EWebView *web_view)
+{
+ g_clear_object (&web_view->priv->web_extension);
+}
+
+static void
+web_view_watch_web_extension (EWebView *web_view)
+{
+ web_view->priv->web_extension_watch_name_id =
+ g_bus_watch_name (
+ G_BUS_TYPE_SESSION,
+ E_WEB_EXTENSION_SERVICE_NAME,
+ G_BUS_NAME_WATCHER_FLAGS_NONE,
+ (GBusNameAppearedCallback) web_extension_appeared_cb,
+ (GBusNameVanishedCallback) web_extension_vanished_cb,
+ web_view,
+ NULL);
+}
+
+GDBusProxy *
+e_web_view_get_web_extension_proxy (EWebView *web_view)
+{
+ g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
+
+ return web_view->priv->web_extension;
+}
+
+static void
+web_view_update_actions_cb (WebKitWebView *webkit_web_view,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ EWebView *web_view;
GtkActionGroup *action_group;
gboolean can_copy;
gboolean scheme_is_http = FALSE;
@@ -1216,8 +1584,11 @@ web_view_update_actions (EWebView *web_view)
const gchar *group_name;
const gchar *uri;
+ web_view = E_WEB_VIEW (webkit_web_view);
+
uri = e_web_view_get_selected_uri (web_view);
- can_copy = webkit_web_view_can_copy_clipboard (WEBKIT_WEB_VIEW (web_view));
+ can_copy = webkit_web_view_can_execute_editing_command_finish (
+ webkit_web_view, result, NULL);
cursor_image_src = e_web_view_get_cursor_image_src (web_view);
/* Parse the URI early so we know if the actions will work. */
@@ -1301,6 +1672,17 @@ web_view_update_actions (EWebView *web_view)
}
static void
+web_view_update_actions (EWebView *web_view)
+{
+ webkit_web_view_can_execute_editing_command (
+ WEBKIT_WEB_VIEW (web_view),
+ WEBKIT_EDITING_COMMAND_COPY,
+ NULL, /* cancellable */
+ (GAsyncReadyCallback) web_view_update_actions_cb,
+ NULL);
+}
+
+static void
web_view_submit_alert (EAlertSink *alert_sink,
EAlert *alert)
{
@@ -1397,6 +1779,19 @@ web_view_submit_alert (EAlertSink *alert_sink,
}
static void
+web_view_can_execute_editing_command_cb (WebKitWebView *webkit_web_view,
+ GAsyncResult *result,
+ GtkAction *action)
+{
+ gboolean can_do_command;
+
+ can_do_command = webkit_web_view_can_execute_editing_command_finish (
+ webkit_web_view, result, NULL);
+
+ gtk_action_set_sensitive (action, can_do_command);
+}
+
+static void
web_view_selectable_update_actions (ESelectable *selectable,
EFocusTracker *focus_tracker,
GdkAtom *clipboard_targets,
@@ -1410,21 +1805,33 @@ web_view_selectable_update_actions (ESelectable *selectable,
web_view = WEBKIT_WEB_VIEW (selectable);
action = e_focus_tracker_get_cut_clipboard_action (focus_tracker);
- sensitive = webkit_web_view_can_cut_clipboard (web_view);
+ webkit_web_view_can_execute_editing_command (
+ WEBKIT_WEB_VIEW (web_view),
+ WEBKIT_EDITING_COMMAND_CUT,
+ NULL, /* cancellable */
+ (GAsyncReadyCallback) web_view_can_execute_editing_command_cb,
+ action);
tooltip = _("Cut the selection");
- gtk_action_set_sensitive (action, sensitive);
gtk_action_set_tooltip (action, tooltip);
action = e_focus_tracker_get_copy_clipboard_action (focus_tracker);
- sensitive = webkit_web_view_can_copy_clipboard (web_view);
+ webkit_web_view_can_execute_editing_command (
+ WEBKIT_WEB_VIEW (web_view),
+ WEBKIT_EDITING_COMMAND_COPY,
+ NULL, /* cancellable */
+ (GAsyncReadyCallback) web_view_can_execute_editing_command_cb,
+ action);
tooltip = _("Copy the selection");
- gtk_action_set_sensitive (action, sensitive);
gtk_action_set_tooltip (action, tooltip);
action = e_focus_tracker_get_paste_clipboard_action (focus_tracker);
- sensitive = webkit_web_view_can_paste_clipboard (web_view);
+ webkit_web_view_can_execute_editing_command (
+ WEBKIT_WEB_VIEW (web_view),
+ WEBKIT_EDITING_COMMAND_PASTE,
+ NULL, /* cancellable */
+ (GAsyncReadyCallback) web_view_can_execute_editing_command_cb,
+ action);
tooltip = _("Paste the clipboard");
- gtk_action_set_sensitive (action, sensitive);
gtk_action_set_tooltip (action, tooltip);
action = e_focus_tracker_get_select_all_action (focus_tracker);
@@ -1480,30 +1887,6 @@ e_web_view_test_change_and_update_fonts_cb (EWebView *web_view,
}
}
-static gpointer
-web_view_disable_webkit_3rd_party_plugins (gpointer unused)
-{
- WebKitWebPluginDatabase *database;
- GSList *installed_plugins, *iterator;
-
- database = webkit_get_web_plugin_database ();
-
- if (!database)
- return NULL;
-
- installed_plugins = webkit_web_plugin_database_get_plugins (database);
-
- if (!installed_plugins)
- return NULL;
-
- for (iterator = installed_plugins; iterator; iterator = iterator->next)
- webkit_web_plugin_set_enabled (iterator->data, FALSE);
-
- webkit_web_plugin_database_plugins_list_free (installed_plugins);
-
- return NULL;
-}
-
static void
web_view_toplevel_event_after_cb (GtkWidget *widget,
GdkEvent *event,
@@ -1564,6 +1947,7 @@ e_web_view_class_init (EWebViewClass *class)
g_type_class_add_private (class, sizeof (EWebViewPrivate));
object_class = G_OBJECT_CLASS (class);
+ object_class->constructor = web_view_constructor;
object_class->set_property = web_view_set_property;
object_class->get_property = web_view_get_property;
object_class->dispose = web_view_dispose;
@@ -1581,7 +1965,6 @@ e_web_view_class_init (EWebViewClass *class)
class->link_clicked = web_view_link_clicked;
class->load_string = web_view_load_string;
class->load_uri = web_view_load_uri;
- class->redirect_uri = web_view_redirect_uri;
class->suggest_filename = web_view_suggest_filename;
class->popup_event = web_view_popup_event;
class->stop_loading = web_view_stop_loading;
@@ -1597,6 +1980,18 @@ e_web_view_class_init (EWebViewClass *class)
FALSE,
G_PARAM_READWRITE));
+ /* Inherited from ESelectableInterface; just a fake property here */
+ g_object_class_override_property (
+ object_class,
+ PROP_COPY_TARGET_LIST,
+ "copy-target-list");
+
+ /* Inherited from ESelectableInterface; just a fake property here */
+ g_object_class_override_property (
+ object_class,
+ PROP_PASTE_TARGET_LIST,
+ "paste-target-list");
+
g_object_class_install_property (
object_class,
PROP_CURSOR_IMAGE_SRC,
@@ -1726,9 +2121,16 @@ e_web_view_class_init (EWebViewClass *class)
e_marshal_BOOLEAN__STRING,
G_TYPE_BOOLEAN, 1, G_TYPE_STRING);
- webkit_set_cache_model (WEBKIT_CACHE_MODEL_DOCUMENT_VIEWER);
- webkit_set_default_web_database_quota (0);
- webkit_application_cache_set_maximum_size (0);
+ /* Expects an empty string to abandon the request,
+ or NULL to keep the passed-in uri,
+ or a new uri to load instead. */
+ signals[URI_REQUESTED] = g_signal_new (
+ "uri-requested",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EWebViewClass, uri_requested),
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_POINTER);
}
static void
@@ -1748,6 +2150,14 @@ e_web_view_selectable_init (ESelectableInterface *iface)
}
static void
+initialize_web_extensions_cb (WebKitWebContext *web_context)
+{
+ /* Set the web extensions dir before the process is launched */
+ webkit_web_context_set_web_extensions_directory (
+ web_context, EVOLUTION_WEB_EXTENSIONS_DIR);
+}
+
+static void
e_web_view_init (EWebView *web_view)
{
GtkUIManager *ui_manager;
@@ -1760,48 +2170,35 @@ e_web_view_init (EWebView *web_view)
gulong handler_id;
GError *error = NULL;
- g_once (
- &disable_webkit_3rd_party_plugins_once,
- web_view_disable_webkit_3rd_party_plugins, NULL);
-
web_view->priv = E_WEB_VIEW_GET_PRIVATE (web_view);
web_view->priv->old_settings = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
(GDestroyNotify) g_variant_unref);
- web_view->priv->zoom_hack_state = E_WEB_VIEW_ZOOM_HACK_STATE_NONE;
-
- /* XXX No WebKitWebView class method pointers to
- * override so we have to use signal handlers. */
-
- g_signal_connect (
- web_view, "create-plugin-widget",
- G_CALLBACK (web_view_create_plugin_widget_cb), NULL);
g_signal_connect (
web_view, "context-menu",
G_CALLBACK (web_view_context_menu_cb), NULL);
g_signal_connect (
- web_view, "hovering-over-link",
- G_CALLBACK (web_view_hovering_over_link_cb), NULL);
+ web_view, "mouse-target-changed",
+ G_CALLBACK (web_view_mouse_target_changed_cb), NULL);
g_signal_connect (
- web_view, "navigation-policy-decision-requested",
- G_CALLBACK (web_view_navigation_policy_decision_requested_cb),
+ web_view, "decide-policy",
+ G_CALLBACK (web_view_decide_policy_cb),
NULL);
g_signal_connect (
- web_view, "new-window-policy-decision-requested",
- G_CALLBACK (web_view_navigation_policy_decision_requested_cb),
- NULL);
+ webkit_web_context_get_default (), "initialize-web-extensions",
+ G_CALLBACK (initialize_web_extensions_cb), NULL);
g_signal_connect (
+ web_view, "load-changed",
+ G_CALLBACK (web_view_load_changed_cb), NULL);
+/* FIXME WK2
+ g_signal_connect (
web_view, "document-load-finished",
G_CALLBACK (style_updated_cb), NULL);
-
- e_signal_connect_notify (
- web_view, "notify::load-status",
- G_CALLBACK (web_view_load_status_changed_cb), NULL);
-
+*/
g_signal_connect (
web_view, "style-updated",
G_CALLBACK (style_updated_cb), NULL);
@@ -1817,10 +2214,7 @@ e_web_view_init (EWebView *web_view)
ui_manager, "connect-proxy",
G_CALLBACK (web_view_connect_proxy_cb), web_view);
- web_view_init_web_settings (WEBKIT_WEB_VIEW (web_view));
-
- e_web_view_install_request_handler (web_view, E_TYPE_FILE_REQUEST);
- e_web_view_install_request_handler (web_view, E_TYPE_STOCK_REQUEST);
+ web_view_watch_web_extension (web_view);
settings = e_util_ref_settings ("org.gnome.desktop.interface");
web_view->priv->font_settings = g_object_ref (settings);
@@ -1849,8 +2243,6 @@ e_web_view_init (EWebView *web_view)
g_settings_schema_unref (settings_schema);
}
- e_web_view_update_fonts (web_view);
-
action_group = gtk_action_group_new ("uri");
gtk_action_group_set_translation_domain (action_group, domain);
gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
@@ -1958,13 +2350,15 @@ e_web_view_init (EWebView *web_view)
e_plugin_ui_register_manager (ui_manager, id, web_view);
e_plugin_ui_enable_manager (ui_manager, id);
- e_web_view_clear (E_WEB_VIEW (web_view));
+ web_view->priv->element_clicked_cbs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
(GDestroyNotify) g_ptr_array_unref);
}
GtkWidget *
e_web_view_new (void)
{
- return g_object_new (E_TYPE_WEB_VIEW, NULL);
+ return g_object_new (
+ E_TYPE_WEB_VIEW,
+ NULL);
}
void
@@ -1972,7 +2366,7 @@ e_web_view_clear (EWebView *web_view)
{
g_return_if_fail (E_IS_WEB_VIEW (web_view));
- webkit_web_view_load_html_string (
+ webkit_web_view_load_html (
WEBKIT_WEB_VIEW (web_view),
"<html>"
"<head></head>"
@@ -2010,37 +2404,6 @@ e_web_view_load_uri (EWebView *web_view,
}
/**
- * e_web_view_redirect_uri:
- * @web_view: an #EWebView
- * @uri: the requested URI
- *
- * Replaces @uri with a redirected URI as necessary, primarily for use
- * with custom #SoupRequest handlers. Typically this function would be
- * called just prior to handing a request off to a #SoupSession, such as
- * from a #WebKitWebView #WebKitWebView::resource-request-starting signal
- * handler.
- *
- * A newly-allocated URI string is always returned, whether the @uri was
- * redirected or not. Free the returned string with g_free().
- *
- * Returns: the redirected URI or a copy of @uri
- **/
-gchar *
-e_web_view_redirect_uri (EWebView *web_view,
- const gchar *uri)
-{
- EWebViewClass *class;
-
- g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
- g_return_val_if_fail (uri != NULL, NULL);
-
- class = E_WEB_VIEW_GET_CLASS (web_view);
- g_return_val_if_fail (class->redirect_uri != NULL, NULL);
-
- return class->redirect_uri (web_view, uri);
-}
-
-/**
* e_web_view_suggest_filename:
* @web_view: an #EWebView
* @uri: a URI string
@@ -2089,19 +2452,101 @@ e_web_view_reload (EWebView *web_view)
webkit_web_view_reload (WEBKIT_WEB_VIEW (web_view));
}
+static void
+get_document_content_html_cb (GDBusProxy *web_extension,
+ GAsyncResult *result,
+ GTask *task)
+{
+ GVariant *result_variant;
+ gchar *html_content = NULL;
+
+ result_variant = g_dbus_proxy_call_finish (web_extension, result, NULL);
+ if (result_variant)
+ g_variant_get (result_variant, "(s)", &html_content);
+ g_variant_unref (result_variant);
+
+ g_task_return_pointer (task, html_content, g_free);
+ g_object_unref (task);
+}
+
+void
+e_web_view_get_content_html (EWebView *web_view,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GDBusProxy *web_extension;
+ GTask *task;
+
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+ task = g_task_new (web_view, cancellable, callback, user_data);
+
+ web_extension = e_web_view_get_web_extension_proxy (web_view);
+ if (web_extension) {
+ g_dbus_proxy_call (
+ web_extension,
+ "GetDocumentContentHTML",
+ g_variant_new (
+ "(t)",
+ webkit_web_view_get_page_id (
+ WEBKIT_WEB_VIEW (web_view))),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ cancellable,
+ (GAsyncReadyCallback) get_document_content_html_cb,
+ g_object_ref (task));
+ } else
+ g_task_return_pointer (task, NULL, NULL);
+}
+
gchar *
-e_web_view_get_html (EWebView *web_view)
+e_web_view_get_content_html_finish (EWebView *web_view,
+ GAsyncResult *result,
+ GError **error)
{
- WebKitDOMDocument *document;
- WebKitDOMElement *element;
+ g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
+ g_return_val_if_fail (g_task_is_valid (result, web_view), FALSE);
+
+ return g_task_propagate_pointer (G_TASK (result), error);
+}
+
+gchar *
+e_web_view_get_content_html_sync (EWebView *web_view,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GDBusProxy *web_extension;
g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
- document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (web_view));
- element = webkit_dom_document_get_document_element (document);
+ web_extension = e_web_view_get_web_extension_proxy (web_view);
+ if (web_extension) {
+ GVariant *result;
+
+ result = g_dbus_proxy_call_sync (
+ web_extension,
+ "GetDocumentContentHTML",
+ g_variant_new (
+ "(t)",
+ webkit_web_view_get_page_id (
+ WEBKIT_WEB_VIEW (web_view))),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ cancellable,
+ error);
+
+ if (result) {
+ gchar *html_content = NULL;
+
+ g_variant_get (result, "(s)", &html_content);
+ g_variant_unref (result);
+
+ return html_content;
+ }
+ }
- return webkit_dom_html_element_get_outer_html (
- WEBKIT_DOM_HTML_ELEMENT (element));
+ return NULL;
}
gboolean
@@ -2131,8 +2576,10 @@ e_web_view_get_copy_target_list (EWebView *web_view)
{
g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
- return webkit_web_view_get_copy_target_list (
- WEBKIT_WEB_VIEW (web_view));
+ return NULL;
+ /* FIXME WK2 */
+ /*return webkit_web_view_get_copy_target_list (
+ WEBKIT_WEB_VIEW (web_view));*/
}
gboolean
@@ -2184,7 +2631,7 @@ e_web_view_get_editable (EWebView *web_view)
{
g_return_val_if_fail (E_IS_WEB_VIEW (web_view), FALSE);
- return webkit_web_view_get_editable (WEBKIT_WEB_VIEW (web_view));
+ return webkit_web_view_is_editable (WEBKIT_WEB_VIEW (web_view));
}
void
@@ -2277,8 +2724,10 @@ e_web_view_get_paste_target_list (EWebView *web_view)
{
g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
+ /* FIXME WK2
return webkit_web_view_get_paste_target_list (
- WEBKIT_WEB_VIEW (web_view));
+ WEBKIT_WEB_VIEW (web_view)); */
+ return NULL;
}
GtkAction *
@@ -2352,11 +2801,11 @@ e_web_view_add_highlight (EWebView *web_view,
&web_view->priv->highlights,
g_strdup (highlight));
- webkit_web_view_mark_text_matches (
- WEBKIT_WEB_VIEW (web_view), highlight, FALSE, 0);
-
- webkit_web_view_set_highlight_text_matches (
- WEBKIT_WEB_VIEW (web_view), TRUE);
+ webkit_find_controller_search (
+ web_view->priv->find_controller,
+ highlight,
+ WEBKIT_FIND_OPTIONS_NONE,
+ G_MAXUINT);
}
void
@@ -2364,7 +2813,7 @@ e_web_view_clear_highlights (EWebView *web_view)
{
g_return_if_fail (E_IS_WEB_VIEW (web_view));
- webkit_web_view_unmark_text_matches (WEBKIT_WEB_VIEW (web_view));
+ webkit_find_controller_search_finish (web_view->priv->find_controller);
while (!g_queue_is_empty (&web_view->priv->highlights))
g_free (g_queue_pop_head (&web_view->priv->highlights));
@@ -2411,7 +2860,8 @@ e_web_view_copy_clipboard (EWebView *web_view)
{
g_return_if_fail (E_IS_WEB_VIEW (web_view));
- webkit_web_view_copy_clipboard (WEBKIT_WEB_VIEW (web_view));
+ webkit_web_view_execute_editing_command (
+ WEBKIT_WEB_VIEW (web_view), WEBKIT_EDITING_COMMAND_COPY);
}
void
@@ -2419,15 +2869,43 @@ e_web_view_cut_clipboard (EWebView *web_view)
{
g_return_if_fail (E_IS_WEB_VIEW (web_view));
- webkit_web_view_cut_clipboard (WEBKIT_WEB_VIEW (web_view));
+ webkit_web_view_execute_editing_command (
+ WEBKIT_WEB_VIEW (web_view), WEBKIT_EDITING_COMMAND_CUT);
}
gboolean
e_web_view_is_selection_active (EWebView *web_view)
{
+ GDBusProxy *web_extension;
+
g_return_val_if_fail (E_IS_WEB_VIEW (web_view), FALSE);
- return webkit_web_view_has_selection (WEBKIT_WEB_VIEW (web_view));
+ web_extension = e_web_view_get_web_extension_proxy (web_view);
+ if (web_extension) {
+ GVariant *result;
+
+ result = g_dbus_proxy_call_sync (
+ web_extension,
+ "DocumentHasSelection",
+ g_variant_new (
+ "(t)",
+ webkit_web_view_get_page_id (
+ WEBKIT_WEB_VIEW (web_view))),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL);
+
+ if (result) {
+ gboolean value = FALSE;
+
+ g_variant_get (result, "(b)", &value);
+ g_variant_unref (result);
+ return value;
+ }
+ }
+
+ return FALSE;
}
void
@@ -2435,17 +2913,18 @@ e_web_view_paste_clipboard (EWebView *web_view)
{
g_return_if_fail (E_IS_WEB_VIEW (web_view));
- webkit_web_view_paste_clipboard (WEBKIT_WEB_VIEW (web_view));
+ webkit_web_view_execute_editing_command (
+ WEBKIT_WEB_VIEW (web_view), WEBKIT_EDITING_COMMAND_PASTE);
}
gboolean
e_web_view_scroll_forward (EWebView *web_view)
{
g_return_val_if_fail (E_IS_WEB_VIEW (web_view), FALSE);
-
+/* FIXME WK2
webkit_web_view_move_cursor (
WEBKIT_WEB_VIEW (web_view), GTK_MOVEMENT_PAGES, 1);
-
+*/
return TRUE; /* XXX This means nothing. */
}
@@ -2453,10 +2932,10 @@ gboolean
e_web_view_scroll_backward (EWebView *web_view)
{
g_return_val_if_fail (E_IS_WEB_VIEW (web_view), FALSE);
-
+/* FIXME WK2
webkit_web_view_move_cursor (
WEBKIT_WEB_VIEW (web_view), GTK_MOVEMENT_PAGES, -1);
-
+*/
return TRUE; /* XXX This means nothing. */
}
@@ -2465,7 +2944,8 @@ e_web_view_select_all (EWebView *web_view)
{
g_return_if_fail (E_IS_WEB_VIEW (web_view));
- webkit_web_view_select_all (WEBKIT_WEB_VIEW (web_view));
+ webkit_web_view_execute_editing_command (
+ WEBKIT_WEB_VIEW (web_view), WEBKIT_EDITING_COMMAND_SELECT_ALL);
}
void
@@ -2489,19 +2969,31 @@ e_web_view_zoom_100 (EWebView *web_view)
void
e_web_view_zoom_in (EWebView *web_view)
{
+ gdouble zoom_level;
+
g_return_if_fail (E_IS_WEB_VIEW (web_view));
- if (webkit_web_view_get_zoom_level (WEBKIT_WEB_VIEW (web_view)) < 4.9999)
- webkit_web_view_zoom_in (WEBKIT_WEB_VIEW (web_view));
+ /* There is no webkit_web_view_zoom_in function in WK2, so emulate it */
+ zoom_level = webkit_web_view_get_zoom_level (WEBKIT_WEB_VIEW (web_view));
+ /* zoom-step in WK1 was 0.1 */
+ zoom_level += 0.1;
+ if (zoom_level < 4.9999)
+ webkit_web_view_set_zoom_level (WEBKIT_WEB_VIEW (web_view), zoom_level);
}
void
e_web_view_zoom_out (EWebView *web_view)
{
+ gdouble zoom_level;
+
g_return_if_fail (E_IS_WEB_VIEW (web_view));
- if (webkit_web_view_get_zoom_level (WEBKIT_WEB_VIEW (web_view)) > 0.7999)
- webkit_web_view_zoom_out (WEBKIT_WEB_VIEW (web_view));
+ /* There is no webkit_web_view_zoom_out function in WK2, so emulate it */
+ zoom_level = webkit_web_view_get_zoom_level (WEBKIT_WEB_VIEW (web_view));
+ /* zoom-step in WK1 was 0.1 */
+ zoom_level -= 0.1;
+ if (zoom_level > 0.7999)
+ webkit_web_view_set_zoom_level (WEBKIT_WEB_VIEW (web_view), zoom_level);
}
GtkUIManager *
@@ -2609,132 +3101,98 @@ e_web_view_update_actions (EWebView *web_view)
g_signal_emit (web_view, signals[UPDATE_ACTIONS], 0);
}
-static gboolean
-element_is_in_pre_tag (WebKitDOMNode *node)
+static void
+get_selection_content_html_cb (GDBusProxy *web_extension,
+ GAsyncResult *result,
+ GTask *task)
{
- WebKitDOMElement *element;
-
- if (!node)
- return FALSE;
+ GVariant *result_variant;
+ gchar *html_content = NULL;
- while (element = webkit_dom_node_get_parent_element (node), element) {
- node = WEBKIT_DOM_NODE (element);
+ result_variant = g_dbus_proxy_call_finish (web_extension, result, NULL);
+ if (result_variant)
+ g_variant_get (result_variant, "(s)", &html_content);
+ g_variant_unref (result_variant);
- if (WEBKIT_DOM_IS_HTML_PRE_ELEMENT (element)) {
- return TRUE;
- } else if (WEBKIT_DOM_IS_HTML_IFRAME_ELEMENT (element)) {
- break;
- }
- }
-
- return FALSE;
+ g_task_return_pointer (task, html_content, g_free);
+ g_object_unref (task);
}
-static gchar *
-web_view_get_frame_selection_html (WebKitDOMElement *iframe)
-{
- WebKitDOMDocument *document;
- WebKitDOMDOMWindow *dom_window;
- WebKitDOMDOMSelection *dom_selection;
- WebKitDOMNodeList *frames;
- gulong ii, length;
-
- document = webkit_dom_html_iframe_element_get_content_document (
- WEBKIT_DOM_HTML_IFRAME_ELEMENT (iframe));
- dom_window = webkit_dom_document_get_default_view (document);
- dom_selection = webkit_dom_dom_window_get_selection (dom_window);
- g_object_unref (dom_window);
- if (dom_selection && (webkit_dom_dom_selection_get_range_count (dom_selection) > 0)) {
- WebKitDOMRange *range;
- WebKitDOMElement *element;
- WebKitDOMDocumentFragment *fragment;
-
- range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
- if (range != NULL) {
- gchar *inner_html;
- WebKitDOMNode *node;
-
- fragment = webkit_dom_range_clone_contents (
- range, NULL);
-
- element = webkit_dom_document_create_element (
- document, "DIV", NULL);
- webkit_dom_node_append_child (
- WEBKIT_DOM_NODE (element),
- WEBKIT_DOM_NODE (fragment), NULL);
-
- inner_html = webkit_dom_html_element_get_inner_html (
- WEBKIT_DOM_HTML_ELEMENT (element));
- node = webkit_dom_range_get_start_container (range, NULL);
- if (element_is_in_pre_tag (node)) {
- gchar *tmp = inner_html;
- inner_html = g_strconcat ("<pre>", tmp, "</pre>", NULL);
- g_free (tmp);
- }
-
- g_object_unref (range);
- g_object_unref (dom_selection);
- return inner_html;
- }
- }
-
- g_object_unref (dom_selection);
-
- frames = webkit_dom_document_get_elements_by_tag_name (
- document, "IFRAME");
- length = webkit_dom_node_list_get_length (frames);
- for (ii = 0; ii < length; ii++) {
- WebKitDOMNode *node;
- gchar *text;
-
- node = webkit_dom_node_list_item (frames, ii);
-
- text = web_view_get_frame_selection_html (
- WEBKIT_DOM_ELEMENT (node));
+void
+e_web_view_get_selection_content_html (EWebView *web_view,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GDBusProxy *web_extension;
+ GTask *task;
- g_object_unref (node);
- if (text != NULL) {
- g_object_unref (frames);
- return text;
- }
- }
- g_object_unref (frames);
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
- return NULL;
+ task = g_task_new (web_view, cancellable, callback, user_data);
+
+ web_extension = e_web_view_get_web_extension_proxy (web_view);
+ if (web_extension) {
+ g_dbus_proxy_call (
+ web_extension,
+ "GetSelectionContentHTML",
+ g_variant_new (
+ "(t)",
+ webkit_web_view_get_page_id (
+ WEBKIT_WEB_VIEW (web_view))),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ cancellable,
+ (GAsyncReadyCallback) get_selection_content_html_cb,
+ g_object_ref (task));
+ } else
+ g_task_return_pointer (task, NULL, NULL);
}
gchar *
-e_web_view_get_selection_html (EWebView *web_view)
+e_web_view_get_selection_content_html_finish (EWebView *web_view,
+ GAsyncResult *result,
+ GError **error)
{
- WebKitDOMDocument *document;
- WebKitDOMNodeList *frames;
- gulong ii, length;
-
g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
+ g_return_val_if_fail (g_task_is_valid (result, web_view), FALSE);
- if (!webkit_web_view_has_selection (WEBKIT_WEB_VIEW (web_view)))
- return NULL;
-
- document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (web_view));
- frames = webkit_dom_document_get_elements_by_tag_name (document, "IFRAME");
- length = webkit_dom_node_list_get_length (frames);
-
- for (ii = 0; ii < length; ii++) {
- gchar *text;
- WebKitDOMNode *node;
+ return g_task_propagate_pointer (G_TASK (result), error);
+}
- node = webkit_dom_node_list_item (frames, ii);
+gchar *
+e_web_view_get_selection_content_html_sync (EWebView *web_view,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GDBusProxy *web_extension;
- text = web_view_get_frame_selection_html (
- WEBKIT_DOM_ELEMENT (node));
+ g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
- g_object_unref (node);
- if (text != NULL) {
- g_object_unref (frames);
- return text;
+ web_extension = e_web_view_get_web_extension_proxy (web_view);
+ if (web_extension) {
+ GVariant *result;
+
+ result = g_dbus_proxy_call_sync (
+ web_extension,
+ "GetSelectionContentHTML",
+ g_variant_new (
+ "(t)",
+ webkit_web_view_get_page_id (
+ WEBKIT_WEB_VIEW (web_view))),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ cancellable,
+ error);
+
+ if (result) {
+ gchar *html_content = NULL;
+
+ g_variant_get (result, "(s)", &html_content);
+ g_variant_unref (result);
+ return html_content;
}
}
- g_object_unref (frames);
return NULL;
}
@@ -2757,60 +3215,61 @@ e_web_view_get_citation_color_for_level (gint level)
}
void
-e_web_view_update_fonts (EWebView *web_view)
+e_web_view_update_fonts_settings (GSettings *font_settings,
+ GSettings *aliasing_settings,
+ PangoFontDescription *ms_font,
+ PangoFontDescription *vw_font,
+ GtkWidget *view_widget)
{
- EWebViewClass *class;
- GString *stylesheet;
- gchar *base64;
+ gboolean clean_ms = FALSE, clean_vw = FALSE;
gchar *aa = NULL;
- WebKitWebSettings *settings;
- PangoFontDescription *min_size, *ms, *vw;
const gchar *styles[] = { "normal", "oblique", "italic" };
const gchar *smoothing = NULL;
- GtkStyleContext *context;
GdkColor *link = NULL;
GdkColor *visited = NULL;
+ GString *stylesheet;
+ GtkStyleContext *context;
+ PangoFontDescription *min_size, *ms, *vw;
+ WebKitSettings *wk_settings;
+ WebKitUserContentManager *manager;
+ WebKitUserStyleSheet *style_sheet;
- g_return_if_fail (E_IS_WEB_VIEW (web_view));
-
- ms = NULL;
- vw = NULL;
-
- class = E_WEB_VIEW_GET_CLASS (web_view);
- if (class->set_fonts != NULL)
- class->set_fonts (web_view, &ms, &vw);
-
- if (ms == NULL) {
+ if (!ms_font) {
gchar *font;
font = g_settings_get_string (
- web_view->priv->font_settings,
+ font_settings,
"monospace-font-name");
ms = pango_font_description_from_string (
(font != NULL) ? font : "monospace 10");
+ clean_ms = TRUE;
+
g_free (font);
- }
+ } else
+ ms = ms_font;
- if (vw == NULL) {
+ if (!vw_font) {
gchar *font;
font = g_settings_get_string (
- web_view->priv->font_settings,
+ font_settings,
"font-name");
vw = pango_font_description_from_string (
(font != NULL) ? font : "serif 10");
+ clean_vw = TRUE;
+
g_free (font);
- }
+ } else
+ vw = vw_font;
- if (pango_font_description_get_size (ms) < pango_font_description_get_size (vw)) {
+ if (pango_font_description_get_size (ms) < pango_font_description_get_size (vw))
min_size = ms;
- } else {
+ else
min_size = vw;
- }
stylesheet = g_string_new ("");
g_string_append_printf (
@@ -2825,9 +3284,9 @@ e_web_view_update_fonts (EWebView *web_view)
pango_font_description_get_weight (vw),
styles[pango_font_description_get_style (vw)]);
- if (web_view->priv->aliasing_settings != NULL)
+ if (aliasing_settings != NULL)
aa = g_settings_get_string (
- web_view->priv->aliasing_settings, "antialiasing");
+ aliasing_settings, "antialiasing");
if (g_strcmp0 (aa, "none") == 0)
smoothing = "none";
@@ -2854,176 +3313,229 @@ e_web_view_update_fonts (EWebView *web_view)
" font-weight: %d;\n"
" font-style: %s;\n"
" margin: 0px;\n"
- "}",
+ "}\n",
pango_font_description_get_family (ms),
pango_font_description_get_size (ms) / PANGO_SCALE,
pango_font_description_get_weight (ms),
styles[pango_font_description_get_style (ms)]);
- context = gtk_widget_get_style_context (GTK_WIDGET (web_view));
- gtk_style_context_get_style (
- context,
- "link-color", &link,
- "visited-link-color", &visited,
- NULL);
-
- if (link == NULL) {
- #if GTK_CHECK_VERSION(3,12,0)
- GdkRGBA rgba;
- GtkStateFlags state;
- #endif
-
- link = g_slice_new0 (GdkColor);
- link->blue = G_MAXINT16;
+ if (view_widget) {
+ context = gtk_widget_get_style_context (view_widget);
+ gtk_style_context_get_style (
+ context,
+ "link-color", &link,
+ "visited-link-color", &visited,
+ NULL);
- #if GTK_CHECK_VERSION(3,12,0)
- rgba.alpha = 1;
- rgba.red = 0;
- rgba.green = 0;
- rgba.blue = 1;
+ if (link == NULL) {
+ #if GTK_CHECK_VERSION(3,12,0)
+ GdkRGBA rgba;
+ GtkStateFlags state;
+ #endif
- state = gtk_style_context_get_state (context);
- state = state & (~(GTK_STATE_FLAG_VISITED | GTK_STATE_FLAG_LINK));
- state = state | GTK_STATE_FLAG_LINK;
+ link = g_slice_new0 (GdkColor);
+ link->blue = G_MAXINT16;
- gtk_style_context_save (context);
- gtk_style_context_set_state (context, state);
- gtk_style_context_get_color (context, state, &rgba);
- gtk_style_context_restore (context);
+ #if GTK_CHECK_VERSION(3,12,0)
+ rgba.alpha = 1;
+ rgba.red = 0;
+ rgba.green = 0;
+ rgba.blue = 1;
- e_rgba_to_color (&rgba, link);
- #endif
- }
+ state = gtk_style_context_get_state (context);
+ state = state & (~(GTK_STATE_FLAG_VISITED | GTK_STATE_FLAG_LINK));
+ state = state | GTK_STATE_FLAG_LINK;
- if (visited == NULL) {
- #if GTK_CHECK_VERSION(3,12,0)
- GdkRGBA rgba;
- GtkStateFlags state;
- #endif
+ gtk_style_context_save (context);
+ gtk_style_context_set_state (context, state);
+ gtk_style_context_get_color (context, state, &rgba);
+ gtk_style_context_restore (context);
- visited = g_slice_new0 (GdkColor);
- visited->red = G_MAXINT16;
-
- #if GTK_CHECK_VERSION(3,12,0)
- rgba.alpha = 1;
- rgba.red = 1;
- rgba.green = 0;
- rgba.blue = 0;
+ e_rgba_to_color (&rgba, link);
+ #endif
+ }
- state = gtk_style_context_get_state (context);
- state = state & (~(GTK_STATE_FLAG_VISITED | GTK_STATE_FLAG_LINK));
- state = state | GTK_STATE_FLAG_VISITED;
+ if (visited == NULL) {
+ #if GTK_CHECK_VERSION(3,12,0)
+ GdkRGBA rgba;
+ GtkStateFlags state;
+ #endif
- gtk_style_context_save (context);
- gtk_style_context_set_state (context, state);
- gtk_style_context_get_color (context, state, &rgba);
- gtk_style_context_restore (context);
+ visited = g_slice_new0 (GdkColor);
+ visited->red = G_MAXINT16;
- e_rgba_to_color (&rgba, visited);
- #endif
- }
+ #if GTK_CHECK_VERSION(3,12,0)
+ rgba.alpha = 1;
+ rgba.red = 1;
+ rgba.green = 0;
+ rgba.blue = 0;
- g_string_append_printf (
- stylesheet,
- "a {\n"
- " color: #%06x;\n"
- "}\n"
- "a:visited {\n"
- " color: #%06x;\n"
- "}\n",
- e_color_to_value (link),
- e_color_to_value (visited));
+ state = gtk_style_context_get_state (context);
+ state = state & (~(GTK_STATE_FLAG_VISITED | GTK_STATE_FLAG_LINK));
+ state = state | GTK_STATE_FLAG_VISITED;
- gdk_color_free (link);
- gdk_color_free (visited);
+ gtk_style_context_save (context);
+ gtk_style_context_set_state (context, state);
+ gtk_style_context_get_color (context, state, &rgba);
+ gtk_style_context_restore (context);
- g_string_append (
- stylesheet,
- "blockquote[type=cite]:not(.-x-evo-plaintext-quoted) "
- "{\n"
- " padding: 0ch 1ch 0ch 1ch;\n"
- " margin: 0ch;\n"
- " border-width: 0px 2px 0px 2px;\n"
- " border-style: none solid none solid;\n"
- " border-radius: 2px;\n"
- "}\n");
+ e_rgba_to_color (&rgba, visited);
+ #endif
+ }
- g_string_append_printf (
- stylesheet,
- "blockquote[type=cite]:not(.-x-evo-plaintext-quoted) "
- "{\n"
- " border-color: %s;\n"
- "}\n",
- e_web_view_get_citation_color_for_level (1));
+ g_string_append_printf (
+ stylesheet,
+ "a {\n"
+ " color: #%06x;\n"
+ "}\n"
+ "a:visited {\n"
+ " color: #%06x;\n"
+ "}\n",
+ e_color_to_value (link),
+ e_color_to_value (visited));
+
+ gdk_color_free (link);
+ gdk_color_free (visited);
+
+ g_string_append (
+ stylesheet,
+ "blockquote[type=cite]:not(.-x-evo-plaintext-quoted) "
+ "{\n"
+ " padding: 0ch 1ch 0ch 1ch;\n"
+ " margin: 0ch;\n"
+ " border-width: 0px 2px 0px 2px;\n"
+ " border-style: none solid none solid;\n"
+ " border-radius: 2px;\n"
+ "}\n");
- g_string_append_printf (
- stylesheet,
- "blockquote[type=cite]:not(.-x-evo-plaintext-quoted) "
- "blockquote[type=cite]:not(.-x-evo-plaintext-quoted) "
- "{\n"
- " border-color: %s;\n"
- "}\n",
- e_web_view_get_citation_color_for_level (2));
+ g_string_append_printf (
+ stylesheet,
+ "blockquote[type=cite]:not(.-x-evo-plaintext-quoted) "
+ "{\n"
+ " border-color: %s;\n"
+ "}\n",
+ e_web_view_get_citation_color_for_level (1));
- g_string_append_printf (
- stylesheet,
- "blockquote[type=cite]:not(.-x-evo-plaintext-quoted) "
- "blockquote[type=cite]:not(.-x-evo-plaintext-quoted) "
- "blockquote[type=cite]:not(.-x-evo-plaintext-quoted) "
- "{\n"
- " border-color: %s;\n"
- "}\n",
- e_web_view_get_citation_color_for_level (3));
+ g_string_append_printf (
+ stylesheet,
+ "blockquote[type=cite]:not(.-x-evo-plaintext-quoted) "
+ "blockquote[type=cite]:not(.-x-evo-plaintext-quoted) "
+ "{\n"
+ " border-color: %s;\n"
+ "}\n",
+ e_web_view_get_citation_color_for_level (2));
- g_string_append_printf (
- stylesheet,
- "blockquote[type=cite]:not(.-x-evo-plaintext-quoted) "
- "blockquote[type=cite]:not(.-x-evo-plaintext-quoted) "
- "blockquote[type=cite]:not(.-x-evo-plaintext-quoted) "
- "blockquote[type=cite]:not(.-x-evo-plaintext-quoted) "
- "{\n"
- " border-color: %s;\n"
- "}\n",
- e_web_view_get_citation_color_for_level (4));
+ g_string_append_printf (
+ stylesheet,
+ "blockquote[type=cite]:not(.-x-evo-plaintext-quoted) "
+ "blockquote[type=cite]:not(.-x-evo-plaintext-quoted) "
+ "blockquote[type=cite]:not(.-x-evo-plaintext-quoted) "
+ "{\n"
+ " border-color: %s;\n"
+ "}\n",
+ e_web_view_get_citation_color_for_level (3));
- g_string_append_printf (
- stylesheet,
- "blockquote[type=cite]:not(.-x-evo-plaintext-quoted) "
- "blockquote[type=cite]:not(.-x-evo-plaintext-quoted) "
- "blockquote[type=cite]:not(.-x-evo-plaintext-quoted) "
- "blockquote[type=cite]:not(.-x-evo-plaintext-quoted) "
- "blockquote[type=cite]:not(.-x-evo-plaintext-quoted) "
- "{\n"
- " border-color: %s;\n"
- "}\n",
- e_web_view_get_citation_color_for_level (5));
+ g_string_append_printf (
+ stylesheet,
+ "blockquote[type=cite]:not(.-x-evo-plaintext-quoted) "
+ "blockquote[type=cite]:not(.-x-evo-plaintext-quoted) "
+ "blockquote[type=cite]:not(.-x-evo-plaintext-quoted) "
+ "blockquote[type=cite]:not(.-x-evo-plaintext-quoted) "
+ "{\n"
+ " border-color: %s;\n"
+ "}\n",
+ e_web_view_get_citation_color_for_level (4));
- base64 = g_base64_encode ((guchar *) stylesheet->str, stylesheet->len);
- g_string_free (stylesheet, TRUE);
+ g_string_append_printf (
+ stylesheet,
+ "blockquote[type=cite]:not(.-x-evo-plaintext-quoted) "
+ "blockquote[type=cite]:not(.-x-evo-plaintext-quoted) "
+ "blockquote[type=cite]:not(.-x-evo-plaintext-quoted) "
+ "blockquote[type=cite]:not(.-x-evo-plaintext-quoted) "
+ "blockquote[type=cite]:not(.-x-evo-plaintext-quoted) "
+ "{\n"
+ " border-color: %s;\n"
+ "}\n",
+ e_web_view_get_citation_color_for_level (5));
+ }
- stylesheet = g_string_new ("data:text/css;charset=utf-8;base64,");
- g_string_append (stylesheet, base64);
- g_free (base64);
+ wk_settings = webkit_web_view_get_settings (WEBKIT_WEB_VIEW (view_widget));
- settings = webkit_web_view_get_settings (WEBKIT_WEB_VIEW (web_view));
g_object_set (
- G_OBJECT (settings),
+ wk_settings,
"default-font-size",
- pango_font_description_get_size (vw) / PANGO_SCALE,
+ e_util_normalize_font_size (
+ view_widget, pango_font_description_get_size (vw) / PANGO_SCALE),
"default-font-family",
pango_font_description_get_family (vw),
"monospace-font-family",
pango_font_description_get_family (ms),
"default-monospace-font-size",
- pango_font_description_get_size (ms) / PANGO_SCALE,
+ e_util_normalize_font_size (
+ view_widget, pango_font_description_get_size (ms) / PANGO_SCALE),
"minimum-font-size",
- pango_font_description_get_size (min_size) / PANGO_SCALE,
- "user-stylesheet-uri",
+ e_util_normalize_font_size (
+ view_widget, pango_font_description_get_size (min_size) / PANGO_SCALE),
+ NULL);
+
+ manager = webkit_web_view_get_user_content_manager (WEBKIT_WEB_VIEW (view_widget));
+ webkit_user_content_manager_remove_all_style_sheets (manager);
+
+ style_sheet = webkit_user_style_sheet_new (
stylesheet->str,
+ WEBKIT_USER_CONTENT_INJECT_ALL_FRAMES,
+ WEBKIT_USER_STYLE_LEVEL_USER,
+ NULL,
NULL);
+ webkit_user_content_manager_add_style_sheet (manager, style_sheet);
+
+ webkit_user_style_sheet_unref (style_sheet);
+
g_string_free (stylesheet, TRUE);
+ if (clean_ms)
+ pango_font_description_free (ms);
+ if (clean_vw)
+ pango_font_description_free (vw);
+}
+
+WebKitSettings *
+e_web_view_get_default_webkit_settings (void)
+{
+ return webkit_settings_new_with_settings (
+ "auto-load-images", TRUE,
+ "default-charset", "utf-8",
+ "enable-html5-database", FALSE,
+ "enable-dns-prefetching", FALSE,
+ "enable-html5-local-storage", FALSE,
+ "enable-java", FALSE,
+ "enable-javascript", FALSE,
+ "enable-offline-web-application-cache", FALSE,
+ "enable-page-cache", FALSE,
+ "enable-plugins", FALSE,
+ "enable-smooth-scrolling", FALSE,
+ "media-playback-allows-inline", FALSE,
+ NULL);
+}
+
+void
+e_web_view_update_fonts (EWebView *web_view)
+{
+ EWebViewClass *class;
+ PangoFontDescription *ms = NULL, *vw = NULL;
+
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+ class = E_WEB_VIEW_GET_CLASS (web_view);
+ if (class->set_fonts != NULL)
+ class->set_fonts (web_view, &ms, &vw);
+
+ e_web_view_update_fonts_settings (
+ web_view->priv->font_settings,
+ web_view->priv->aliasing_settings,
+ ms, vw, GTK_WIDGET (web_view));
+
pango_font_description_free (ms);
pango_font_description_free (vw);
}
@@ -3387,24 +3899,25 @@ e_web_view_cursor_image_save (EWebView *web_view)
/* Helper for e_web_view_request() */
static void
-web_view_request_send_cb (GObject *source_object,
- GAsyncResult *result,
- gpointer user_data)
+web_view_request_process_thread (GTask *task,
+ gpointer source_object,
+ gpointer task_data,
+ GCancellable *cancellable)
{
- GSimpleAsyncResult *simple;
- AsyncContext *async_context;
+ AsyncContext *async_context = task_data;
+ gint64 stream_length = -1;
+ gchar *mime_type = NULL;
GError *local_error = NULL;
- simple = G_SIMPLE_ASYNC_RESULT (user_data);
- async_context = g_simple_async_result_get_op_res_gpointer (simple);
-
- async_context->input_stream = soup_request_send_finish (
- SOUP_REQUEST (source_object), result, &local_error);
-
- if (local_error != NULL)
- g_simple_async_result_take_error (simple, local_error);
+ if (!e_content_request_process_sync (async_context->content_request,
+ async_context->uri, source_object, &async_context->input_stream,
+ &stream_length, &mime_type, cancellable, &local_error)) {
+ g_task_return_error (task, local_error);
+ } else {
+ g_task_return_boolean (task, TRUE);
+ }
- g_simple_async_result_complete (simple);
+ g_free (mime_type);
}
/**
@@ -3415,9 +3928,7 @@ web_view_request_send_cb (GObject *source_object,
* @callback: a #GAsyncReadyCallback to call when the request is satisfied
* @user_data: data to pass to the callback function
*
- * Asynchronously requests data at @uri by way of a #SoupRequest to WebKit's
- * default #SoupSession, incorporating both e_web_view_redirect_uri() and the
- * custom request handlers installed via e_web_view_install_request_handler().
+ * Asynchronously requests data at @uri as displaed in the @web_view.
*
* When the operation is finished, @callback will be called. You can then
* call e_web_view_request_finish() to get the result of the operation.
@@ -3429,52 +3940,41 @@ e_web_view_request (EWebView *web_view,
GAsyncReadyCallback callback,
gpointer user_data)
{
- SoupSession *session;
- SoupRequest *request;
- gchar *real_uri;
- GSimpleAsyncResult *simple;
+ EContentRequest *content_request = NULL;
AsyncContext *async_context;
- GError *local_error = NULL;
+ GSList *link;
+ GTask *task;
g_return_if_fail (E_IS_WEB_VIEW (web_view));
g_return_if_fail (uri != NULL);
- session = webkit_get_default_session ();
-
- async_context = g_slice_new0 (AsyncContext);
-
- simple = g_simple_async_result_new (
- G_OBJECT (web_view), callback,
- user_data, e_web_view_request);
+ for (link = web_view->priv->content_requests; link; link = g_slist_next (link)) {
+ EContentRequest *adept = link->data;
- g_simple_async_result_set_check_cancellable (simple, cancellable);
+ if (!E_IS_CONTENT_REQUEST (adept) ||
+ !e_content_request_can_process_uri (adept, uri))
+ continue;
- g_simple_async_result_set_op_res_gpointer (
- simple, async_context, (GDestroyNotify) async_context_free);
-
- real_uri = e_web_view_redirect_uri (web_view, uri);
- request = soup_session_request (session, real_uri, &local_error);
- g_free (real_uri);
-
- /* Sanity check. */
- g_return_if_fail (
- ((request != NULL) && (local_error == NULL)) ||
- ((request == NULL) && (local_error != NULL)));
+ content_request = adept;
+ break;
+ }
- if (request != NULL) {
- soup_request_send_async (
- request, cancellable,
- web_view_request_send_cb,
- g_object_ref (simple));
+ async_context = g_slice_new0 (AsyncContext);
+ async_context->uri = g_strdup (uri);
- g_object_unref (request);
+ task = g_task_new (web_view, cancellable, callback, user_data);
+ g_task_set_task_data (task, async_context, async_context_free);
+ g_task_set_check_cancellable (task, TRUE);
+ if (content_request) {
+ async_context->content_request = g_object_ref (content_request);
+ g_task_run_in_thread (task, web_view_request_process_thread);
} else {
- g_simple_async_result_take_error (simple, local_error);
- g_simple_async_result_complete_in_idle (simple);
+ g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED,
+ _("Cannot get URI '%s', do not know how to download it."), uri);
}
- g_object_unref (simple);
+ g_object_unref (task);
}
/**
@@ -3496,204 +3996,435 @@ e_web_view_request_finish (EWebView *web_view,
GAsyncResult *result,
GError **error)
{
- GSimpleAsyncResult *simple;
AsyncContext *async_context;
- g_return_val_if_fail (
- g_simple_async_result_is_valid (
- result, G_OBJECT (web_view), e_web_view_request), NULL);
-
- simple = G_SIMPLE_ASYNC_RESULT (result);
- async_context = g_simple_async_result_get_op_res_gpointer (simple);
+ g_return_val_if_fail (g_task_is_valid (result, web_view), NULL);
- if (g_simple_async_result_propagate_error (simple, error))
+ if (!g_task_propagate_boolean (G_TASK (result), error))
return NULL;
+ async_context = g_task_get_task_data (G_TASK (result));
+
g_return_val_if_fail (async_context->input_stream != NULL, NULL);
return g_object_ref (async_context->input_stream);
}
+/**
+ * e_web_view_create_and_add_css_style_sheet:
+ * @web_view: an #EWebView
+ * @style_sheet_id: CSS style sheet's id
+ *
+ * Creates new CSS style sheet with given @style_sheel_id and inserts
+ * it into given @web_view document.
+ **/
void
-e_web_view_install_request_handler (EWebView *web_view,
- GType handler_type)
+e_web_view_create_and_add_css_style_sheet (EWebView *web_view,
+ const gchar *style_sheet_id)
{
- SoupSession *session;
+ GDBusProxy *web_extension;
+
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+ g_return_if_fail (style_sheet_id && *style_sheet_id);
- session = webkit_get_default_session ();
- soup_session_add_feature_by_type (session, handler_type);
+ web_extension = e_web_view_get_web_extension_proxy (web_view);
+ if (web_extension) {
+ g_dbus_proxy_call (
+ web_extension,
+ "CreateAndAddCSSStyleSheet",
+ g_variant_new (
+ "(ts)",
+ webkit_web_view_get_page_id (
+ WEBKIT_WEB_VIEW (web_view)),
+ style_sheet_id),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+ }
}
+/**
+ * e_web_view_add_css_rule_into_style_sheet:
+ * @web_view: an #EWebView
+ * @style_sheet_id: CSS style sheet's id
+ * @selector: CSS selector
+ * @style: style for given selector
+ *
+ * Insert new CSS rule (defined with @selector and @style) into CSS style sheet
+ * with given @style_sheet_id. If style sheet doesn't exist, it's created.
+ *
+ * The rule is inserted to every DOM document that is in page. That means also
+ * into DOM documents inside iframe elements.
+ **/
void
-e_web_view_create_and_add_css_style_sheet (WebKitDOMDocument *document,
- const gchar *style_sheet_id)
+e_web_view_add_css_rule_into_style_sheet (EWebView *web_view,
+ const gchar *style_sheet_id,
+ const gchar *selector,
+ const gchar *style)
{
- WebKitDOMElement *style_element;
+ GDBusProxy *web_extension;
- style_element = webkit_dom_document_get_element_by_id (document, style_sheet_id);
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+ g_return_if_fail (style_sheet_id && *style_sheet_id);
+ g_return_if_fail (selector && *selector);
+ g_return_if_fail (style && *style);
- if (!style_element) {
- WebKitDOMText *dom_text;
- WebKitDOMHTMLHeadElement *head;
+ web_extension = e_web_view_get_web_extension_proxy (web_view);
+ if (web_extension) {
+ g_dbus_proxy_call (
+ web_extension,
+ "AddCSSRuleIntoStyleSheet",
+ g_variant_new (
+ "(tsss)",
+ webkit_web_view_get_page_id (
+ WEBKIT_WEB_VIEW (web_view)),
+ style_sheet_id,
+ selector,
+ style),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+ }
+}
- dom_text = webkit_dom_document_create_text_node (document, "");
+/**
+ * e_web_view_get_document_uri_from_point:
+ * @web_view: an #EWebView
+ * @x: x-coordinate
+ * @y: y-coordinate
+ *
+ * Returns: A document URI which is under the @x, @y coordinates or %NULL,
+ * if there is none. Free the returned pointer with g_free() when done with it.
+ *
+ * Since: 3.22
+ **/
+gchar *
+e_web_view_get_document_uri_from_point (EWebView *web_view,
+ gint32 x,
+ gint32 y)
+{
+ GDBusProxy *web_extension;
+ GVariant *result;
+ GError *local_error = NULL;
- /* Create new <style> element */
- style_element = webkit_dom_document_create_element (document, "style", NULL);
- webkit_dom_element_set_id (
- WEBKIT_DOM_ELEMENT (style_element),
- style_sheet_id);
- webkit_dom_html_style_element_set_media (
- WEBKIT_DOM_HTML_STYLE_ELEMENT (style_element),
- "screen");
- webkit_dom_node_append_child (
- WEBKIT_DOM_NODE (style_element),
- /* WebKit hack - we have to insert empty TextNode into style element */
- WEBKIT_DOM_NODE (dom_text),
- NULL);
+ g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
- head = webkit_dom_document_get_head (document);
+ web_extension = e_web_view_get_web_extension_proxy (web_view);
+ if (!web_extension)
+ return NULL;
- webkit_dom_node_append_child (
- WEBKIT_DOM_NODE (head),
- WEBKIT_DOM_NODE (style_element),
- NULL);
+ result = g_dbus_proxy_call_sync (
+ web_extension,
+ "GetDocumentURIFromPoint",
+ g_variant_new (
+ "(tii)",
+ webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (web_view)),
+ x,
+ y),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ &local_error);
+
+ if (local_error)
+ g_warning ("%s: Failed with error: %s", G_STRFUNC, local_error->message);
+
+ g_clear_error (&local_error);
+
+ if (result) {
+ gchar *uri = NULL;
+
+ g_variant_get (result, "(s)", &uri);
+ g_variant_unref (result);
+
+ if (g_strcmp0 (uri, "") == 0) {
+ g_free (uri);
+ uri = NULL;
+ }
- g_object_unref (head);
- g_object_unref (dom_text);
- g_object_unref (style_element);
+ return uri;
}
+
+ return NULL;
}
static void
-add_css_rule_into_style_sheet (WebKitDOMDocument *document,
- const gchar *style_sheet_id,
- const gchar *selector,
- const gchar *style)
+e_web_view_set_document_iframe_src_done_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
{
- WebKitDOMElement *style_element;
- WebKitDOMStyleSheet *sheet;
- WebKitDOMCSSRuleList *rules_list;
- gint length, ii, selector_length;
- gboolean removed = FALSE;
+ GVariant *variant;
+ GError *local_error = NULL;
- g_return_if_fail (selector != NULL);
+ variant = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object), result, &local_error);
+ if (variant)
+ g_variant_unref (variant);
- selector_length = strlen (selector);
- style_element = webkit_dom_document_get_element_by_id (document, style_sheet_id);
+ if (local_error)
+ g_warning ("%s: Failed with error: %s", G_STRFUNC, local_error->message);
- if (!style_element) {
- e_web_view_create_and_add_css_style_sheet (document, style_sheet_id);
- style_element = webkit_dom_document_get_element_by_id (document, style_sheet_id);
- }
+ g_clear_error (&local_error);
+}
- /* Get sheet that is associated with style element */
- sheet = webkit_dom_html_style_element_get_sheet (WEBKIT_DOM_HTML_STYLE_ELEMENT (style_element));
+/**
+ * e_web_view_set_document_iframe_src:
+ * @web_view: an #EWebView
+ * @document_uri: a document URI for whose IFrame change the source
+ * @new_iframe_src: the source to change the IFrame to
+ *
+ * Change IFrame source for the given @document_uri IFrame
+ * to the @new_iframe_src.
+ *
+ * Since: 3.22
+ **/
+void
+e_web_view_set_document_iframe_src (EWebView *web_view,
+ const gchar *document_uri,
+ const gchar *new_iframe_src)
+{
+ GDBusProxy *web_extension;
- rules_list = webkit_dom_css_style_sheet_get_css_rules (WEBKIT_DOM_CSS_STYLE_SHEET (sheet));
- length = webkit_dom_css_rule_list_get_length (rules_list);
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
- /* Check if rule exists */
- for (ii = 0; ii < length && !removed; ii++) {
- WebKitDOMCSSRule *rule;
- gchar *rule_text = NULL;
+ web_extension = e_web_view_get_web_extension_proxy (web_view);
+ if (!web_extension)
+ return;
- rule = webkit_dom_css_rule_list_item (rules_list, ii);
+ /* Cannot call this synchronously, blocking the local main loop, because the reload
+ can on the WebProcess side can be asking for a redirection policy, waiting
+ for a response which may be waiting in the blocked main loop. */
+ g_dbus_proxy_call (
+ web_extension,
+ "SetDocumentIFrameSrc",
+ g_variant_new (
+ "(tss)",
+ webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (web_view)),
+ document_uri,
+ new_iframe_src),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ e_web_view_set_document_iframe_src_done_cb, NULL);
+}
- g_return_if_fail (WEBKIT_DOM_IS_CSS_RULE (rule));
+/**
+ * EWebViewElementClickedFunc:
+ * @web_view: an #EWebView
+ * @element_class: an element class, as set on the element which had been clicked
+ * @element_value: a 'value' attribute content of the clicked element
+ * @element_position: a #GtkAllocation with the position of the clicked element
+ * @user_data: user data as provided in the e_web_view_register_element_clicked() call
+ *
+ * The callback is called whenever an element of class @element_class is clicked.
+ * The @element_value is a content of the 'value' attribute of the clicked element.
+ * The @element_position is the place of the element within the web page, already
+ * accounting scrollbar positions.
+ *
+ * See: e_web_view_register_element_clicked, e_web_view_unregister_element_clicked
+ *
+ * Since: 3.22
+ **/
- rule_text = webkit_dom_css_rule_get_css_text (rule);
+/**
+ * e_web_view_register_element_clicked:
+ * @web_view: an #EWebView
+ * @element_class: an element class on which to listen for clicking
+ * @callback: an #EWebViewElementClickedFunc to call, when the element is clicked
+ * @user_data: user data to pass to @callback
+ *
+ * Registers a @callback to be called when any element of the class @element_class
+ * is clicked. If the element contains a 'value' attribute, then it is passed to
+ * the @callback too. These callback are valid until a new content of the @web_view
+ * is loaded, after which all the registered callbacks are forgotten.
+ *
+ * Since: 3.22
+ **/
+void
+e_web_view_register_element_clicked (EWebView *web_view,
+ const gchar *element_class,
+ EWebViewElementClickedFunc callback,
+ gpointer user_data)
+{
+ ElementClickedData *ecd;
+ GPtrArray *cbs;
+ guint ii;
- /* Find the start of the style => end of the selector */
- if (rule_text && selector && g_str_has_prefix (rule_text, selector) &&
- rule_text[selector_length] == ' ' && rule_text[selector_length + 1] == '{') {
- /* If exists remove it */
- webkit_dom_css_style_sheet_remove_rule (
- WEBKIT_DOM_CSS_STYLE_SHEET (sheet),
- ii, NULL);
- length--;
- removed = TRUE;
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+ g_return_if_fail (element_class != NULL);
+ g_return_if_fail (callback != NULL);
+
+ cbs = g_hash_table_lookup (web_view->priv->element_clicked_cbs, element_class);
+ if (cbs) {
+ for (ii = 0; ii < cbs->len; ii++) {
+ ecd = g_ptr_array_index (cbs, ii);
+
+ if (ecd && ecd->callback == callback && ecd->user_data == user_data) {
+ /* Callback is already registered, but re-register it, in case the page
+ was changed dynamically and new elements with the given call are added. */
+ web_view_register_element_clicked_hfunc ((gpointer) element_class, cbs,
web_view);
+ return;
+ }
}
+ }
+
+ ecd = g_new0 (ElementClickedData, 1);
+ ecd->callback = callback;
+ ecd->user_data = user_data;
+
+ if (!cbs) {
+ cbs = g_ptr_array_new_full (1, g_free);
+ g_ptr_array_add (cbs, ecd);
- g_free (rule_text);
- g_object_unref (rule);
+ g_hash_table_insert (web_view->priv->element_clicked_cbs, g_strdup (element_class), cbs);
+ } else {
+ g_ptr_array_add (cbs, ecd);
}
- g_object_unref (rules_list);
+ /* Dynamically changing page can call this multiple times; re-register all classes */
+ g_hash_table_foreach (web_view->priv->element_clicked_cbs, web_view_register_element_clicked_hfunc,
web_view);
+}
+
+/**
+ * e_web_view_unregister_element_clicked:
+ * @web_view: an #EWebView
+ * @element_class: an element class on which to listen for clicking
+ * @callback: an #EWebViewElementClickedFunc to call, when the element is clicked
+ * @user_data: user data to pass to @callback
+ *
+ * Unregisters the @callback for the @element_class with the given @user_data, which
+ * should be previously registered with e_web_view_register_element_clicked(). This
+ * unregister is usually not needed, because the @web_view unregisters all callbacks
+ * when a new content is loaded.
+ *
+ * Since: 3.22
+ **/
+void
+e_web_view_unregister_element_clicked (EWebView *web_view,
+ const gchar *element_class,
+ EWebViewElementClickedFunc callback,
+ gpointer user_data)
+{
+ ElementClickedData *ecd;
+ GPtrArray *cbs;
+ guint ii;
+
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+ g_return_if_fail (element_class != NULL);
+ g_return_if_fail (callback != NULL);
+
+ cbs = g_hash_table_lookup (web_view->priv->element_clicked_cbs, element_class);
+ if (!cbs)
+ return;
- /* Insert the rule at the end, so it will override previously inserted */
- webkit_dom_css_style_sheet_add_rule (
- WEBKIT_DOM_CSS_STYLE_SHEET (sheet), selector, style, length, NULL);
+ for (ii = 0; ii < cbs->len; ii++) {
+ ecd = g_ptr_array_index (cbs, ii);
- g_object_unref (sheet);
- g_object_unref (style_element);
+ if (ecd && ecd->callback == callback && ecd->user_data == user_data) {
+ g_ptr_array_remove (cbs, ecd);
+ if (!cbs->len)
+ g_hash_table_remove (web_view->priv->element_clicked_cbs, element_class);
+ break;
+ }
+ }
}
-static void
-add_css_rule_into_style_sheet_recursive (WebKitDOMDocument *document,
- const gchar *style_sheet_id,
- const gchar *selector,
- const gchar *style)
+void
+e_web_view_set_element_hidden (EWebView *web_view,
+ const gchar *element_id,
+ gboolean hidden)
{
- WebKitDOMNodeList *frames;
- gint ii, length;
+ GDBusProxy *web_extension;
- /* Add rule to document */
- add_css_rule_into_style_sheet (
- document,
- style_sheet_id,
- selector,
- style);
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+ g_return_if_fail (element_id && *element_id);
- frames = webkit_dom_document_query_selector_all (document, "iframe", NULL);
- length = webkit_dom_node_list_get_length (frames);
+ web_extension = e_web_view_get_web_extension_proxy (web_view);
+ if (!web_extension)
+ return;
- /* Add rules to every sub document */
- for (ii = 0; ii < length; ii++) {
- WebKitDOMDocument *iframe_document;
- WebKitDOMNode *node;
+ g_dbus_proxy_call (
+ web_extension,
+ "SetElementHidden",
+ g_variant_new (
+ "(tsb)",
+ webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (web_view)),
+ element_id,
+ hidden),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+}
- node = webkit_dom_node_list_item (frames, ii);
- iframe_document = webkit_dom_html_iframe_element_get_content_document (
- WEBKIT_DOM_HTML_IFRAME_ELEMENT (node));
+void
+e_web_view_set_element_style_property (EWebView *web_view,
+ const gchar *element_id,
+ const gchar *property_name,
+ const gchar *value,
+ const gchar *priority)
+{
+ GDBusProxy *web_extension;
- add_css_rule_into_style_sheet_recursive (
- iframe_document,
- style_sheet_id,
- selector,
- style);
- g_object_unref (node);
- }
- g_object_unref (frames);
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+ g_return_if_fail (element_id && *element_id);
+ g_return_if_fail (property_name && *property_name);
+
+ web_extension = e_web_view_get_web_extension_proxy (web_view);
+ if (!web_extension)
+ return;
+
+ g_dbus_proxy_call (
+ web_extension,
+ "SetElementStyleProperty",
+ g_variant_new (
+ "(tssss)",
+ webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (web_view)),
+ element_id,
+ property_name,
+ value ? value : "",
+ priority ? priority : ""),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
}
-/**
- * e_web_view_add_css_rule_into_style_sheet:
- * @web_view: an #EWebView
- * @style_sheet_id: CSS style sheet's id
- * @selector: CSS selector
- * @style: style for given selector
- *
- * Insert new CSS rule (defined with @selector and @style) into CSS style sheet
- * with given @style_sheet_id. If style sheet doesn't exist, it's created.
- *
- * The rule is inserted to every DOM document that is in page. That means also
- * into DOM documents inside iframe elements.
- **/
void
-e_web_view_add_css_rule_into_style_sheet (EWebView *view,
- const gchar *style_sheet_id,
- const gchar *selector,
- const gchar *style)
+e_web_view_set_element_attribute (EWebView *web_view,
+ const gchar *element_id,
+ const gchar *namespace_uri,
+ const gchar *qualified_name,
+ const gchar *value)
{
- g_return_if_fail (E_IS_WEB_VIEW (view));
- g_return_if_fail (style_sheet_id && *style_sheet_id);
- g_return_if_fail (selector && *selector);
- g_return_if_fail (style && *style);
+ GDBusProxy *web_extension;
- add_css_rule_into_style_sheet_recursive (
- webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (view)),
- style_sheet_id,
- selector,
- style);
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+ g_return_if_fail (element_id && *element_id);
+ g_return_if_fail (qualified_name && *qualified_name);
+
+ web_extension = e_web_view_get_web_extension_proxy (web_view);
+ if (!web_extension)
+ return;
+
+ g_dbus_proxy_call (
+ web_extension,
+ "SetElementAttribute",
+ g_variant_new (
+ "(tssss)",
+ webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (web_view)),
+ element_id,
+ namespace_uri ? namespace_uri : "",
+ qualified_name,
+ value ? value : ""),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
}
diff --git a/e-util/e-web-view.h b/e-util/e-web-view.h
index 545c3bb..62203d2 100644
--- a/e-util/e-web-view.h
+++ b/e-util/e-web-view.h
@@ -28,8 +28,9 @@
#ifndef E_WEB_VIEW_H
#define E_WEB_VIEW_H
-#include <webkit/webkit.h>
+#include <webkit2/webkit2.h>
#include <e-util/e-activity.h>
+#include <e-util/e-content-request.h>
/* Standard GObject macros */
#define E_TYPE_WEB_VIEW \
@@ -56,6 +57,21 @@ typedef struct _EWebView EWebView;
typedef struct _EWebViewClass EWebViewClass;
typedef struct _EWebViewPrivate EWebViewPrivate;
+typedef enum {
+ CID_URI_SCHEME,
+ FILE_URI_SCHEME,
+ MAIL_URI_SCHEME,
+ EVO_HTTP_URI_SCHEME,
+ EVO_HTTPS_URI_SCHEME,
+ GTK_STOCK_URI_SCHEME
+} EURIScheme;
+
+typedef void (*EWebViewElementClickedFunc) (EWebView *web_view,
+ const gchar *element_class,
+ const gchar *element_value,
+ const GtkAllocation *element_position,
+ gpointer user_data);
+
struct _EWebView {
WebKitWebView parent;
EWebViewPrivate *priv;
@@ -78,8 +94,6 @@ struct _EWebViewClass {
const gchar *load_string);
void (*load_uri) (EWebView *web_view,
const gchar *load_uri);
- gchar * (*redirect_uri) (EWebView *web_view,
- const gchar *uri);
gchar * (*suggest_filename) (EWebView *web_view,
const gchar *uri);
void (*set_fonts) (EWebView *web_view,
@@ -97,21 +111,48 @@ struct _EWebViewClass {
void (*update_actions) (EWebView *web_view);
gboolean (*process_mailto) (EWebView *web_view,
const gchar *mailto_uri);
+ void (*uri_requested) (EWebView *web_view,
+ const gchar *uri,
+ gchar **redirect_to_uri);
};
GType e_web_view_get_type (void) G_GNUC_CONST;
GtkWidget * e_web_view_new (void);
+WebKitSettings *
+ e_web_view_get_default_webkit_settings
+ (void);
+void e_web_view_register_content_request_for_scheme
+ (EWebView *web_view,
+ const gchar *scheme,
+ EContentRequest *content_request);
+void e_web_view_update_fonts_settings
+ (GSettings *font_settings,
+ GSettings *aliasing_settings,
+ PangoFontDescription *ms_font,
+ PangoFontDescription *vw_font,
+ GtkWidget *view_widget);
void e_web_view_clear (EWebView *web_view);
void e_web_view_load_string (EWebView *web_view,
const gchar *string);
void e_web_view_load_uri (EWebView *web_view,
const gchar *uri);
-gchar * e_web_view_redirect_uri (EWebView *web_view,
- const gchar *uri);
gchar * e_web_view_suggest_filename (EWebView *web_view,
const gchar *uri);
void e_web_view_reload (EWebView *web_view);
-gchar * e_web_view_get_html (EWebView *web_view);
+void e_web_view_get_content_html (EWebView *web_view,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gchar * e_web_view_get_content_html_finish
+ (EWebView *web_view,
+ GAsyncResult *result,
+ GError **error);
+gchar * e_web_view_get_content_html_sync
+ (EWebView *web_view,
+ GCancellable *cancellable,
+ GError **error);
+GDBusProxy * e_web_view_get_web_extension_proxy
+ (EWebView *web_view);
gboolean e_web_view_get_caret_mode (EWebView *web_view);
void e_web_view_set_caret_mode (EWebView *web_view,
gboolean caret_mode);
@@ -180,7 +221,19 @@ void e_web_view_status_message (EWebView *web_view,
const gchar *status_message);
void e_web_view_stop_loading (EWebView *web_view);
void e_web_view_update_actions (EWebView *web_view);
-gchar * e_web_view_get_selection_html (EWebView *web_view);
+void e_web_view_get_selection_content_html
+ (EWebView *web_view,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gchar * e_web_view_get_selection_content_html_finish
+ (EWebView *web_view,
+ GAsyncResult *result,
+ GError **error);
+gchar * e_web_view_get_selection_content_html_sync
+ (EWebView *web_view,
+ GCancellable *cancellable,
+ GError **error);
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);
@@ -196,7 +249,7 @@ void e_web_view_install_request_handler
(EWebView *web_view,
GType handler_type);
void e_web_view_create_and_add_css_style_sheet
- (WebKitDOMDocument* document,
+ (EWebView *web_view,
const gchar *style_sheet_id);
void e_web_view_add_css_rule_into_style_sheet
(EWebView *web_view,
@@ -205,6 +258,39 @@ void e_web_view_add_css_rule_into_style_sheet
const gchar *style);
const gchar * e_web_view_get_citation_color_for_level
(gint level);
+gchar * e_web_view_get_document_uri_from_point
+ (EWebView *web_view,
+ gint32 x,
+ gint32 y);
+void e_web_view_set_document_iframe_src
+ (EWebView *web_view,
+ const gchar *document_uri,
+ const gchar *new_iframe_src);
+void e_web_view_register_element_clicked
+ (EWebView *web_view,
+ const gchar *element_class,
+ EWebViewElementClickedFunc callback,
+ gpointer user_data);
+void e_web_view_unregister_element_clicked
+ (EWebView *web_view,
+ const gchar *element_class,
+ EWebViewElementClickedFunc callback,
+ gpointer user_data);
+void e_web_view_set_element_hidden (EWebView *web_view,
+ const gchar *element_id,
+ gboolean hidden);
+void e_web_view_set_element_style_property
+ (EWebView *web_view,
+ const gchar *element_id,
+ const gchar *property_name,
+ const gchar *value,
+ const gchar *priority);
+void e_web_view_set_element_attribute
+ (EWebView *web_view,
+ const gchar *element_id,
+ const gchar *namespace_uri,
+ const gchar *qualified_name,
+ const gchar *value);
G_END_DECLS
#endif /* E_WEB_VIEW_H */
diff --git a/e-util/test-html-editor-units-utils.c b/e-util/test-html-editor-units-utils.c
new file mode 100644
index 0000000..911cc98
--- /dev/null
+++ b/e-util/test-html-editor-units-utils.c
@@ -0,0 +1,1045 @@
+/*
+ * Copyright (C) 2016 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library 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.
+ *
+ * This library 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 this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "e-util/e-util.h"
+
+#include "test-html-editor-units-utils.h"
+
+static guint event_processing_delay_ms = 5;
+
+void
+test_utils_set_event_processing_delay_ms (guint value)
+{
+ event_processing_delay_ms = value;
+}
+
+guint
+test_utils_get_event_processing_delay_ms (void)
+{
+ return event_processing_delay_ms;
+}
+
+typedef struct _UndoContent {
+ gchar *html;
+ gchar *plain;
+} UndoContent;
+
+static UndoContent *
+undo_content_new (TestFixture *fixture)
+{
+ EContentEditor *cnt_editor;
+ UndoContent *uc;
+
+ g_return_val_if_fail (fixture != NULL, NULL);
+ g_return_val_if_fail (E_IS_HTML_EDITOR (fixture->editor), NULL);
+
+ cnt_editor = e_html_editor_get_content_editor (fixture->editor);
+
+ uc = g_new0 (UndoContent, 1);
+ uc->html = e_content_editor_get_content (cnt_editor, E_CONTENT_EDITOR_GET_PROCESSED |
E_CONTENT_EDITOR_GET_TEXT_HTML, NULL, NULL);
+ uc->plain = e_content_editor_get_content (cnt_editor, E_CONTENT_EDITOR_GET_PROCESSED |
E_CONTENT_EDITOR_GET_TEXT_PLAIN, NULL, NULL);
+
+ g_warn_if_fail (uc->html != NULL);
+ g_warn_if_fail (uc->plain != NULL);
+
+ return uc;
+}
+
+static void
+undo_content_free (gpointer ptr)
+{
+ UndoContent *uc = ptr;
+
+ if (uc) {
+ g_free (uc->html);
+ g_free (uc->plain);
+ g_free (uc);
+ }
+}
+
+static gboolean
+undo_content_test (TestFixture *fixture,
+ const UndoContent *uc,
+ gint cmd_index)
+{
+ EContentEditor *cnt_editor;
+ gchar *text;
+
+ g_return_val_if_fail (fixture != NULL, FALSE);
+ g_return_val_if_fail (E_IS_HTML_EDITOR (fixture->editor), FALSE);
+ g_return_val_if_fail (uc != NULL, FALSE);
+
+ cnt_editor = e_html_editor_get_content_editor (fixture->editor);
+
+ text = e_content_editor_get_content (cnt_editor, E_CONTENT_EDITOR_GET_PROCESSED |
E_CONTENT_EDITOR_GET_TEXT_HTML, NULL, NULL);
+ g_return_val_if_fail (text != NULL, FALSE);
+
+ if (!test_utils_html_equal (fixture, text, uc->html)) {
+ g_warning ("%s: returned HTML\n---%s---\n and expected HTML\n---%s---\n do not match at
command %d", G_STRFUNC, text, uc->html, cmd_index);
+ g_free (text);
+ return FALSE;
+ }
+
+ g_free (text);
+
+ text = e_content_editor_get_content (cnt_editor, E_CONTENT_EDITOR_GET_PROCESSED |
E_CONTENT_EDITOR_GET_TEXT_PLAIN, NULL, NULL);
+ g_return_val_if_fail (text != NULL, FALSE);
+
+ if (!test_utils_html_equal (fixture, text, uc->plain)) {
+ g_warning ("%s: returned Plain\n---%s---\n and expected Plain\n---%s---\n do not match at
command %d", G_STRFUNC, text, uc->plain, cmd_index);
+ g_free (text);
+ return FALSE;
+ }
+
+ g_free (text);
+
+ return TRUE;
+}
+
+static gboolean
+test_utils_web_process_crashed_cb (WebKitWebView *web_view,
+ gpointer user_data)
+{
+ g_warning ("%s:", G_STRFUNC);
+
+ return FALSE;
+}
+
+typedef struct _CreateData {
+ gpointer async_data;
+ TestFixture *fixture;
+} CreateData;
+
+static void
+test_utils_html_editor_created_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ CreateData *create_data = user_data;
+ TestFixture *fixture;
+ EContentEditor *cnt_editor;
+ GtkWidget *html_editor;
+ GError *error = NULL;
+
+ g_return_if_fail (create_data != NULL);
+
+ fixture = create_data->fixture;
+
+ html_editor = e_html_editor_new_finish (result, &error);
+ if (error) {
+ g_warning ("%s: Failed to create editor: %s", G_STRFUNC, error->message);
+ g_clear_error (&error);
+ return;
+ }
+
+ fixture->editor = E_HTML_EDITOR (html_editor);
+
+ g_object_set (G_OBJECT (fixture->editor),
+ "halign", GTK_ALIGN_FILL,
+ "hexpand", TRUE,
+ "valign", GTK_ALIGN_FILL,
+ "vexpand", TRUE,
+ NULL);
+ gtk_widget_show (GTK_WIDGET (fixture->editor));
+ gtk_container_add (GTK_CONTAINER (fixture->window), GTK_WIDGET (fixture->editor));
+
+ /* Make sure this is off */
+ test_utils_fixture_change_setting_boolean (fixture,
+ "org.gnome.evolution.mail", "prompt-on-composer-mode-switch", FALSE);
+
+ cnt_editor = e_html_editor_get_content_editor (fixture->editor);
+ g_object_set (G_OBJECT (cnt_editor),
+ "halign", GTK_ALIGN_FILL,
+ "hexpand", TRUE,
+ "valign", GTK_ALIGN_FILL,
+ "vexpand", TRUE,
+ "height-request", 150,
+ NULL);
+
+ g_signal_connect (cnt_editor, "web-process-crashed",
+ G_CALLBACK (test_utils_web_process_crashed_cb), NULL);
+
+ gtk_window_set_focus (GTK_WINDOW (fixture->window), GTK_WIDGET (cnt_editor));
+ gtk_widget_show (fixture->window);
+
+ test_utils_async_call_finish (create_data->async_data);
+}
+
+void
+test_utils_fixture_set_up (TestFixture *fixture,
+ gconstpointer user_data)
+{
+ CreateData create_data;
+
+ fixture->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ fixture->undo_stack = NULL;
+ fixture->key_state = 0;
+
+ create_data.async_data = test_utils_async_call_prepare ();
+ create_data.fixture = fixture;
+
+ e_html_editor_new (test_utils_html_editor_created_cb, &create_data);
+
+ test_utils_async_call_wait (create_data.async_data, 5);
+
+ g_warn_if_fail (fixture->editor != NULL);
+ g_warn_if_fail (E_IS_HTML_EDITOR (fixture->editor));
+}
+
+static void
+free_old_settings (gpointer ptr)
+{
+ TestSettings *data = ptr;
+
+ if (data) {
+ GSettings *settings;
+
+ settings = e_util_ref_settings (data->schema);
+ g_settings_set_value (settings, data->key, data->old_value);
+ g_clear_object (&settings);
+
+ g_variant_unref (data->old_value);
+ g_free (data->schema);
+ g_free (data->key);
+ g_free (data);
+ }
+}
+
+void
+test_utils_fixture_tear_down (TestFixture *fixture,
+ gconstpointer user_data)
+{
+ gtk_widget_destroy (GTK_WIDGET (fixture->window));
+ fixture->editor = NULL;
+
+ g_slist_free_full (fixture->settings, free_old_settings);
+ fixture->settings = NULL;
+
+ g_slist_free_full (fixture->undo_stack, undo_content_free);
+ fixture->undo_stack = NULL;
+}
+
+void
+test_utils_fixture_change_setting (TestFixture *fixture,
+ const gchar *schema,
+ const gchar *key,
+ GVariant *value)
+{
+ TestSettings *data;
+ GSettings *settings;
+
+ g_return_if_fail (fixture != NULL);
+ g_return_if_fail (schema != NULL);
+ g_return_if_fail (key != NULL);
+ g_return_if_fail (value != NULL);
+
+ g_variant_ref_sink (value);
+
+ settings = e_util_ref_settings (schema);
+
+ data = g_new0 (TestSettings, 1);
+ data->schema = g_strdup (schema);
+ data->key = g_strdup (key);
+ data->old_value = g_variant_ref_sink (g_settings_get_value (settings, key));
+
+ /* Use prepend, thus the restore comes in the opposite order, thus a change
+ of the same key is not a problem. */
+ fixture->settings = g_slist_prepend (fixture->settings, data);
+
+ g_settings_set_value (settings, key, value);
+
+ g_clear_object (&settings);
+ g_variant_unref (value);
+}
+
+void
+test_utils_fixture_change_setting_boolean (TestFixture *fixture,
+ const gchar *schema,
+ const gchar *key,
+ gboolean value)
+{
+ test_utils_fixture_change_setting (fixture, schema, key, g_variant_new_boolean (value));
+}
+
+void
+test_utils_fixture_change_setting_int32 (TestFixture *fixture,
+ const gchar *schema,
+ const gchar *key,
+ gint value)
+{
+ test_utils_fixture_change_setting (fixture, schema, key, g_variant_new_int32 (value));
+}
+
+void
+test_utils_fixture_change_setting_string (TestFixture *fixture,
+ const gchar *schema,
+ const gchar *key,
+ const gchar *value)
+{
+ test_utils_fixture_change_setting (fixture, schema, key, g_variant_new_string (value));
+}
+
+static void
+test_utils_flush_main_context (void)
+{
+ GMainContext *main_context;
+
+ main_context = g_main_context_default ();
+
+ while (g_main_context_pending (main_context)) {
+ g_main_context_iteration (main_context, FALSE);
+ }
+}
+
+gpointer
+test_utils_async_call_prepare (void)
+{
+ return g_main_loop_new (NULL, FALSE);
+}
+
+typedef struct _AsynCallData {
+ GMainLoop *loop;
+ gboolean timeout_reached;
+} AsyncCallData;
+
+static gboolean
+test_utils_async_call_timeout_reached_cb (gpointer user_data)
+{
+ AsyncCallData *async_call_data = user_data;
+
+ g_return_val_if_fail (async_call_data != NULL, FALSE);
+ g_return_val_if_fail (async_call_data->loop != NULL, FALSE);
+ g_return_val_if_fail (!async_call_data->timeout_reached, FALSE);
+
+ if (!g_source_is_destroyed (g_main_current_source ())) {
+ async_call_data->timeout_reached = TRUE;
+ g_main_loop_quit (async_call_data->loop);
+ }
+
+ return FALSE;
+}
+
+gboolean
+test_utils_async_call_wait (gpointer async_data,
+ guint timeout_seconds)
+{
+ GMainLoop *loop = async_data;
+ AsyncCallData async_call_data;
+ GSource *source = NULL;
+
+ g_return_val_if_fail (loop != NULL, FALSE);
+
+ async_call_data.loop = loop;
+ async_call_data.timeout_reached = FALSE;
+
+ /* 0 is to wait forever */
+ if (timeout_seconds > 0) {
+ source = g_timeout_source_new_seconds (timeout_seconds);
+ g_source_set_callback (source, test_utils_async_call_timeout_reached_cb, &async_call_data,
NULL);
+ g_source_attach (source, NULL);
+ }
+
+ g_main_loop_run (loop);
+
+ if (source) {
+ g_source_destroy (source);
+ g_source_unref (source);
+ }
+
+ test_utils_flush_main_context ();
+
+ g_main_loop_unref (loop);
+
+ return !async_call_data.timeout_reached;
+}
+
+gboolean
+test_utils_async_call_finish (gpointer async_data)
+{
+ GMainLoop *loop = async_data;
+
+ g_return_val_if_fail (loop != NULL, FALSE);
+
+ g_main_loop_quit (loop);
+
+ return FALSE;
+}
+
+gboolean
+test_utils_wait_milliseconds (guint milliseconds)
+{
+ gpointer async_data;
+
+ async_data = test_utils_async_call_prepare ();
+ g_timeout_add (milliseconds, test_utils_async_call_finish, async_data);
+
+ return test_utils_async_call_wait (async_data, milliseconds / 1000 + 1);
+}
+
+static void
+test_utils_send_key_event (GtkWidget *widget,
+ GdkEventType type,
+ guint keyval,
+ guint state)
+{
+ GdkKeymap *keymap;
+ GdkKeymapKey *keys = NULL;
+ gint n_keys;
+ GdkEvent *event;
+
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+
+ event = gdk_event_new (type);
+ event->key.is_modifier =
+ keyval == GDK_KEY_Shift_L ||
+ keyval == GDK_KEY_Shift_R ||
+ keyval == GDK_KEY_Control_L ||
+ keyval == GDK_KEY_Control_R ||
+ keyval == GDK_KEY_Alt_L ||
+ keyval == GDK_KEY_Alt_R;
+ event->key.keyval = keyval;
+ event->key.state = state;
+ event->key.window = g_object_ref (gtk_widget_get_window (widget));
+ event->key.send_event = TRUE;
+ event->key.length = 0;
+ event->key.string = NULL;
+ event->key.hardware_keycode = 0;
+ event->key.group = 0;
+ event->key.time = GDK_CURRENT_TIME;
+
+ gdk_event_set_device (event, gdk_seat_get_keyboard (gdk_display_get_default_seat
(gtk_widget_get_display (widget))));
+
+ keymap = gdk_keymap_get_for_display (gtk_widget_get_display (widget));
+ if (gdk_keymap_get_entries_for_keyval (keymap, keyval, &keys, &n_keys)) {
+ if (n_keys > 0) {
+ event->key.hardware_keycode = keys[0].keycode;
+ event->key.group = keys[0].group;
+ }
+
+ g_free (keys);
+ }
+
+ gtk_main_do_event (event);
+
+ test_utils_wait_milliseconds (event_processing_delay_ms);
+
+ gdk_event_free (event);
+}
+
+gboolean
+test_utils_type_text (TestFixture *fixture,
+ const gchar *text)
+{
+ GtkWidget *widget;
+
+ g_return_val_if_fail (fixture != NULL, FALSE);
+ g_return_val_if_fail (E_IS_HTML_EDITOR (fixture->editor), FALSE);
+
+ widget = GTK_WIDGET (e_html_editor_get_content_editor (fixture->editor));
+ g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
+
+ g_return_val_if_fail (text != NULL, FALSE);
+ g_return_val_if_fail (g_utf8_validate (text, -1, NULL), FALSE);
+
+ while (*text) {
+ guint keyval;
+ gunichar unichar;
+
+ unichar = g_utf8_get_char (text);
+ text = g_utf8_next_char (text);
+
+ switch (unichar) {
+ case '\n':
+ keyval = GDK_KEY_Return;
+ break;
+ case '\t':
+ keyval = GDK_KEY_Tab;
+ break;
+ case '\b':
+ keyval = GDK_KEY_BackSpace;
+ break;
+ default:
+ keyval = gdk_unicode_to_keyval (unichar);
+ break;
+ }
+
+ test_utils_send_key_event (widget, GDK_KEY_PRESS, keyval, fixture->key_state);
+ test_utils_send_key_event (widget, GDK_KEY_RELEASE, keyval, fixture->key_state);
+ }
+
+ test_utils_wait_milliseconds (event_processing_delay_ms);
+
+ return TRUE;
+}
+
+static void
+sync_wrapper_result_callback (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GAsyncResult **out_async_result = user_data;
+
+ g_return_if_fail (out_async_result != NULL);
+ g_return_if_fail (*out_async_result == NULL);
+
+ *out_async_result = g_object_ref (result);
+}
+
+/* Wraps GDBusProxy synchronous call into an asynchronous without blocking
+ the main context, thus there is no freeze when this is called in the UI
+ process and the WebProcess also does its own IPC call. */
+static GVariant *
+g_dbus_proxy_call_sync_wrapper (GDBusProxy *proxy,
+ const gchar *method_name,
+ GVariant *parameters,
+ GDBusCallFlags flags,
+ gint timeout_msec,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GAsyncResult *async_result = NULL;
+ GVariant *var_result;
+
+ g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), NULL);
+ g_return_val_if_fail (method_name != NULL, NULL);
+
+ g_dbus_proxy_call (
+ proxy, method_name, parameters, flags, timeout_msec, cancellable,
+ sync_wrapper_result_callback, &async_result);
+
+ while (!async_result) {
+ g_main_context_iteration (NULL, TRUE);
+ }
+
+ var_result = g_dbus_proxy_call_finish (proxy, async_result, error);
+
+ g_clear_object (&async_result);
+
+ return var_result;
+}
+
+gboolean
+test_utils_html_equal (TestFixture *fixture,
+ const gchar *html1,
+ const gchar *html2)
+{
+ EContentEditor *cnt_editor;
+ GDBusProxy *web_extension = NULL;
+ GVariant *result;
+ GError *error = NULL;
+ gboolean html_equal = FALSE;
+
+ g_return_val_if_fail (fixture != NULL, FALSE);
+ g_return_val_if_fail (E_IS_HTML_EDITOR (fixture->editor), FALSE);
+ g_return_val_if_fail (html1 != NULL, FALSE);
+ g_return_val_if_fail (html2 != NULL, FALSE);
+
+ cnt_editor = e_html_editor_get_content_editor (fixture->editor);
+ g_return_val_if_fail (cnt_editor != NULL, FALSE);
+
+ g_object_get (cnt_editor, "web-extension", &web_extension, NULL);
+
+ g_return_val_if_fail (G_IS_DBUS_PROXY (web_extension), FALSE);
+
+ result = g_dbus_proxy_call_sync_wrapper (
+ web_extension,
+ "TestHTMLEqual",
+ g_variant_new ("(tss)", webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (cnt_editor)), html1,
html2),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ &error);
+ g_assert_no_error (error);
+
+ g_clear_error (&error);
+
+ g_return_val_if_fail (result != NULL, FALSE);
+
+ g_variant_get (result, "(b)", &html_equal);
+ g_variant_unref (result);
+
+ return html_equal;
+}
+
+static gboolean
+test_utils_process_sequence (TestFixture *fixture,
+ const gchar *sequence)
+{
+ GtkWidget *widget;
+ const gchar *seq;
+ guint keyval;
+ gboolean success = TRUE;
+
+ g_return_val_if_fail (fixture != NULL, FALSE);
+ g_return_val_if_fail (E_IS_HTML_EDITOR (fixture->editor), FALSE);
+ g_return_val_if_fail (sequence != NULL, FALSE);
+
+ widget = GTK_WIDGET (e_html_editor_get_content_editor (fixture->editor));
+ g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
+
+ for (seq = sequence; *seq && success; seq++) {
+ gboolean call_press = TRUE, call_release = TRUE;
+ guint change_state = fixture->key_state;
+
+ switch (*seq) {
+ case 'S': /* Shift key press */
+ keyval = GDK_KEY_Shift_L;
+
+ if ((fixture->key_state & GDK_SHIFT_MASK) != 0) {
+ success = FALSE;
+ g_warning ("%s: Shift is already pressed", G_STRFUNC);
+ } else {
+ change_state |= GDK_SHIFT_MASK;
+ }
+ call_release = FALSE;
+ break;
+ case 's': /* Shift key release */
+ keyval = GDK_KEY_Shift_L;
+
+ if ((fixture->key_state & GDK_SHIFT_MASK) == 0) {
+ success = FALSE;
+ g_warning ("%s: Shift is already released", G_STRFUNC);
+ } else {
+ change_state &= ~GDK_SHIFT_MASK;
+ }
+ call_press = FALSE;
+ break;
+ case 'C': /* Ctrl key press */
+ keyval = GDK_KEY_Control_L;
+
+ if ((fixture->key_state & GDK_CONTROL_MASK) != 0) {
+ success = FALSE;
+ g_warning ("%s: Control is already pressed", G_STRFUNC);
+ } else {
+ change_state |= GDK_CONTROL_MASK;
+ }
+ call_release = FALSE;
+ break;
+ case 'c': /* Ctrl key release */
+ keyval = GDK_KEY_Control_L;
+
+ if ((fixture->key_state & GDK_CONTROL_MASK) == 0) {
+ success = FALSE;
+ g_warning ("%s: Control is already released", G_STRFUNC);
+ } else {
+ change_state &= ~GDK_CONTROL_MASK;
+ }
+ call_press = FALSE;
+ break;
+ case 'A': /* Alt key press */
+ keyval = GDK_KEY_Alt_L;
+
+ if ((fixture->key_state & GDK_MOD1_MASK) != 0) {
+ success = FALSE;
+ g_warning ("%s: Alt is already pressed", G_STRFUNC);
+ } else {
+ change_state |= GDK_MOD1_MASK;
+ }
+ call_release = FALSE;
+ break;
+ case 'a': /* Alt key release */
+ keyval = GDK_KEY_Alt_L;
+
+ if ((fixture->key_state & GDK_MOD1_MASK) == 0) {
+ success = FALSE;
+ g_warning ("%s: Alt is already released", G_STRFUNC);
+ } else {
+ change_state &= ~GDK_MOD1_MASK;
+ }
+ call_press = FALSE;
+ break;
+ case 'h': /* Home key press + release */
+ keyval = GDK_KEY_Home;
+ break;
+ case 'e': /* End key press + release */
+ keyval = GDK_KEY_End;
+ break;
+ case 'P': /* Page-Up key press + release */
+ keyval = GDK_KEY_Page_Up;
+ break;
+ case 'p': /* Page-Down key press + release */
+ keyval = GDK_KEY_Page_Down;
+ break;
+ case 'l': /* Arrow-Left key press + release */
+ keyval = GDK_KEY_Left;
+ break;
+ case 'r': /* Arrow-Right key press + release */
+ keyval = GDK_KEY_Right;
+ break;
+ case 'u': /* Arrow-Up key press + release */
+ keyval = GDK_KEY_Up;
+ break;
+ case 'd': /* Arrow-Down key press + release */
+ keyval = GDK_KEY_Down;
+ break;
+ case 'D': /* Delete key press + release */
+ keyval = GDK_KEY_Delete;
+ break;
+ case 'b': /* Backspace key press + release */
+ keyval = GDK_KEY_BackSpace;
+ break;
+ case 't': /* Tab key press + release */
+ keyval = GDK_KEY_Tab;
+ break;
+ case 'n': /* Return key press + release */
+ keyval = GDK_KEY_Return;
+ break;
+ default:
+ success = FALSE;
+ g_warning ("%s: Unknown sequence command '%c' in sequence '%s'", G_STRFUNC, *seq,
sequence);
+ break;
+ }
+
+ if (success) {
+ if (call_press)
+ test_utils_send_key_event (widget, GDK_KEY_PRESS, keyval, fixture->key_state);
+
+ if (call_release)
+ test_utils_send_key_event (widget, GDK_KEY_RELEASE, keyval,
fixture->key_state);
+ }
+
+ fixture->key_state = change_state;
+ }
+
+ test_utils_wait_milliseconds (event_processing_delay_ms);
+
+ return success;
+}
+
+static gboolean
+test_utils_execute_action (TestFixture *fixture,
+ const gchar *action_name)
+{
+ GtkAction *action;
+
+ g_return_val_if_fail (fixture != NULL, FALSE);
+ g_return_val_if_fail (E_IS_HTML_EDITOR (fixture->editor), FALSE);
+ g_return_val_if_fail (action_name != NULL, FALSE);
+
+ action = e_html_editor_get_action (fixture->editor, action_name);
+ if (action) {
+ gtk_action_activate (action);
+ } else {
+ g_warning ("%s: Failed to find action '%s'", G_STRFUNC, action_name);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* Expects only the part like "undo" [ ":" number ] */
+static gint
+test_utils_maybe_extract_undo_number (const gchar *command)
+{
+ const gchar *ptr;
+ gint number;
+
+ g_return_val_if_fail (command != NULL, -1);
+
+ ptr = strchr (command, ':');
+ if (!ptr)
+ return 1;
+
+ number = atoi (ptr + 1);
+ g_return_val_if_fail (number > 0, -1);
+
+ return number;
+}
+
+static const UndoContent *
+test_utils_pick_undo_content (const GSList *undo_stack,
+ gint number)
+{
+ const GSList *link;
+
+ g_return_val_if_fail (undo_stack != NULL, NULL);
+
+ number--;
+ for (link = undo_stack; link && number > 0; link = g_slist_next (link)) {
+ number--;
+ }
+
+ g_return_val_if_fail (link != NULL, NULL);
+ g_return_val_if_fail (link->data != NULL, NULL);
+
+ return link->data;
+}
+
+/* Each line of 'commands' contains one command.
+
+ commands = command *("\n" command)
+
+ command = actioncmd ; Execute an action
+ / modecmd ; Change editor mode to HTML or Plain Text
+ / seqcmd ; Sequence of special key strokes
+ / typecmd ; Type a text
+ / undocmd ; Undo/redo commands
+ / waitcmd ; Wait command
+
+ actioncmd = "action:" name
+
+ actioncmd = "mode:" ("html" / "plain")
+
+ seqcmd = "seq:" sequence
+
+ sequence = "S" ; Shift key press
+ / "s" ; Shift key release
+ / "C" ; Ctrl key press
+ / "c" ; Ctrl key release
+ / "A" ; Alt key press
+ / "a" ; Alt key release
+ / "h" ; Home key press + release
+ / "e" ; End key press + release
+ / "P" ; Page-Up key press + release
+ / "p" ; Page-Down key press + release
+ / "l" ; Arrow-Left key press + release
+ / "r" ; Arrow-Right key press + release
+ / "u" ; Arrow-Up key press + release
+ / "d" ; Arrow-Down key press + release
+ / "D" ; Delete key press + release
+ / "b" ; Backspace key press + release
+ / "t" ; Tab key press + release
+ / "n" ; Return key press + release
+
+ typecmd = "type:" text ; the 'text' can contain escaped letters with a backslash, like "\\n" transforms
into "\n"
+
+ undocmd = "undo:" undotype
+
+ undotype = "undo" [ ":" number ] ; Call 'undo', number-times; if 'number' is not provided, then call it
exactly once
+ / "redo" [ ":" number ] ; Call 'redo', number-times; if 'number' is not provided, then call it
exactly once
+ / "save" ; Save current content of the editor for later tests
+ / "drop" [ ":" number ] ; Forgets saved content, if 'number' is provided, then top number saves
are forgotten
+ / "test" [ ":" number ] ; Tests current editor content against any previously saved state; the
optional
+ ; 'number' argument can be used to specify which exact previous state
to use
+
+ waitcmd = "wait:" milliseconds ; waits for 'milliseconds'
+ */
+gboolean
+test_utils_process_commands (TestFixture *fixture,
+ const gchar *commands)
+{
+ gchar **cmds;
+ gint cc;
+ gboolean success = TRUE;
+
+ g_return_val_if_fail (fixture != NULL, FALSE);
+ g_return_val_if_fail (E_IS_HTML_EDITOR (fixture->editor), FALSE);
+ g_return_val_if_fail (commands != NULL, FALSE);
+
+ cmds = g_strsplit (commands, "\n", -1);
+ for (cc = 0; cmds && cmds[cc] && success; cc++) {
+ const gchar *command = cmds[cc];
+
+ if (g_str_has_prefix (command, "action:")) {
+ test_utils_execute_action (fixture, command + 7);
+ } else if (g_str_has_prefix (command, "mode:")) {
+ const gchar *mode_change = command + 5;
+
+ if (g_str_equal (mode_change, "html")) {
+ test_utils_execute_action (fixture, "mode-html");
+ } else if (g_str_equal (mode_change, "plain")) {
+ test_utils_execute_action (fixture, "mode-plain");
+ } else {
+ success = FALSE;
+ g_warning ("%s: Unknown mode '%s'", G_STRFUNC, mode_change);
+ }
+ } else if (g_str_has_prefix (command, "seq:")) {
+ success = test_utils_process_sequence (fixture, command + 4);
+ } else if (g_str_has_prefix (command, "type:")) {
+ gchar *text;
+
+ text = g_strcompress (command + 5);
+ success = test_utils_type_text (fixture, text);
+ if (!success)
+ g_warning ("%s: Failed to type text '%s'", G_STRFUNC, text);
+ g_free (text);
+ } else if (g_str_has_prefix (command, "undo:")) {
+ gint number;
+
+ command += 5;
+
+ if (g_str_equal (command, "undo") || g_str_has_prefix (command, "undo:")) {
+ number = test_utils_maybe_extract_undo_number (command);
+ while (number > 0 && success) {
+ success = test_utils_execute_action (fixture, "undo");
+ number--;
+ }
+ } else if (g_str_has_prefix (command, "redo") || g_str_has_prefix (command, "redo:"))
{
+ number = test_utils_maybe_extract_undo_number (command);
+ while (number > 0 && success) {
+ success = test_utils_execute_action (fixture, "redo");
+ number--;
+ }
+ } else if (g_str_equal (command, "save")) {
+ UndoContent *uc;
+
+ uc = undo_content_new (fixture);
+ fixture->undo_stack = g_slist_prepend (fixture->undo_stack, uc);
+ } else if (g_str_equal (command, "drop") || g_str_has_prefix (command, "drop:")) {
+ number = test_utils_maybe_extract_undo_number (command);
+ g_warn_if_fail (number <= g_slist_length (fixture->undo_stack));
+
+ while (number > 0 && fixture->undo_stack) {
+ UndoContent *uc = fixture->undo_stack->data;
+
+ fixture->undo_stack = g_slist_remove (fixture->undo_stack, uc);
+ undo_content_free (uc);
+ number--;
+ }
+ } else if (g_str_equal (command, "test") || g_str_has_prefix (command, "test:")) {
+ const UndoContent *uc;
+
+ number = test_utils_maybe_extract_undo_number (command);
+ uc = test_utils_pick_undo_content (fixture->undo_stack, number);
+ success = uc && undo_content_test (fixture, uc, cc);
+ } else {
+ g_warning ("%s: Unknown command 'undo:%s'", G_STRFUNC, command);
+ success = FALSE;
+ }
+
+ test_utils_wait_milliseconds (event_processing_delay_ms);
+ } else if (g_str_has_prefix (command, "wait:")) {
+ test_utils_wait_milliseconds (atoi (command + 5));
+ } else if (*command) {
+ g_warning ("%s: Unknown command '%s'", G_STRFUNC, command);
+ success = FALSE;
+ }
+
+ /* Wait at least 100 ms, to give a chance to move the cursor and
+ other things for WebKit, for example before executing actions. */
+ test_utils_wait_milliseconds (MAX (event_processing_delay_ms, 100));
+ }
+
+ g_strfreev (cmds);
+
+ if (success) {
+ /* Give the editor some time to finish any ongoing async operations */
+ test_utils_wait_milliseconds (MAX (event_processing_delay_ms, 100));
+ }
+
+ return success;
+}
+
+gboolean
+test_utils_run_simple_test (TestFixture *fixture,
+ const gchar *commands,
+ const gchar *expected_html,
+ const gchar *expected_plain)
+{
+ EContentEditor *cnt_editor;
+ gchar *text;
+
+ g_return_val_if_fail (fixture != NULL, FALSE);
+ g_return_val_if_fail (E_IS_HTML_EDITOR (fixture->editor), FALSE);
+ g_return_val_if_fail (commands != NULL, FALSE);
+
+ cnt_editor = e_html_editor_get_content_editor (fixture->editor);
+
+ if (!test_utils_process_commands (fixture, commands))
+ return FALSE;
+
+ if (expected_html) {
+ text = e_content_editor_get_content (cnt_editor, E_CONTENT_EDITOR_GET_PROCESSED |
E_CONTENT_EDITOR_GET_TEXT_HTML, NULL, NULL);
+ g_return_val_if_fail (text != NULL, FALSE);
+
+ if (!test_utils_html_equal (fixture, text, expected_html)) {
+ g_warning ("%s: returned HTML\n---%s---\n and expected HTML\n---%s---\n do not
match", G_STRFUNC, text, expected_html);
+ g_free (text);
+ return FALSE;
+ }
+
+ g_free (text);
+ }
+
+ if (expected_plain) {
+ text = e_content_editor_get_content (cnt_editor, E_CONTENT_EDITOR_GET_PROCESSED |
E_CONTENT_EDITOR_GET_TEXT_PLAIN, NULL, NULL);
+ g_return_val_if_fail (text != NULL, FALSE);
+
+ if (!test_utils_html_equal (fixture, text, expected_plain)) {
+ g_warning ("%s: returned Plain\n---%s---\n and expected Plain\n---%s---\n do not
match", G_STRFUNC, text, expected_plain);
+ g_free (text);
+ return FALSE;
+ }
+
+ g_free (text);
+ }
+
+ return TRUE;
+}
+
+void
+test_utils_insert_content (TestFixture *fixture,
+ const gchar *content,
+ EContentEditorInsertContentFlags flags)
+{
+ EContentEditor *cnt_editor;
+
+ g_return_if_fail (fixture != NULL);
+ g_return_if_fail (E_IS_HTML_EDITOR (fixture->editor));
+ g_return_if_fail (content != NULL);
+
+ cnt_editor = e_html_editor_get_content_editor (fixture->editor);
+ e_content_editor_insert_content (cnt_editor, content, flags);
+}
+
+void
+test_utils_set_clipboard_text (const gchar *text,
+ gboolean is_html)
+{
+ GtkClipboard *clipboard;
+
+ g_return_if_fail (text != NULL);
+
+ clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
+ g_return_if_fail (clipboard != NULL);
+
+ gtk_clipboard_clear (clipboard);
+
+ if (is_html) {
+ e_clipboard_set_html (clipboard, text, -1);
+ } else {
+ gtk_clipboard_set_text (clipboard, text, -1);
+ }
+}
+
+gchar *
+test_utils_get_clipboard_text (gboolean request_html)
+{
+ GtkClipboard *clipboard;
+ gchar *text;
+
+ clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
+ g_return_val_if_fail (clipboard != NULL, NULL);
+
+ if (request_html) {
+ g_return_val_if_fail (e_clipboard_wait_is_html_available (clipboard), NULL);
+ text = e_clipboard_wait_for_html (clipboard);
+ } else {
+ g_return_val_if_fail (gtk_clipboard_wait_is_text_available (clipboard), NULL);
+ text = gtk_clipboard_wait_for_text (clipboard);
+ }
+
+ g_return_val_if_fail (text != NULL, NULL);
+
+ return text;
+}
diff --git a/e-util/test-html-editor-units-utils.h b/e-util/test-html-editor-units-utils.h
new file mode 100644
index 0000000..f9d045f
--- /dev/null
+++ b/e-util/test-html-editor-units-utils.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2016 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library 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.
+ *
+ * This library 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 this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef TEST_HTML_EDITOR_UNITS_UTILS_H
+#define TEST_HTML_EDITOR_UNITS_UTILS_H
+
+#include <glib.h>
+#include <e-util/e-util.h>
+
+typedef struct _TestSettings {
+ gchar *schema;
+ gchar *key;
+ GVariant *old_value;
+} TestSettings;
+
+typedef struct _TestFixture {
+ GtkWidget *window;
+ EHTMLEditor *editor;
+ GSList *settings; /* TestSettings * */
+ guint key_state;
+
+ GSList *undo_stack; /* UndoContent * */
+} TestFixture;
+
+void test_utils_set_event_processing_delay_ms
+ (guint value);
+guint test_utils_get_event_processing_delay_ms
+ (void);
+void test_utils_fixture_set_up (TestFixture *fixture,
+ gconstpointer user_data);
+void test_utils_fixture_tear_down (TestFixture *fixture,
+ gconstpointer user_data);
+void test_utils_fixture_change_setting
+ (TestFixture *fixture,
+ const gchar *schema,
+ const gchar *key,
+ GVariant *value);
+void test_utils_fixture_change_setting_boolean
+ (TestFixture *fixture,
+ const gchar *schema,
+ const gchar *key,
+ gboolean value);
+void test_utils_fixture_change_setting_int32
+ (TestFixture *fixture,
+ const gchar *schema,
+ const gchar *key,
+ gint value);
+void test_utils_fixture_change_setting_string
+ (TestFixture *fixture,
+ const gchar *schema,
+ const gchar *key,
+ const gchar *value);
+gpointer test_utils_async_call_prepare (void);
+gboolean test_utils_async_call_wait (gpointer async_data,
+ guint timeout_seconds);
+gboolean test_utils_async_call_finish (gpointer async_data);
+gboolean test_utils_wait_milliseconds (guint milliseconds);
+gboolean test_utils_type_text (TestFixture *fixture,
+ const gchar *text);
+gboolean test_utils_html_equal (TestFixture *fixture,
+ const gchar *html1,
+ const gchar *html2);
+gboolean test_utils_process_commands (TestFixture *fixture,
+ const gchar *commands);
+gboolean test_utils_run_simple_test (TestFixture *fixture,
+ const gchar *commands,
+ const gchar *expected_html,
+ const gchar *expected_plain);
+void test_utils_insert_content (TestFixture *fixture,
+ const gchar *content,
+ EContentEditorInsertContentFlags flags);
+void test_utils_set_clipboard_text (const gchar *text,
+ gboolean is_html);
+gchar * test_utils_get_clipboard_text (gboolean request_html);
+
+#endif /* TEST_HTML_EDITOR_UNITS_UTILS_H */
diff --git a/e-util/test-html-editor-units.c b/e-util/test-html-editor-units.c
new file mode 100644
index 0000000..c72a9a2
--- /dev/null
+++ b/e-util/test-html-editor-units.c
@@ -0,0 +1,2823 @@
+/*
+ * Copyright (C) 2016 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library 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.
+ *
+ * This library 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 this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <locale.h>
+#include <e-util/e-util.h>
+
+#include "e-html-editor-private.h"
+#include "test-html-editor-units-utils.h"
+
+#define HTML_PREFIX "<html><head></head><body>"
+#define HTML_PREFIX_PLAIN "<html><head></head><body style=\"font-family: Monospace;\">"
+#define HTML_SUFFIX "</body></html>"
+
+/* The tests do not use the 'user_data' argument, thus the functions avoid them and the typecast is needed.
*/
+typedef void (* ETestFixtureFunc) (TestFixture *fixture, gconstpointer user_data);
+
+static void
+test_create_editor (TestFixture *fixture)
+{
+ g_assert (fixture->editor != NULL);
+ g_assert_cmpstr (e_html_editor_get_content_editor_name (fixture->editor), ==,
DEFAULT_CONTENT_EDITOR_NAME);
+
+ /* test of the test function */
+ g_assert (test_utils_html_equal (fixture, "<span>a</span>", "<sPaN>a</spaN>"));
+ g_assert (!test_utils_html_equal (fixture, "<span>A</span>", "<sPaN>a</spaN>"));
+}
+
+static void
+test_style_bold_selection (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:some bold text\n"
+ "seq:hCrcrCSrsc\n"
+ "action:bold\n",
+ HTML_PREFIX "<p>some <b>bold</b> text</p>" HTML_SUFFIX,
+ "some bold text"))
+ g_test_fail ();
+}
+
+static void
+test_style_bold_typed (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:some \n"
+ "action:bold\n"
+ "type:bold\n"
+ "action:bold\n"
+ "type: text\n",
+ HTML_PREFIX "<p>some <b>bold</b> text</p>" HTML_SUFFIX,
+ "some bold text"))
+ g_test_fail ();
+}
+
+static void
+test_style_italic_selection (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:some italic text\n"
+ "seq:hCrcrCSrsc\n"
+ "action:italic\n",
+ HTML_PREFIX "<p>some <i>italic</i> text</p>" HTML_SUFFIX,
+ "some italic text"))
+ g_test_fail ();
+}
+
+static void
+test_style_italic_typed (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:some \n"
+ "action:italic\n"
+ "type:italic\n"
+ "action:italic\n"
+ "type: text\n",
+ HTML_PREFIX "<p>some <i>italic</i> text</p>" HTML_SUFFIX,
+ "some italic text"))
+ g_test_fail ();
+}
+
+static void
+test_style_underline_selection (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:some underline text\n"
+ "seq:hCrcrCSrsc\n"
+ "action:underline\n",
+ HTML_PREFIX "<p>some <u>underline</u> text</p>" HTML_SUFFIX,
+ "some underline text"))
+ g_test_fail ();
+}
+
+static void
+test_style_underline_typed (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:some \n"
+ "action:underline\n"
+ "type:underline\n"
+ "action:underline\n"
+ "type: text\n",
+ HTML_PREFIX "<p>some <u>underline</u> text</p>" HTML_SUFFIX,
+ "some underline text"))
+ g_test_fail ();
+}
+
+static void
+test_style_strikethrough_selection (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:some strikethrough text\n"
+ "seq:hCrcrCSrsc\n"
+ "action:strikethrough\n",
+ HTML_PREFIX "<p>some <strike>strikethrough</strike> text</p>" HTML_SUFFIX,
+ "some strikethrough text"))
+ g_test_fail ();
+}
+
+static void
+test_style_strikethrough_typed (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:some \n"
+ "action:strikethrough\n"
+ "type:strikethrough\n"
+ "action:strikethrough\n"
+ "type: text\n",
+ HTML_PREFIX "<p>some <strike>strikethrough</strike> text</p>" HTML_SUFFIX,
+ "some strikethrough text"))
+ g_test_fail ();
+}
+
+static void
+test_style_monospace_selection (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:some monospace text\n"
+ "seq:hCrcrCSrsc\n"
+ "action:monospaced\n",
+ HTML_PREFIX "<p>some <font face=\"monospace\" size=\"3\">monospace</font> text</p>"
HTML_SUFFIX,
+ "some monospace text"))
+ g_test_fail ();
+}
+
+static void
+test_style_monospace_typed (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:some \n"
+ "action:monospaced\n"
+ "type:monospace\n"
+ "action:monospaced\n"
+ "type: text\n",
+ HTML_PREFIX "<p>some <font face=\"monospace\" size=\"3\">monospace</font> text</p>"
HTML_SUFFIX,
+ "some monospace text"))
+ g_test_fail ();
+}
+
+static void
+test_justify_selection (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:center\\n\n"
+ "type:right\\n\n"
+ "type:left\\n\n"
+ "seq:uuu\n"
+ "action:justify-center\n"
+ "seq:d\n"
+ "action:justify-right\n"
+ "seq:d\n"
+ "action:justify-left\n",
+ HTML_PREFIX
+ "<p style=\"text-align: center\">center</p>"
+ "<p style=\"text-align: right\">right</p>"
+ "<p>left</p><p><br></p>"
+ HTML_SUFFIX,
+ " center\n"
+ " right\n"
+ "left\n"))
+ g_test_fail ();
+}
+
+static void
+test_justify_typed (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "action:justify-center\n"
+ "type:center\\n\n"
+ "action:justify-right\n"
+ "type:right\\n\n"
+ "action:justify-left\n"
+ "type:left\\n\n",
+ HTML_PREFIX
+ "<p style=\"text-align: center\">center</p>"
+ "<p style=\"text-align: right\">right</p>"
+ "<p>left</p><p><br></p>"
+ HTML_SUFFIX,
+ " center\n"
+ " right\n"
+ "left\n"))
+ g_test_fail ();
+}
+
+static void
+test_indent_selection (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:level 0\\n\n"
+ "type:level 1\\n\n"
+ "type:level 2\\n\n"
+ "type:level 1\\n\n"
+ "seq:uuu\n"
+ "action:indent\n"
+ "seq:d\n"
+ "action:indent\n"
+ "action:indent\n"
+ "seq:d\n"
+ "action:indent\n"
+ "action:indent\n" /* just to try whether the unindent will work too */
+ "action:unindent\n",
+ HTML_PREFIX
+ "<p>level 0</p>"
+ "<div style=\"margin-left: 3ch;\">"
+ "<p>level 1</p>"
+ "<div style=\"margin-left: 3ch;\"><p>level 2</p></div>"
+ "<p>level 1</p>"
+ "</div><p><br></p>"
+ HTML_SUFFIX,
+ "level 0\n"
+ " level 1\n"
+ " level 2\n"
+ " level 1\n"))
+ g_test_fail ();
+}
+
+static void
+test_indent_typed (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:level 0\\n\n"
+ "action:indent\n"
+ "type:level 1\\n\n"
+ "action:indent\n"
+ "type:level 2\\n\n"
+ "action:unindent\n"
+ "type:level 1\\n\n"
+ "action:unindent\n",
+ HTML_PREFIX
+ "<p>level 0</p>"
+ "<div style=\"margin-left: 3ch;\">"
+ "<p>level 1</p>"
+ "<div style=\"margin-left: 3ch;\"><p>level 2</p></div>"
+ "<p>level 1</p>"
+ "</div><p><br></p>"
+ HTML_SUFFIX,
+ "level 0\n"
+ " level 1\n"
+ " level 2\n"
+ " level 1\n"))
+ g_test_fail ();
+}
+
+static void
+test_font_size_selection (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:FontM2 FontM1 Font0 FontP1 FontP2 FontP3 FontP4\n"
+ "seq:hCSrsc\n"
+ "action:size-minus-two\n"
+ "seq:rrCSrcs\n"
+ "action:size-minus-one\n"
+ "seq:rrCSrcs\n"
+ "action:size-plus-zero\n"
+ "seq:rrCSrcs\n"
+ "action:size-plus-one\n"
+ "seq:rrCSrcs\n"
+ "action:size-plus-two\n"
+ "seq:rrCSrcs\n"
+ "action:size-plus-three\n"
+ "seq:rrCSrcs\n"
+ "action:size-plus-four\n",
+ HTML_PREFIX "<p><font size=\"1\">FontM2</font> <font size=\"2\">FontM1</font> Font0 <font
size=\"4\">FontP1</font> "
+ "<font size=\"5\">FontP2</font> <font size=\"6\">FontP3</font> <font
size=\"7\">FontP4</font></p>" HTML_SUFFIX,
+ "FontM2 FontM1 Font0 FontP1 FontP2 FontP3 FontP4"))
+ g_test_fail ();
+}
+
+static void
+test_font_size_typed (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "action:size-minus-two\n"
+ "type:FontM2\n"
+ "action:size-plus-zero\n"
+ "type: \n"
+ "action:size-minus-one\n"
+ "type:FontM1\n"
+ "action:size-plus-zero\n"
+ "type: \n"
+ "type:Font0\n"
+ "action:size-plus-zero\n"
+ "type: \n"
+ "action:size-plus-one\n"
+ "type:FontP1\n"
+ "action:size-plus-zero\n"
+ "type: \n"
+ "action:size-plus-two\n"
+ "type:FontP2\n"
+ "action:size-plus-zero\n"
+ "type: \n"
+ "action:size-plus-three\n"
+ "type:FontP3\n"
+ "action:size-plus-zero\n"
+ "type: \n"
+ "action:size-plus-four\n"
+ "type:FontP4\n"
+ "action:size-plus-zero\n",
+ HTML_PREFIX "<p><font size=\"1\">FontM2</font> <font size=\"2\">FontM1</font> Font0 <font
size=\"4\">FontP1</font> "
+ "<font size=\"5\">FontP2</font> <font size=\"6\">FontP3</font> <font
size=\"7\">FontP4</font></p>" HTML_SUFFIX,
+ "FontM2 FontM1 Font0 FontP1 FontP2 FontP3 FontP4"))
+ g_test_fail ();
+}
+
+static void
+test_font_color_selection (TestFixture *fixture)
+{
+ EContentEditor *cnt_editor;
+ GdkRGBA rgba;
+
+ g_return_if_fail (fixture != NULL);
+ g_return_if_fail (E_IS_HTML_EDITOR (fixture->editor));
+
+ cnt_editor = e_html_editor_get_content_editor (fixture->editor);
+ g_return_if_fail (cnt_editor != NULL);
+
+ if (!test_utils_process_commands (fixture,
+ "mode:html\n"
+ "type:default red green blue\n"
+ "seq:hCrcrCSrsc\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ rgba.red = 1.0;
+ rgba.green = 0.0;
+ rgba.blue = 0.0;
+ rgba.alpha = 1.0;
+
+ e_content_editor_set_font_color (cnt_editor, &rgba);
+
+ if (!test_utils_process_commands (fixture,
+ "seq:rrCSrcs\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ rgba.red = 0.0;
+ rgba.green = 1.0;
+ rgba.blue = 0.0;
+ rgba.alpha = 1.0;
+
+ e_content_editor_set_font_color (cnt_editor, &rgba);
+
+ if (!test_utils_process_commands (fixture,
+ "seq:rrCSrcs\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ rgba.red = 0.0;
+ rgba.green = 0.0;
+ rgba.blue = 1.0;
+ rgba.alpha = 1.0;
+
+ e_content_editor_set_font_color (cnt_editor, &rgba);
+
+ if (!test_utils_run_simple_test (fixture, "",
+ HTML_PREFIX "<p>default <font color=\"#ff0000\">red</font> <font
color=\"#00ff00\">green</font> "
+ "<font color=\"#0000ff\">blue</font></p>" HTML_SUFFIX,
+ "default red green blue"))
+ g_test_fail ();
+}
+
+static void
+test_font_color_typed (TestFixture *fixture)
+{
+ EContentEditor *cnt_editor;
+ GdkRGBA rgba;
+
+ g_return_if_fail (fixture != NULL);
+ g_return_if_fail (E_IS_HTML_EDITOR (fixture->editor));
+
+ cnt_editor = e_html_editor_get_content_editor (fixture->editor);
+ g_return_if_fail (cnt_editor != NULL);
+
+ if (!test_utils_process_commands (fixture,
+ "mode:html\n"
+ "type:default \n")) {
+ g_test_fail ();
+ return;
+ }
+
+ rgba.red = 1.0;
+ rgba.green = 0.0;
+ rgba.blue = 0.0;
+ rgba.alpha = 1.0;
+
+ e_content_editor_set_font_color (cnt_editor, &rgba);
+
+ if (!test_utils_process_commands (fixture,
+ "type:red \n")) {
+ g_test_fail ();
+ return;
+ }
+
+ rgba.red = 0.0;
+ rgba.green = 1.0;
+ rgba.blue = 0.0;
+ rgba.alpha = 1.0;
+
+ e_content_editor_set_font_color (cnt_editor, &rgba);
+
+ if (!test_utils_process_commands (fixture,
+ "type:green \n")) {
+ g_test_fail ();
+ return;
+ }
+
+ rgba.red = 0.0;
+ rgba.green = 0.0;
+ rgba.blue = 1.0;
+ rgba.alpha = 1.0;
+
+ e_content_editor_set_font_color (cnt_editor, &rgba);
+
+ if (!test_utils_process_commands (fixture,
+ "type:blue\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture, "",
+ HTML_PREFIX "<p>default <font color=\"#ff0000\">red </font><font color=\"#00ff00\">green
</font>"
+ "<font color=\"#0000ff\">blue</font></p>" HTML_SUFFIX,
+ "default red green blue"))
+ g_test_fail ();
+}
+
+static void
+test_list_bullet_plain (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:plain\n"
+ "action:style-list-bullet\n"
+ "type:item 1\\n\n"
+ "type:item 2\\n\n"
+ "type:item 3\\n\n"
+ "type:\\n\n"
+ "type:text\n",
+ NULL,
+ " * item 1\n"
+ " * item 2\n"
+ " * item 3\n"
+ "text"))
+ g_test_fail ();
+}
+
+static void
+test_list_bullet_html (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "action:style-list-bullet\n"
+ "type:item 1\\n\n"
+ "action:indent\n"
+ "type:item 2\\n\n"
+ "action:unindent\n"
+ "type:item 3\\n\n"
+ "type:\\n\n"
+ "type:text\n",
+ HTML_PREFIX
+ "<ul>"
+ "<li>item 1</li>"
+ "<ul>"
+ "<li>item 2</li>"
+ "</ul>"
+ "<li>item 3</li>"
+ "</ul>"
+ "<p>text</p>"
+ HTML_SUFFIX,
+ " * item 1\n"
+ " * item 2\n"
+ " * item 3\n"
+ "text"))
+ g_test_fail ();
+}
+
+static void
+test_list_bullet_html_from_block (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:item 1\\n\n"
+ "type:item 2\n"
+ "action:style-list-roman\n"
+ "type:\\n\n"
+ "action:style-preformat\n"
+ "type:item 3\\n\n"
+ "action:select-all\n"
+ "action:style-list-bullet\n",
+ HTML_PREFIX
+ "<ul>"
+ "<li>item 1</li>"
+ "<li>item 2</li>"
+ "<li>item 3</li>"
+ "<li><br></li>"
+ "</ul>"
+ HTML_SUFFIX,
+ " * item 1\n"
+ " * item 2\n"
+ " * item 3\n"
+ " * "))
+ g_test_fail ();
+}
+
+static void
+test_list_alpha_html (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "action:style-list-alpha\n"
+ "type:item 1\\n\n"
+ "action:indent\n"
+ "type:item 2\\n\n"
+ "action:unindent\n"
+ "type:item 3\\n\n"
+ "type:\\n\n"
+ "type:text\n",
+ HTML_PREFIX
+ "<ol type=\"A\">"
+ "<li>item 1</li>"
+ "<ol type=\"A\">"
+ "<li>item 2</li>"
+ "</ol>"
+ "<li>item 3</li>"
+ "</ol>"
+ "<p>text</p>"
+ HTML_SUFFIX,
+ " A. item 1\n"
+ " A. item 2\n"
+ " B. item 3\n"
+ "text"))
+ g_test_fail ();
+}
+
+static void
+test_list_alpha_plain (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:plain\n"
+ "action:style-list-alpha\n"
+ "type:item 1\\n\n"
+ "action:indent\n"
+ "type:item 2\\n\n"
+ "action:unindent\n"
+ "type:item 3\\n\n"
+ "type:\\n\n"
+ "type:text\n",
+ NULL,
+ " A. item 1\n"
+ " A. item 2\n"
+ " B. item 3\n"
+ "text"))
+ g_test_fail ();
+}
+
+static void
+test_list_roman_html (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "action:style-list-roman\n"
+ "type:1\\n\n"
+ "type:2\\n\n"
+ "type:3\\n\n"
+ "type:4\\n\n"
+ "type:5\\n\n"
+ "type:6\\n\n"
+ "type:7\\n\n"
+ "type:8\\n\n"
+ "type:9\\n\n"
+ "type:10\\n\n"
+ "type:11\\n\n"
+ "type:12\\n\n"
+ "type:13\\n\n"
+ "type:14\\n\n"
+ "type:15\\n\n"
+ "type:16\\n\n"
+ "type:17\\n\n"
+ "type:18\n",
+ HTML_PREFIX "<ol type=\"I\">"
+ "<li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li>"
+ "<li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li>"
+ "<li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li>"
+ "</ol>" HTML_SUFFIX,
+ " I. 1\n"
+ " II. 2\n"
+ " III. 3\n"
+ " IV. 4\n"
+ " V. 5\n"
+ " VI. 6\n"
+ " VII. 7\n"
+ "VIII. 8\n"
+ " IX. 9\n"
+ " X. 10\n"
+ " XI. 11\n"
+ " XII. 12\n"
+ "XIII. 13\n"
+ " XIV. 14\n"
+ " XV. 15\n"
+ " XVI. 16\n"
+ "XVII. 17\n"
+ "XVIII. 18"))
+ g_test_fail ();
+}
+
+static void
+test_list_roman_plain (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:plain\n"
+ "action:style-list-roman\n"
+ "type:1\\n\n"
+ "type:2\\n\n"
+ "type:3\\n\n"
+ "type:4\\n\n"
+ "type:5\\n\n"
+ "type:6\\n\n"
+ "type:7\\n\n"
+ "type:8\\n\n"
+ "type:9\\n\n"
+ "type:10\\n\n"
+ "type:11\\n\n"
+ "type:12\\n\n"
+ "type:13\\n\n"
+ "type:14\\n\n"
+ "type:15\\n\n"
+ "type:16\\n\n"
+ "type:17\\n\n"
+ "type:18\n",
+ NULL,
+ " I. 1\n"
+ " II. 2\n"
+ " III. 3\n"
+ " IV. 4\n"
+ " V. 5\n"
+ " VI. 6\n"
+ " VII. 7\n"
+ "VIII. 8\n"
+ " IX. 9\n"
+ " X. 10\n"
+ " XI. 11\n"
+ " XII. 12\n"
+ "XIII. 13\n"
+ " XIV. 14\n"
+ " XV. 15\n"
+ " XVI. 16\n"
+ "XVII. 17\n"
+ "XVIII. 18"))
+ g_test_fail ();
+}
+
+static void
+test_list_multi_html (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "action:style-list-bullet\n"
+ "type:item 1\\n\n"
+ "type:item 2\\n\n"
+ "type:\\n\n"
+ "action:style-list-roman\n"
+ "type:item 3\\n\n"
+ "type:item 4\\n\n",
+ HTML_PREFIX
+ "<ul>"
+ "<li>item 1</li>"
+ "<li>item 2</li>"
+ "</ul>"
+ "<ol type=\"I\">"
+ "<li>item 3</li>"
+ "<li>item 4</li>"
+ "<li><br></li>"
+ "</ol>"
+ HTML_SUFFIX,
+ " * item 1\n"
+ " * item 2\n"
+ " I. item 3\n"
+ " II. item 4\n"
+ " III. "))
+ g_test_fail ();
+}
+
+static void
+test_list_multi_plain (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:plain\n"
+ "action:style-list-bullet\n"
+ "type:item 1\\n\n"
+ "type:item 2\\n\n"
+ "type:\\n\n"
+ "action:style-list-roman\n"
+ "type:item 3\\n\n"
+ "type:item 4\\n\n",
+ NULL,
+ " * item 1\n"
+ " * item 2\n"
+ " I. item 3\n"
+ " II. item 4\n"
+ " III. "))
+ g_test_fail ();
+}
+
+static void
+test_list_multi_change_html (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "action:style-list-bullet\n"
+ "type:item 1\\n\n"
+ "type:item 2\\n\n"
+ "type:\\n\n"
+ "action:style-list-roman\n"
+ "type:item 3\\n\n"
+ "type:item 4\\n\n"
+ "action:select-all\n"
+ "action:style-list-number\n",
+ HTML_PREFIX
+ "<ol>"
+ "<li>item 1</li>"
+ "<li>item 2</li>"
+ "<li>item 3</li>"
+ "<li>item 4</li>"
+ "<li><br></li>"
+ "</ol>"
+ HTML_SUFFIX,
+ " 1. item 1\n"
+ " 2. item 2\n"
+ " 3. item 3\n"
+ " 4. item 4\n"
+ " 5. "))
+ g_test_fail ();
+}
+
+static void
+test_list_multi_change_plain (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:plain\n"
+ "action:style-list-bullet\n"
+ "type:item 1\\n\n"
+ "type:item 2\\n\n"
+ "type:\\n\n"
+ "action:style-list-roman\n"
+ "type:item 3\\n\n"
+ "type:item 4\\n\n"
+ "action:select-all\n"
+ "action:style-list-number\n",
+ NULL,
+ " 1. item 1\n"
+ " 2. item 2\n"
+ " 3. item 3\n"
+ " 4. item 4\n"
+ " 5. "))
+ g_test_fail ();
+}
+
+static void
+test_link_insert_dialog (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:a link example: \n"
+ "action:insert-link\n"
+ "type:http://www.gnome.org\n"
+ "seq:n\n",
+ HTML_PREFIX "<p>a link example: <a
href=\"http://www.gnome.org\">http://www.gnome.org</a></p>" HTML_SUFFIX,
+ "a link example: http://www.gnome.org"))
+ g_test_fail ();
+}
+
+static void
+test_link_insert_dialog_selection (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:a link example: GNOME\n"
+ "seq:CSlsc\n"
+ "action:insert-link\n"
+ "type:http://www.gnome.org\n"
+ "seq:n\n",
+ HTML_PREFIX "<p>a link example: <a href=\"http://www.gnome.org\">GNOME</a></p>" HTML_SUFFIX,
+ "a link example: GNOME"))
+ g_test_fail ();
+}
+
+static void
+test_link_insert_typed (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:www.gnome.org \n",
+ HTML_PREFIX "<p><a href=\"http://www.gnome.org\">www.gnome.org</a> </p>" HTML_SUFFIX,
+ "www.gnome.org "))
+ g_test_fail ();
+}
+
+static void
+test_link_insert_typed_change_description (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:www.gnome.org \n"
+ "seq:ll\n"
+ "action:insert-link\n"
+ "seq:tt\n" /* Jump to the description */
+ "type:GNOME\n"
+ "seq:n\n",
+ HTML_PREFIX "<p><a href=\"http://www.gnome.org\">GNOME</a> </p>" HTML_SUFFIX,
+ "GNOME "))
+ g_test_fail ();
+}
+
+static void
+test_link_insert_dialog_remove_link (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:www.gnome.org \n"
+ "seq:ll\n"
+ "action:insert-link\n"
+ "seq:tttt\n" /* Jump to 'Remove Link' */
+ "seq:n\n", /* Press the button */
+ HTML_PREFIX "<p>www.gnome.org </p>" HTML_SUFFIX,
+ "www.gnome.org "))
+ g_test_fail ();
+}
+
+static void
+test_link_insert_typed_append (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:www.gnome.org \n"
+ "seq:l\n"
+ "type:/about\n",
+ HTML_PREFIX "<p><a href=\"http://www.gnome.org/about\">www.gnome.org/about</a> </p>"
HTML_SUFFIX,
+ "www.gnome.org/about "))
+ g_test_fail ();
+}
+
+static void
+test_link_insert_typed_remove (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:www.gnome.org \n"
+ "seq:bbb\n",
+ HTML_PREFIX "<p><a href=\"http://www.gnome.org\">www.gnome.o</a></p>" HTML_SUFFIX,
+ "www.gnome.o"))
+ g_test_fail ();
+}
+
+static void
+test_h_rule_insert (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:text\n"
+ "action:insert-rule\n"
+ "seq:tttttn\n", /* Move to the Close button and press it */
+ HTML_PREFIX "<p>text</p><hr align=\"left\" size=\"2\" noshade=\"\">" HTML_SUFFIX,
+ "text"))
+ g_test_fail ();
+}
+
+static void
+test_h_rule_insert_text_after (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:above\n"
+ "action:insert-rule\n"
+ "seq:tttttn\n" /* Move to the Close button and press it */
+ "seq:den\n"
+ "type:below\n",
+ HTML_PREFIX "<p>above</p><hr align=\"left\" size=\"2\" noshade=\"\"><p>below</p>" HTML_SUFFIX,
+ "above\nbelow"))
+ g_test_fail ();
+}
+
+static void
+test_emoticon_insert_typed (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:before :)after\n",
+ HTML_PREFIX "<p>before <img src=\"data:image/png;base64,"
+ "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfA"
+ "hkiAAAAAlwSFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlu"
+ "a3NjYXBlLm9yZ5vuPBoAAAAXdEVYdEF1dGhvcgBMYXBvIENhbGFtYW5kcmVp35"
+ "EaKgAAACl0RVh0RGVzY3JpcHRpb24AQmFzZWQgb2YgSmFrdWIgU3RlaW5lciBk"
+ "ZXNpZ26ghAVzAAADRklEQVQ4jWWTXWiVdQCHn//7ec4+zmrbcZ+usT4wy23ilj"
+ "K3cmIRIl10GYGgVCMovOjjMsSrwGEFSXohMchCKBBUWEFqrQ10yTbHNh2bp03n"
+ "vrdztvN+/t/330U3C3/XD8/FDx6hlGLrLnzeXq0L/R1bVwfQxB4AYvW3H4kbkY"
+ "ouHvuyb24rL7YKej7rOJYsKv7m5Vf22eW1VUZheRqUIr+8yNLsYzk00O/nNzc/"
+ "fu9M/4UnBD982nat9oXdnS0HX08I/w7CWgRLAgp8E8JKIrOJvt6rXmZ8+HrXt7"
+ "cPA2gA33/S3lXz3K7O1vb9iWj6PFd+vcaVgQxaugyRLoMSxenvfuTu72d47eCh"
+ "RE3Diwe632/pAtDOn+io061k9562NxLe3XPE0QK3J/LcHllH2UmwCxAFRfw1km"
+ "Po3gze6FlePXQkqZt298mjLXVaKMPjzc177XjmOnHuAQJI2BoJWwcVI5QCFZOw"
+ "DCxLIHMZePgH+/d12FEkjxuRDDrLKrbrwUQvQsTg+xxpT6OltyG83H9PbWZ596"
+ "16GlPrCG+N4NEtKp49qkcy6DQCpTcWPVXB+uI0q2jUFHrsrHLRyx3ihVkEArWx"
+ "wZsvScIFH5mTLMxPUbwjRSC1RiOUwvCyC+ihz9OFNlf716mtlWyvd6moKsQ0BM"
+ "r1eTiT5d5Ejrl5l+ZSRaWlEUTKMFzXGc3cH9pba5RgyU0O7ypnaDnBz79lWd2Y"
+ "oyChIaRCKEFjXQmdO1OkYsnU2C183xs1vIib45P3W9OFBZrlriCyKzSlK9nd2A"
+ "ZFNfjuBpZdjB75+JkB5KNxfLue4fHx2JPcNGSkekamFj+qbtCTOyIF+KhonnC1"
+ "F19LEGOioggt2MCWEt2PeSBN+kcyfiC1Hn1gbHHpcs/X1j8rbmupuW6mlESPFF"
+ "ocEwcBkesifAc7DFFOQMaBS2Oak3Pj0z/dmL6kAVTkq09lA3Py8ly1M7hmMJ8L"
+ "8bMu5qZDgeti5F3WciF3VjUuTpY6yw6TS/rMqf+18EFLi5lPrZxUSp14piiXqE"
+ "n6ojLpA/DYsZh1bDWVLfIU4qtyb9sX5wYHwydqBHi7o6FJI/xQINqjWDwPoGtq"
+ "UqH6Ysyzv/w5PbyV/xd0ZaEGG/mx/wAAAABJRU5ErkJggg==\" alt=\":-)\">"
+ "after</p>" HTML_SUFFIX,
+ "before :-)after"))
+ g_test_fail ();
+}
+
+static void
+test_emoticon_insert_typed_dash (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:before :-)after\n",
+ HTML_PREFIX "<p>before <img src=\"data:image/png;base64,"
+ "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfA"
+ "hkiAAAAAlwSFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlu"
+ "a3NjYXBlLm9yZ5vuPBoAAAAXdEVYdEF1dGhvcgBMYXBvIENhbGFtYW5kcmVp35"
+ "EaKgAAACl0RVh0RGVzY3JpcHRpb24AQmFzZWQgb2YgSmFrdWIgU3RlaW5lciBk"
+ "ZXNpZ26ghAVzAAADRklEQVQ4jWWTXWiVdQCHn//7ec4+zmrbcZ+usT4wy23ilj"
+ "K3cmIRIl10GYGgVCMovOjjMsSrwGEFSXohMchCKBBUWEFqrQ10yTbHNh2bp03n"
+ "vrdztvN+/t/330U3C3/XD8/FDx6hlGLrLnzeXq0L/R1bVwfQxB4AYvW3H4kbkY"
+ "ouHvuyb24rL7YKej7rOJYsKv7m5Vf22eW1VUZheRqUIr+8yNLsYzk00O/nNzc/"
+ "fu9M/4UnBD982nat9oXdnS0HX08I/w7CWgRLAgp8E8JKIrOJvt6rXmZ8+HrXt7"
+ "cPA2gA33/S3lXz3K7O1vb9iWj6PFd+vcaVgQxaugyRLoMSxenvfuTu72d47eCh"
+ "RE3Diwe632/pAtDOn+io061k9562NxLe3XPE0QK3J/LcHllH2UmwCxAFRfw1km"
+ "Po3gze6FlePXQkqZt298mjLXVaKMPjzc177XjmOnHuAQJI2BoJWwcVI5QCFZOw"
+ "DCxLIHMZePgH+/d12FEkjxuRDDrLKrbrwUQvQsTg+xxpT6OltyG83H9PbWZ596"
+ "16GlPrCG+N4NEtKp49qkcy6DQCpTcWPVXB+uI0q2jUFHrsrHLRyx3ihVkEArWx"
+ "wZsvScIFH5mTLMxPUbwjRSC1RiOUwvCyC+ihz9OFNlf716mtlWyvd6moKsQ0BM"
+ "r1eTiT5d5Ejrl5l+ZSRaWlEUTKMFzXGc3cH9pba5RgyU0O7ypnaDnBz79lWd2Y"
+ "oyChIaRCKEFjXQmdO1OkYsnU2C183xs1vIib45P3W9OFBZrlriCyKzSlK9nd2A"
+ "ZFNfjuBpZdjB75+JkB5KNxfLue4fHx2JPcNGSkekamFj+qbtCTOyIF+KhonnC1"
+ "F19LEGOioggt2MCWEt2PeSBN+kcyfiC1Hn1gbHHpcs/X1j8rbmupuW6mlESPFF"
+ "ocEwcBkesifAc7DFFOQMaBS2Oak3Pj0z/dmL6kAVTkq09lA3Py8ly1M7hmMJ8L"
+ "8bMu5qZDgeti5F3WciF3VjUuTpY6yw6TS/rMqf+18EFLi5lPrZxUSp14piiXqE"
+ "n6ojLpA/DYsZh1bDWVLfIU4qtyb9sX5wYHwydqBHi7o6FJI/xQINqjWDwPoGtq"
+ "UqH6Ysyzv/w5PbyV/xd0ZaEGG/mx/wAAAABJRU5ErkJggg==\" alt=\":-)\">"
+ "after</p>" HTML_SUFFIX,
+ "before :-)after"))
+ g_test_fail ();
+}
+
+static void
+test_paragraph_normal_selection (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "action:style-preformat\n"
+ "type:Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.\\n\n"
+ "type:Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.\n"
+ "seq:hu\n"
+ "action:style-normal\n",
+ HTML_PREFIX "<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio.
Praesent libero.</p>"
+ "<pre>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.</pre>" HTML_SUFFIX,
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec\n"
+ "odio. Praesent libero.\n"
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "mode:plain\n",
+ HTML_PREFIX_PLAIN "<p style=\"width: 71ch;\">Lorem ipsum dolor sit amet, consectetur
adipiscing elit. Integer nec odio. Praesent libero.</p>"
+ "<pre>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.</pre>" HTML_SUFFIX,
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec\n"
+ "odio. Praesent libero.\n"
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n",
+ HTML_PREFIX "<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio.
Praesent libero.</p>"
+ "<pre>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.</pre>" HTML_SUFFIX,
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec\n"
+ "odio. Praesent libero.\n"
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.")) {
+ g_test_fail ();
+ return;
+ }
+}
+
+static void
+test_paragraph_normal_typed (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "action:style-normal\n"
+ "type:Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.\\n\n"
+ "type:Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.\n",
+ HTML_PREFIX "<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio.
Praesent libero.</p>"
+ "<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.</p>" HTML_SUFFIX,
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec\n"
+ "odio. Praesent libero.\n"
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec\n"
+ "odio. Praesent libero.")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "mode:plain\n",
+ HTML_PREFIX_PLAIN "<p style=\"width: 71ch;\">Lorem ipsum dolor sit amet, consectetur
adipiscing elit. Integer nec odio. Praesent libero.</p>"
+ "<p style=\"width: 71ch;\">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer
nec odio. Praesent libero.</p>" HTML_SUFFIX,
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec\n"
+ "odio. Praesent libero.\n"
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec\n"
+ "odio. Praesent libero.")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n",
+ HTML_PREFIX "<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio.
Praesent libero.</p>"
+ "<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.</p>" HTML_SUFFIX,
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec\n"
+ "odio. Praesent libero.\n"
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec\n"
+ "odio. Praesent libero.")) {
+ g_test_fail ();
+ return;
+ }
+}
+
+static void
+test_paragraph_preformatted_selection (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "action:style-normal\n"
+ "type:Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.\\n\n"
+ "type:Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.\n"
+ "seq:Chc\n"
+ "action:style-preformat\n",
+ HTML_PREFIX "<pre>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio.
Praesent libero.</pre>"
+ "<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.</p>" HTML_SUFFIX,
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.\n"
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec\n"
+ "odio. Praesent libero.")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "mode:plain\n",
+ HTML_PREFIX_PLAIN "<pre>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec
odio. Praesent libero.</pre>"
+ "<p style=\"width: 71ch;\">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer
nec odio. Praesent libero.</p>" HTML_SUFFIX,
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.\n"
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec\n"
+ "odio. Praesent libero.")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n",
+ HTML_PREFIX "<pre>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio.
Praesent libero.</pre>"
+ "<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.</p>" HTML_SUFFIX,
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.\n"
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec\n"
+ "odio. Praesent libero.")) {
+ g_test_fail ();
+ return;
+ }
+}
+
+static void
+test_paragraph_preformatted_typed (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "action:style-preformat\n"
+ "type:Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero. \n"
+ "type:Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.\n",
+ HTML_PREFIX "<pre>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio.
Praesent libero."
+ " Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.</pre>" HTML_SUFFIX,
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero. "
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "mode:plain\n",
+ HTML_PREFIX_PLAIN "<pre>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec
odio. Praesent libero."
+ " Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.</pre>" HTML_SUFFIX,
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero. "
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n",
+ HTML_PREFIX "<pre>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio.
Praesent libero."
+ " Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.</pre>" HTML_SUFFIX,
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero. "
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.")) {
+ g_test_fail ();
+ return;
+ }
+}
+
+static void
+test_paragraph_address_selection (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "action:style-normal\n"
+ "type:normal text\\n\n"
+ "type:address line 1\\n\n"
+ "type:address line 2\\n\n"
+ "type:address line 3\\n\n"
+ "type:\\n\n"
+ "type:normal text\n"
+ "seq:huuuuSddrs\n"
+ "action:style-address\n",
+ HTML_PREFIX "<p>normal text</p>"
+ "<address>address line 1</address>"
+ "<address>address line 2</address>"
+ "<address>address line 3</address>"
+ "<p><br></p>"
+ "<p>normal text</p>" HTML_SUFFIX,
+ "normal text\n"
+ "address line 1\n"
+ "address line 2\n"
+ "address line 3\n"
+ "\n"
+ "normal text"))
+ g_test_fail ();
+}
+
+static void
+test_paragraph_address_typed (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "action:style-normal\n"
+ "type:normal text\\n\n"
+ "action:style-address\n"
+ "type:address line 1\\n\n"
+ "type:address line 2\\n\n"
+ "type:address line 3\\n\n"
+ "action:style-normal\n"
+ "type:\\n\n"
+ "type:normal text\n",
+ HTML_PREFIX "<p>normal text</p>"
+ "<address>address line 1</address>"
+ "<address>address line 2</address>"
+ "<address>address line 3</address>"
+ "<p><br></p>"
+ "<p>normal text</p>" HTML_SUFFIX,
+ "normal text\n"
+ "address line 1\n"
+ "address line 2\n"
+ "address line 3\n"
+ "normal text"))
+ g_test_fail ();
+}
+
+static gboolean
+test_paragraph_header_n_selection (TestFixture *fixture,
+ gint header_n)
+{
+ gchar *actions, *expected_html, *expected_plain;
+ gboolean success;
+
+ actions = g_strdup_printf (
+ "mode:html\n"
+ "action:style-normal\n"
+ "type:normal text\\n\n"
+ "type:header %d\\n\n"
+ "type:normal text\n"
+ "seq:hu\n"
+ "action:style-h%d\n",
+ header_n, header_n);
+
+ expected_html = g_strdup_printf (
+ HTML_PREFIX "<p>normal text</p>"
+ "<h%d>header %d</h%d>"
+ "<p>normal text</p>" HTML_SUFFIX,
+ header_n, header_n, header_n);
+
+ expected_plain = g_strdup_printf (
+ "normal text\n"
+ "header %d\n"
+ "normal text",
+ header_n);
+
+ success = test_utils_run_simple_test (fixture, actions, expected_html, expected_plain);
+
+ g_free (expected_plain);
+ g_free (expected_html);
+ g_free (actions);
+
+ if (!success)
+ return success;
+
+ expected_html = g_strdup_printf (
+ HTML_PREFIX "<p>normal text</p>"
+ "<h%d>header %d</h%d>"
+ "<p><br></p>"
+ "<p>normal text</p>" HTML_SUFFIX,
+ header_n, header_n, header_n);
+
+ expected_plain = g_strdup_printf (
+ "normal text\n"
+ "header %d\n"
+ "\n"
+ "normal text",
+ header_n);
+
+ success = test_utils_run_simple_test (fixture,
+ "seq:h\n"
+ "type:\\n\n",
+ expected_html, expected_plain);
+
+ g_free (expected_plain);
+ g_free (expected_html);
+
+ return success;
+}
+
+static gboolean
+test_paragraph_header_n_typed (TestFixture *fixture,
+ gint header_n)
+{
+ gchar *actions, *expected_html, *expected_plain;
+ gboolean success;
+
+ actions = g_strdup_printf (
+ "mode:html\n"
+ "action:style-normal\n"
+ "type:normal text\\n\n"
+ "action:style-h%d\n"
+ "type:header %d\\n\n"
+ "action:style-normal\n"
+ "type:normal text\n",
+ header_n, header_n);
+
+ expected_html = g_strdup_printf (
+ HTML_PREFIX "<p>normal text</p>"
+ "<h%d>header %d</h%d>"
+ "<p>normal text</p>" HTML_SUFFIX,
+ header_n, header_n, header_n);
+
+ expected_plain = g_strdup_printf (
+ "normal text\n"
+ "header %d\n"
+ "normal text",
+ header_n);
+
+ success = test_utils_run_simple_test (fixture, actions, expected_html, expected_plain);
+
+ g_free (expected_plain);
+ g_free (expected_html);
+ g_free (actions);
+
+ if (!success)
+ return success;
+
+ expected_html = g_strdup_printf (
+ HTML_PREFIX "<p>normal text</p>"
+ "<h%d>header %d</h%d>"
+ "<p><br></p>"
+ "<p>normal text</p>" HTML_SUFFIX,
+ header_n, header_n, header_n);
+
+ expected_plain = g_strdup_printf (
+ "normal text\n"
+ "header %d\n"
+ "\n"
+ "normal text",
+ header_n);
+
+ success = test_utils_run_simple_test (fixture,
+ "seq:h\n"
+ "type:\\n\n",
+ expected_html, expected_plain);
+
+ g_free (expected_plain);
+ g_free (expected_html);
+
+ return success;
+}
+
+static void
+test_paragraph_header1_selection (TestFixture *fixture)
+{
+ if (!test_paragraph_header_n_selection (fixture, 1))
+ g_test_fail ();
+}
+
+static void
+test_paragraph_header1_typed (TestFixture *fixture)
+{
+ if (!test_paragraph_header_n_typed (fixture, 1))
+ g_test_fail ();
+}
+
+static void
+test_paragraph_header2_selection (TestFixture *fixture)
+{
+ if (!test_paragraph_header_n_selection (fixture, 2))
+ g_test_fail ();
+}
+
+static void
+test_paragraph_header2_typed (TestFixture *fixture)
+{
+ if (!test_paragraph_header_n_typed (fixture, 2))
+ g_test_fail ();
+}
+
+static void
+test_paragraph_header3_selection (TestFixture *fixture)
+{
+ if (!test_paragraph_header_n_selection (fixture, 3))
+ g_test_fail ();
+}
+
+static void
+test_paragraph_header3_typed (TestFixture *fixture)
+{
+ if (!test_paragraph_header_n_typed (fixture, 3))
+ g_test_fail ();
+}
+
+static void
+test_paragraph_header4_selection (TestFixture *fixture)
+{
+ if (!test_paragraph_header_n_selection (fixture, 4))
+ g_test_fail ();
+}
+
+static void
+test_paragraph_header4_typed (TestFixture *fixture)
+{
+ if (!test_paragraph_header_n_typed (fixture, 4))
+ g_test_fail ();
+}
+
+static void
+test_paragraph_header5_selection (TestFixture *fixture)
+{
+ if (!test_paragraph_header_n_selection (fixture, 5))
+ g_test_fail ();
+}
+
+static void
+test_paragraph_header5_typed (TestFixture *fixture)
+{
+ if (!test_paragraph_header_n_typed (fixture, 5))
+ g_test_fail ();
+}
+
+static void
+test_paragraph_header6_selection (TestFixture *fixture)
+{
+ if (!test_paragraph_header_n_selection (fixture, 6))
+ g_test_fail ();
+}
+
+static void
+test_paragraph_header6_typed (TestFixture *fixture)
+{
+ if (!test_paragraph_header_n_typed (fixture, 6))
+ g_test_fail ();
+}
+
+static void
+test_paragraph_wrap_lines (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.\\n\n"
+ "type:Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent
libero.\n"
+ "action:select-all\n"
+ "action:wrap-lines\n",
+ HTML_PREFIX "<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec<br>odio.
Praesent libero.</p>"
+ "<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec<br>odio. Praesent
libero.</p>" HTML_SUFFIX,
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec\n" "odio. Praesent
libero.\n"
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec\n" "odio. Praesent
libero."))
+ g_test_fail ();
+}
+
+static void
+test_paste_singleline_html2html (TestFixture *fixture)
+{
+ test_utils_set_clipboard_text ("<html><body>some <b>bold</b> text</body></html>", TRUE);
+
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:text before \n"
+ "action:paste\n"
+ "type: text after\n",
+ HTML_PREFIX "<p>text before some <b>bold</b> text text after</p>" HTML_SUFFIX,
+ "text before some bold text text after"))
+ g_test_fail ();
+}
+
+static void
+test_paste_singleline_html2plain (TestFixture *fixture)
+{
+ test_utils_set_clipboard_text ("<html><body>some <b>bold</b> text</body></html>", TRUE);
+
+ if (!test_utils_run_simple_test (fixture,
+ "mode:plain\n"
+ "type:text before \n"
+ "action:paste\n"
+ "type: text after\n",
+ HTML_PREFIX_PLAIN "<p style=\"width: 71ch;\">text before some bold text text after</p>"
HTML_SUFFIX,
+ "text before some bold text text after"))
+ g_test_fail ();
+}
+
+static void
+test_paste_singleline_plain2html (TestFixture *fixture)
+{
+ test_utils_set_clipboard_text ("some plain text", FALSE);
+
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:text before \n"
+ "action:paste\n"
+ "type: text after\n",
+ HTML_PREFIX "<p>text before some plain text text after</p>" HTML_SUFFIX,
+ "text before some plain text text after"))
+ g_test_fail ();
+}
+
+static void
+test_paste_singleline_plain2plain (TestFixture *fixture)
+{
+ test_utils_set_clipboard_text ("some plain text", FALSE);
+
+ if (!test_utils_run_simple_test (fixture,
+ "mode:plain\n"
+ "type:text before \n"
+ "action:paste\n"
+ "type: text after\n",
+ HTML_PREFIX_PLAIN "<p style=\"width: 71ch;\">text before some plain text text after</p>"
HTML_SUFFIX,
+ "text before some plain text text after"))
+ g_test_fail ();
+}
+
+static void
+test_paste_multiline_html2html (TestFixture *fixture)
+{
+ test_utils_set_clipboard_text ("<html><body><b>bold</b> text<br><i>italic</i>
text<br><u>underline</u> text<br></body></html>", TRUE);
+
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:text before \n"
+ "action:paste\n"
+ "type:text after\n",
+ HTML_PREFIX "<p>text before <b>bold</b> text</p><p><i>italic</i> text</p><p><u>underline</u>
text</p><p>text after</p>" HTML_SUFFIX,
+ "text before bold text\nitalic text\nunderline text\ntext after"))
+ g_test_fail ();
+}
+
+static void
+test_paste_multiline_html2plain (TestFixture *fixture)
+{
+ test_utils_set_clipboard_text ("<html><body><b>bold</b> text<br><i>italic</i>
text<br><u>underline</u> text</body></html>", TRUE);
+
+ if (!test_utils_run_simple_test (fixture,
+ "mode:plain\n"
+ "type:text before \n"
+ "action:paste\n"
+ "type:\\ntext after\n",
+ HTML_PREFIX_PLAIN "<p style=\"width: 71ch;\">text before bold text</p>"
+ "<p style=\"width: 71ch;\">italic text</p>"
+ "<p style=\"width: 71ch;\">underline text</p>"
+ "<p style=\"width: 71ch;\">text after</p>" HTML_SUFFIX,
+ "text before bold text\nitalic text\nunderline text\ntext after"))
+ g_test_fail ();
+}
+
+static void
+test_paste_multiline_div_html2html (TestFixture *fixture)
+{
+ test_utils_set_clipboard_text ("<html><body><div><b>bold</b> text</div><div><i>italic</i>
text</div><div><u>underline</u> text</div><div></div></body></html>", TRUE);
+
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:text before \n"
+ "action:paste\n"
+ "type:text after\n",
+ HTML_PREFIX "<p>text before <b>bold</b> text</p><p><i>italic</i> text</p><p><u>underline</u>
text</p><p>text after</p>" HTML_SUFFIX,
+ "text before bold text\nitalic text\nunderline text\ntext after"))
+ g_test_fail ();
+}
+
+static void
+test_paste_multiline_div_html2plain (TestFixture *fixture)
+{
+ test_utils_set_clipboard_text ("<html><body><div><b>bold</b> text</div><div><i>italic</i>
text</div><div><u>underline</u> text</div></body></html>", TRUE);
+
+ if (!test_utils_run_simple_test (fixture,
+ "mode:plain\n"
+ "type:text before \n"
+ "action:paste\n"
+ "type:\\ntext after\n",
+ HTML_PREFIX_PLAIN "<p style=\"width: 71ch;\">text before bold text</p>"
+ "<p style=\"width: 71ch;\">italic text</p>"
+ "<p style=\"width: 71ch;\">underline text</p>"
+ "<p style=\"width: 71ch;\">text after</p>" HTML_SUFFIX,
+ "text before bold text\nitalic text\nunderline text\ntext after"))
+ g_test_fail ();
+}
+
+static void
+test_paste_multiline_p_html2html (TestFixture *fixture)
+{
+ test_utils_set_clipboard_text ("<html><body><p><b>bold</b> text</p><p><i>italic</i>
text</p><p><u>underline</u> text</p><p></p></body></html>", TRUE);
+
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:text before \n"
+ "action:paste\n"
+ "type:text after\n",
+ HTML_PREFIX "<p>text before <b>bold</b> text</p><p><i>italic</i> text</p><p><u>underline</u>
text</p><p>text after</p>" HTML_SUFFIX,
+ "text before bold text\nitalic text\nunderline text\ntext after"))
+ g_test_fail ();
+}
+
+static void
+test_paste_multiline_p_html2plain (TestFixture *fixture)
+{
+ test_utils_set_clipboard_text ("<html><body><p><b>bold</b> text</p><p><i>italic</i>
text</p><p><u>underline</u> text</p></body></html>", TRUE);
+
+ if (!test_utils_run_simple_test (fixture,
+ "mode:plain\n"
+ "type:text before \n"
+ "action:paste\n"
+ "type:\\ntext after\n",
+ HTML_PREFIX_PLAIN "<p style=\"width: 71ch;\">text before bold text</p>"
+ "<p style=\"width: 71ch;\">italic text</p>"
+ "<p style=\"width: 71ch;\">underline text</p>"
+ "<p style=\"width: 71ch;\">text after</p>" HTML_SUFFIX,
+ "text before bold text\nitalic text\nunderline text\ntext after"))
+ g_test_fail ();
+}
+
+static void
+test_paste_multiline_plain2html (TestFixture *fixture)
+{
+ test_utils_set_clipboard_text ("line 1\nline 2\nline 3\n", FALSE);
+
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:text before \n"
+ "action:paste\n"
+ "type:text after\n",
+ HTML_PREFIX "<p>text before line 1</p><p>line 2</p><p>line 3</p><p>text after</p>"
HTML_SUFFIX,
+ "text before line 1\nline 2\nline 3\ntext after"))
+ g_test_fail ();
+}
+
+static void
+test_paste_multiline_plain2plain (TestFixture *fixture)
+{
+ test_utils_set_clipboard_text ("line 1\nline 2\nline 3", FALSE);
+
+ if (!test_utils_run_simple_test (fixture,
+ "mode:plain\n"
+ "type:text before \n"
+ "action:paste\n"
+ "type:\\ntext after\n",
+ HTML_PREFIX_PLAIN "<p style=\"width: 71ch;\">text before line 1</p>"
+ "<p style=\"width: 71ch;\">line 2</p>"
+ "<p style=\"width: 71ch;\">line 3</p>"
+ "<p style=\"width: 71ch;\">text after</p>" HTML_SUFFIX,
+ "text before line 1\nline 2\nline 3\ntext after"))
+ g_test_fail ();
+}
+
+static void
+test_paste_quoted_singleline_html2html (TestFixture *fixture)
+{
+ test_utils_set_clipboard_text ("<html><body>some <b>bold</b> text</body></html>", TRUE);
+
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:text before \n"
+ "action:paste-quote\n"
+ "type:\\n\n" /* stop quotting */
+ "type:text after\n",
+ HTML_PREFIX "<p>text before </p>"
+ "<blockquote type=\"cite\"><p>some <b>bold</b> text</p></blockquote>"
+ "<p>text after</p>" HTML_SUFFIX,
+ "text before \n"
+ "> some bold text\n"
+ "text after"))
+ g_test_fail ();
+}
+
+static void
+test_paste_quoted_singleline_html2plain (TestFixture *fixture)
+{
+ test_utils_set_clipboard_text ("<html><body>some <b>bold</b> text</body></html>", TRUE);
+
+ if (!test_utils_run_simple_test (fixture,
+ "mode:plain\n"
+ "type:text before \n"
+ "action:paste-quote\n"
+ "type:\\n\n" /* stop quotting */
+ "type:text after\n",
+ HTML_PREFIX_PLAIN "<p style=\"width: 71ch;\">text before </p>"
+ "<blockquote type=\"cite\"><p style=\"width: 71ch;\">> some <b>bold</b>
text</p></blockquote>"
+ "<p style=\"width: 71ch;\">text after</p>" HTML_SUFFIX,
+ "text before \n"
+ "> some bold text\n"
+ "text after"))
+ g_test_fail ();
+}
+
+static void
+test_paste_quoted_singleline_plain2html (TestFixture *fixture)
+{
+ test_utils_set_clipboard_text ("some plain text", FALSE);
+
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:text before \n"
+ "action:paste-quote\n"
+ "type:\\n\n" /* stop quotting */
+ "type:text after\n",
+ HTML_PREFIX "<p>text before </p>"
+ "<blockquote type=\"cite\"><p>some plain text</p></blockquote>"
+ "<p>text after</p>" HTML_SUFFIX,
+ "text before \n"
+ "> some plain text\n"
+ "text after"))
+ g_test_fail ();
+}
+
+static void
+test_paste_quoted_singleline_plain2plain (TestFixture *fixture)
+{
+ test_utils_set_clipboard_text ("some plain text", FALSE);
+
+ if (!test_utils_run_simple_test (fixture,
+ "mode:plain\n"
+ "type:text before \n"
+ "action:paste-quote\n"
+ "type:\\n\n" /* stop quotting */
+ "type:text after\n",
+ HTML_PREFIX_PLAIN "<p style=\"width: 71ch;\">text before </p>"
+ "<blockquote type=\"cite\"><p style=\"width: 71ch;\">> some plain text</p></blockquote>"
+ "<p style=\"width: 71ch;\">text after</p>" HTML_SUFFIX,
+ "text before \n"
+ "> some plain text\n"
+ "text after"))
+ g_test_fail ();
+}
+
+static void
+test_paste_quoted_multiline_html2html (TestFixture *fixture)
+{
+ test_utils_set_clipboard_text ("<html><body><b>bold</b> text<br><i>italic</i>
text<br><u>underline</u> text<br></body></html>", TRUE);
+
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:text before \n"
+ "action:paste-quote\n"
+ "seq:b\n" /* stop quotting */
+ "type:text after\n",
+ HTML_PREFIX "<p>text before </p>"
+ "<blockquote type=\"cite\">> <b>bold</b> text</p>"
+ "<p>> <i>italic</i> text</p>"
+ "<p>> <u>underline</u> text</p></blockquote>"
+ "<p>text after</p>" HTML_SUFFIX,
+ "text before \n"
+ "> bold text\n"
+ "> italic text\n"
+ "> underline text\n"
+ "text after"))
+ g_test_fail ();
+}
+
+static void
+test_paste_quoted_multiline_html2plain (TestFixture *fixture)
+{
+ test_utils_set_clipboard_text ("<html><body><b>bold</b> text<br><i>italic</i>
text<br><u>underline</u> text</body></html>", TRUE);
+
+ if (!test_utils_run_simple_test (fixture,
+ "mode:plain\n"
+ "type:text before \n"
+ "action:paste-quote\n"
+ "type:\\n\n" /* stop quotting */
+ "type:text after\n",
+ HTML_PREFIX_PLAIN "<p style=\"width: 71ch;\">text before </p>"
+ "<blockquote type=\"cite\"><p>> bold text</p>"
+ "<p style=\"width: 71ch;\">> italic text</p>"
+ "<p style=\"width: 71ch;\">> underline text</p></blockquote>"
+ "<p style=\"width: 71ch;\">> text after</p>" HTML_SUFFIX,
+ "text before \n"
+ "> bold text\n"
+ "> italic text\n"
+ "> underline text\n"
+ "text after"))
+ g_test_fail ();
+}
+
+static void
+test_paste_quoted_multiline_plain2html (TestFixture *fixture)
+{
+ test_utils_set_clipboard_text ("line 1\nline 2\nline 3\n", FALSE);
+
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:text before \n"
+ "action:paste-quote\n"
+ "seq:b\n" /* stop quotting */
+ "type:text after\n",
+ HTML_PREFIX "<p>text before </p>"
+ "<blockquote type=\"cite\"><p>line 1</p>"
+ "<p>line 2</p>"
+ "<p>line 3</p></blockquote>"
+ "<p>text after</p>" HTML_SUFFIX,
+ "text before \n"
+ "> line 1\n"
+ "> line 2\n"
+ "> line 3\n"
+ "text after"))
+ g_test_fail ();
+}
+
+static void
+test_paste_quoted_multiline_plain2plain (TestFixture *fixture)
+{
+ test_utils_set_clipboard_text ("line 1\nline 2\nline 3", FALSE);
+
+ if (!test_utils_run_simple_test (fixture,
+ "mode:plain\n"
+ "type:text before \n"
+ "action:paste-quote\n"
+ "type:\\n\n" /* stop quotting */
+ "type:text after\n",
+ HTML_PREFIX_PLAIN "<p style=\"width: 71ch;\">text before </p>"
+ "<blockquote type=\"cite\"><p style=\"width: 71ch;\">> line 1</p>"
+ "<p style=\"width: 71ch;\">> line 2</p>"
+ "<p style=\"width: 71ch;\">> line 3</p></blockquote>"
+ "<p style=\"width: 71ch;\">text after</p>" HTML_SUFFIX,
+ "text before\n"
+ "> line 1\n"
+ "> line 2\n"
+ "> line 3\n"
+ "text after"))
+ g_test_fail ();
+}
+
+static void
+test_cite_html2plain (TestFixture *fixture)
+{
+ if (!test_utils_process_commands (fixture,
+ "mode:html\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ test_utils_insert_content (fixture,
+ "<html><head></head><body>"
+ "<blockquote type=\"cite\">"
+ "<p>level 1</p>"
+ "<p><br></p>"
+ "<p>level 1</p>"
+ "<blockquote type=\"cite\">"
+ "<p>level 2</p>"
+ "</blockquote>"
+ "<p>back in level 1</p>"
+ "</blockquote>"
+ "<p><br></p>"
+ "<p>out of the citation</p>"
+ "</body></html>",
+ E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML);
+
+ /* Just check the content was read properly */
+ if (!test_utils_run_simple_test (fixture,
+ "",
+ HTML_PREFIX "<blockquote type=\"cite\"><p>level 1</p><p><br></p><p>level 1</p>"
+ "<blockquote type=\"cite\"><p>level 2</p></blockquote><p>back in level 1</p></blockquote>"
+ "<p><br></p><p>out of the citation</p>" HTML_SUFFIX,
+ "> level 1\n"
+ ">\n"
+ "> level 1\n"
+ "> > level 2\n"
+ "> back in level 1\n"
+ "\n"
+ "out of the citation")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "mode:plain\n",
+ HTML_PREFIX_PLAIN ,
+ "> level 1\n"
+ ">\n"
+ "> level 1\n"
+ "> > level 2\n"
+ "> back in level 1\n"
+ "\n"
+ "out of the citation")) {
+ g_test_fail ();
+ }
+}
+
+static void
+test_cite_shortline (TestFixture *fixture)
+{
+ if (!test_utils_process_commands (fixture,
+ "mode:html\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ test_utils_insert_content (fixture,
+ "<html><head></head><body><blockquote type=\"cite\">"
+ "<p>Just one short line.</p>"
+ "</blockquote></body></html>",
+ E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML);
+
+ if (!test_utils_run_simple_test (fixture,
+ "",
+ HTML_PREFIX "<blockquote type=\"cite\">"
+ "<p>Just one short line.</p>"
+ "</blockquote>" HTML_SUFFIX,
+ "> Just one short line.")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_process_commands (fixture,
+ "seq:C\n"
+ "type:a\n"
+ "seq:cD\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ test_utils_insert_content (fixture,
+ "<html><head></head><body><blockquote type=\"cite\">"
+ "<p>Just one short line.</p>"
+ "</blockquote></body></html>",
+ E_CONTENT_EDITOR_INSERT_TEXT_HTML);
+
+ if (!test_utils_run_simple_test (fixture,
+ "",
+ HTML_PREFIX "<blockquote type=\"cite\">"
+ "<p>Just one short line.</p>"
+ "</blockquote>" HTML_SUFFIX,
+ "> Just one short line.")) {
+ g_test_fail ();
+ return;
+ }
+
+ test_utils_insert_content (fixture,
+ "<html><head></head><body><blockquote type=\"cite\">"
+ "<p>short line 1</p>"
+ "<p>short line 2</p>"
+ "<p>short line 3</p>"
+ "</blockquote></body></html>",
+ E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML);
+
+ if (!test_utils_run_simple_test (fixture,
+ "",
+ HTML_PREFIX "<blockquote type=\"cite\">"
+ "<p>short line 1</p>"
+ "<p>short line 2</p>"
+ "<p>short line 3</p>"
+ "</blockquote>" HTML_SUFFIX,
+ "> short line 1\n"
+ "> short line 2\n"
+ "> short line 3")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_process_commands (fixture,
+ "seq:C\n"
+ "type:a\n"
+ "seq:cD\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ test_utils_insert_content (fixture,
+ "<html><head></head><body><blockquote type=\"cite\">"
+ "<p>short line 1</p>"
+ "<p>short line 2</p>"
+ "<p>short line 3</p>"
+ "</blockquote></body></html>",
+ E_CONTENT_EDITOR_INSERT_TEXT_HTML);
+
+ if (!test_utils_run_simple_test (fixture,
+ "",
+ HTML_PREFIX "<blockquote type=\"cite\">"
+ "<p>short line 1</p>"
+ "<p>short line 2</p>"
+ "<p>short line 3</p>"
+ "</blockquote>" HTML_SUFFIX,
+ "> short line 1\n"
+ "> short line 2\n"
+ "> short line 3")) {
+ g_test_fail ();
+ return;
+ }
+}
+
+static void
+test_cite_longline (TestFixture *fixture)
+{
+ if (!test_utils_process_commands (fixture,
+ "mode:html\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ test_utils_insert_content (fixture,
+ "<html><head></head><body><blockquote type=\"cite\">"
+ "<p>This is the first paragraph of a quoted text which has some long text to test. It has the
second sentence as well.</p>"
+ "</blockquote></body></html>",
+ E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML);
+
+ if (!test_utils_run_simple_test (fixture,
+ "",
+ HTML_PREFIX "<blockquote type=\"cite\">"
+ "<p>This is the first paragraph of a quoted text which has some long text to test. It has the
second sentence as well.</p>"
+ "</blockquote>" HTML_SUFFIX,
+ "> This is the first paragraph of a quoted text which has some long\n"
+ "> text to test. It has the second sentence as well.\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_process_commands (fixture,
+ "seq:C\n"
+ "type:a\n"
+ "seq:cD\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ test_utils_insert_content (fixture,
+ "<html><head></head><body><blockquote type=\"cite\">"
+ "<p>This is the first paragraph of a quoted text which has some long text to test. It has the
second sentence as well.</p>"
+ "</blockquote></body></html>",
+ E_CONTENT_EDITOR_INSERT_TEXT_HTML);
+
+ if (!test_utils_run_simple_test (fixture,
+ "",
+ HTML_PREFIX "<blockquote type=\"cite\">"
+ "<p>This is the first paragraph of a quoted text which has some long text to test. It has the
second sentence as well.</p>"
+ "</blockquote>" HTML_SUFFIX,
+ "> This is the first paragraph of a quoted text which has some long\n"
+ "> text to test. It has the second sentence as well.\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ test_utils_insert_content (fixture,
+ "<html><head></head><body><blockquote type=\"cite\">"
+ "<p>This is the first paragraph of a quoted text which has some long text to test. It has the
second sentence as well.</p>"
+ "<p>This is the second paragraph of a quoted text which has some long text to test. It has
the second sentence as well.</p>"
+ "<p>This is the third paragraph of a quoted text which has some long text to test. It has the
second sentence as well.</p>"
+ "</blockquote><br>after quote</body></html>",
+ E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML);
+
+ if (!test_utils_run_simple_test (fixture,
+ "",
+ HTML_PREFIX "<blockquote type=\"cite\">"
+ "<p>This is the first paragraph of a quoted text which has some long text to test. It has the
second sentence as well.</p>"
+ "<p>This is the second paragraph of a quoted text which has some long text to test. It has
the second sentence as well.</p>"
+ "<p>This is the third paragraph of a quoted text which has some long text to test. It has the
second sentence as well.</p>"
+ "</blockquote><br>after quote" HTML_SUFFIX,
+ "> This is the first paragraph of a quoted text which has some long\n"
+ "> text to test. It has the second sentence as well.\n"
+ "> This is the econd paragraph of a quoted text which has some long\n"
+ "> text to test. It has the second sentence as well.\n"
+ "> This is the third paragraph of a quoted text which has some long\n"
+ "> text to test. It has the second sentence as well.\n"
+ "\nafter quote")) {
+ g_test_fail ();
+ return;
+ }
+}
+
+static void
+test_cite_reply_html (TestFixture *fixture)
+{
+ if (!test_utils_process_commands (fixture,
+ "mode:html\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ test_utils_insert_content (fixture,
+ "<pre>line 1\n"
+ "line 2\n"
+ "</pre><span class=\"-x-evo-to-body\" data-credits=\"On Today, User wrote:\"></span>"
+ "<span class=\"-x-evo-cite-body\"></span>",
+ E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML);
+
+ if (!test_utils_run_simple_test (fixture,
+ "",
+ HTML_PREFIX "<p>On Today, User wrote:</p>"
+ "<blockquote type=\"cite\"><pre>line 1\n"
+ "line 2\n"
+ "</pre></blockquote>" HTML_SUFFIX,
+ "On Today, Use wrote:\n"
+ "> line 1\n"
+ "> line 2\n"))
+ g_test_fail ();
+
+}
+
+static void
+test_cite_reply_plain (TestFixture *fixture)
+{
+ if (!test_utils_process_commands (fixture,
+ "mode:plain\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ test_utils_insert_content (fixture,
+ "<pre>line 1\n"
+ "line 2\n"
+ "</pre><span class=\"-x-evo-to-body\" data-credits=\"On Today, User wrote:\"></span>"
+ "<span class=\"-x-evo-cite-body\"></span>",
+ E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML);
+
+ if (!test_utils_run_simple_test (fixture,
+ "",
+ HTML_PREFIX_PLAIN "<p style=\"width: 71ch;\">On Today, User wrote:</p>"
+ "<blockquote type=\"cite\"><p style=\"width: 71ch;\">> line 1</p>"
+ "<p style=\"width: 71ch;\">> line 2</p>"
+ "<p style=\"width: 71ch;\">> <br></p></blockquote>" HTML_SUFFIX,
+ "On Today, Use wrote:\n"
+ "> line 1\n"
+ "> line 2\n"
+ "> "))
+ g_test_fail ();
+}
+
+static void
+test_undo_text_typed (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:some te\n"
+ "undo:save\n" /* 1 */
+ "type:tz\n"
+ "undo:save\n" /* 2 */
+ "undo:undo\n"
+ "undo:undo\n"
+ "undo:test:2\n"
+ "undo:redo\n"
+ "undo:redo\n"
+ "undo:test\n"
+ "undo:undo:2\n"
+ "undo:drop\n"
+ "type:xt\n",
+ HTML_PREFIX "<p>some text</p>" HTML_SUFFIX,
+ "some text"))
+ g_test_fail ();
+}
+
+static void
+test_undo_text_forward_delete (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:some text to delete\n"
+ "seq:hCrcrCDc\n"
+ "undo:undo\n"
+ "undo:redo\n"
+ "undo:undo\n",
+ HTML_PREFIX "<p>some text to delete</p>" HTML_SUFFIX,
+ "some text to delete"))
+ g_test_fail ();
+}
+
+static void
+test_undo_text_backward_delete (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:some text to delete\n"
+ "seq:hCrcrCbc\n"
+ "undo:undo\n"
+ "undo:redo\n"
+ "undo:undo\n",
+ HTML_PREFIX "<p>some text to delete</p>" HTML_SUFFIX,
+ "some text to delete"))
+ g_test_fail ();
+}
+
+static void
+test_undo_text_cut (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:plain\n"
+ "type:some text to delete\n"
+ "seq:CSllsc\n"
+ "action:cut\n"
+ "undo:undo\n",
+ NULL,
+ "some text to delete"))
+ g_test_fail ();
+}
+
+static void
+test_undo_style (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:The first paragraph text\\n\n"
+ "undo:save\n" /* 1 */
+
+ "action:bold\n"
+ "type:bold\n"
+ "undo:save\n" /* 2 */
+ "undo:undo:4\n"
+ "undo:test:2\n"
+ "undo:redo:4\n"
+ "undo:test\n"
+ "undo:drop\n" /* drop the save 2 */
+ "undo:undo:4\n"
+ "type:bold\n"
+ "seq:CSlsc\n"
+ "action:bold\n"
+ "undo:save:\n" /* 2 */
+ "undo:undo:4\n"
+ "undo:test:2\n"
+ "undo:redo:4\n"
+ "undo:test\n"
+ "undo:drop\n" /* drop the save 2 */
+ "undo:undo:4\n"
+
+ "action:italic\n"
+ "type:italic\n"
+ "undo:save\n" /* 2 */
+ "undo:undo:6\n"
+ "undo:test:2\n"
+ "undo:redo:6\n"
+ "undo:test\n"
+ "undo:drop\n" /* drop the save 2 */
+ "undo:undo:6\n"
+ "type:italic\n"
+ "seq:CSlsc\n"
+ "action:italic\n"
+ "undo:save:\n" /* 2 */
+ "undo:undo:6\n"
+ "undo:test:2\n"
+ "undo:redo:6\n"
+ "undo:test\n"
+ "undo:drop\n" /* drop the save 2 */
+ "undo:undo:6\n"
+
+ "action:underline\n"
+ "type:underline\n"
+ "undo:save\n" /* 2 */
+ "undo:undo:9\n"
+ "undo:test:2\n"
+ "undo:redo:9\n"
+ "undo:test\n"
+ "undo:drop\n" /* drop the save 2 */
+ "undo:undo:9\n"
+ "type:italic\n"
+ "seq:CSlsc\n"
+ "action:underline\n"
+ "undo:save:\n" /* 2 */
+ "undo:undo:9\n"
+ "undo:test:2\n"
+ "undo:redo:9\n"
+ "undo:test\n"
+ "undo:drop\n" /* drop the save 2 */
+ "undo:undo:9\n"
+
+ "action:strikethrough\n"
+ "type:strikethrough\n"
+ "undo:save\n" /* 2 */
+ "undo:undo:13\n"
+ "undo:test:2\n"
+ "undo:redo:13\n"
+ "undo:test\n"
+ "undo:drop\n" /* drop the save 2 */
+ "undo:undo:13\n"
+ "type:strikethrough\n"
+ "seq:CSlsc\n"
+ "action:strikethrough\n"
+ "undo:save:\n" /* 2 */
+ "undo:undo:13\n"
+ "undo:test:2\n"
+ "undo:redo:13\n"
+ "undo:test\n"
+ "undo:drop\n" /* drop the save 2 */
+ "undo:undo:13\n"
+
+ "action:monospaced\n"
+ "type:monospaced\n"
+ "undo:save\n" /* 2 */
+ "undo:undo:10\n"
+ "undo:test:2\n"
+ "undo:redo:10\n"
+ "undo:test\n"
+ "undo:drop\n" /* drop the save 2 */
+ "undo:undo:10\n"
+ "type:monospaced\n"
+ "seq:CSlsc\n"
+ "action:monospaced\n"
+ "undo:save:\n" /* 2 */
+ "undo:undo:10\n"
+ "undo:test:2\n"
+ "undo:redo:10\n"
+ "undo:test\n"
+ "undo:drop\n" /* drop the save 2 */
+ "undo:undo:10\n",
+ HTML_PREFIX "<p>The first paragraph</p><p><br></p>" HTML_SUFFIX,
+ "The first paragraph\n"))
+ g_test_fail ();
+}
+
+static void
+test_undo_justify (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:The first paragraph text\\n\n"
+ "undo:save\n" /* 1 */
+
+ "action:justify-left\n"
+ "type:left\n"
+ "undo:save\n" /* 2 */
+ "undo:undo:4\n"
+ "undo:test:2\n"
+ "undo:redo:4\n"
+ "undo:test\n"
+ "undo:drop\n" /* drop the save 2 */
+ "undo:undo:4\n"
+ "type:left\n"
+ "seq:CSlsc\n"
+ "action:justify-left\n"
+ "undo:save:\n" /* 2 */
+ "undo:undo:4\n"
+ "undo:test:2\n"
+ "undo:redo:4\n"
+ "undo:test\n"
+ "undo:drop\n" /* drop the save 2 */
+ "undo:undo:4\n"
+
+ "action:justify-center\n"
+ "type:center\n"
+ "undo:save\n" /* 2 */
+ "undo:undo:6\n"
+ "undo:test:2\n"
+ "undo:redo:6\n"
+ "undo:test\n"
+ "undo:drop\n" /* drop the save 2 */
+ "undo:undo:6\n"
+ "type:center\n"
+ "seq:CSlsc\n"
+ "action:justify-center\n"
+ "undo:save:\n" /* 2 */
+ "undo:undo:6\n"
+ "undo:test:2\n"
+ "undo:redo:6\n"
+ "undo:test\n"
+ "undo:drop\n" /* drop the save 2 */
+ "undo:undo:6\n"
+
+ "action:justify-right\n"
+ "type:right\n"
+ "undo:save\n" /* 2 */
+ "undo:undo:5\n"
+ "undo:test:2\n"
+ "undo:redo:5\n"
+ "undo:test\n"
+ "undo:drop\n" /* drop the save 2 */
+ "undo:undo:5\n"
+ "type:right\n"
+ "seq:CSlsc\n"
+ "action:justify-right\n"
+ "undo:save:\n" /* 2 */
+ "undo:undo:5\n"
+ "undo:test:2\n"
+ "undo:redo:5\n"
+ "undo:test\n"
+ "undo:drop\n" /* drop the save 2 */
+ "undo:undo:5\n",
+
+ HTML_PREFIX "<p>The first paragraph</p><p><br></p>" HTML_SUFFIX,
+ "The first paragraph\n"))
+ g_test_fail ();
+}
+
+static void
+test_undo_indent (TestFixture *fixture)
+{
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:The first paragraph text\\n\n"
+ "undo:save\n" /* 1 */
+
+ "action:indent\n"
+ "type:text\n"
+ "undo:save\n" /* 2 */
+ "undo:undo:5\n"
+ "undo:test:2\n"
+ "undo:redo:5\n"
+ "undo:test\n"
+ "undo:drop\n" /* drop the save 2 */
+ "undo:undo:5\n"
+ "type:text\n"
+ "seq:CSlsc\n"
+ "action:indent\n"
+ "undo:save:\n" /* 2 */
+ "undo:undo:5\n"
+ "undo:test:2\n"
+ "undo:redo:5\n"
+ "undo:test\n"
+ "undo:drop\n" /* drop the save 2 */
+ "undo:undo:5\n"
+
+ "type:text\n"
+ "undo:save\n" /* 2 */
+ "action:indent\n"
+ "undo:save\n" /* 3 */
+ "action:unindent\n"
+ "undo:test:2\n"
+ "action:indent\n"
+ "undo:test\n"
+ "undo:save\n" /* 4 */
+ "undo:undo:2\n"
+ "undo:test:2\n"
+ "undo:redo:2\n"
+ "undo:test\n"
+ "undo:drop:2\n" /* drop the save 4 and 3 */
+ "undo:undo:3\n"
+ "undo:test\n"
+ "undo:drop\n" /* drop the save 2 */
+ "undo:undo:4\n"
+ "undo:test\n"
+
+ "type:level 1\\n\n"
+ "type:level 2\\n\n"
+ "type:level 3\\n\n"
+ "seq:uuu\n"
+ "action:indent\n"
+ "undo:save\n" /* 2 */
+ "seq:d\n"
+ "action:indent\n"
+ "action:indent\n"
+ "undo:save\n" /* 3 */
+ "undo:undo:2\n"
+ "undo:test:2\n"
+ "undo:redo:2\n"
+ "undo:test\n"
+ "undo:drop:2\n" /* drop the save 3 and 2 */
+ "seq:d\n"
+
+ "action:indent\n"
+ "undo:save\n" /* 2 */
+ "action:indent\n"
+ "action:indent\n"
+ "undo:save\n" /* 3 */
+ "undo:undo:2\n"
+ "undo:test:2\n"
+ "undo:redo:2\n"
+ "undo:test\n"
+ "undo:drop:2\n" /* drop the save 3 and 2 */
+
+ "undo:save\n" /* 2 */
+ "undo:undo:30\n" /* 6x action:indent, 24x type "level X\\n" */
+ "undo:test:2\n"
+ "undo:redo:30\n"
+ "undo:test\n"
+ "undo:drop\n" /* drop the save 2 */
+ "undo:undo:30\n",
+
+ HTML_PREFIX "<p>The first paragraph</p><p><br></p>" HTML_SUFFIX,
+ "The first paragraph\n"))
+ g_test_fail ();
+}
+
+static void
+test_undo_link_paste_html (TestFixture *fixture)
+{
+ test_utils_set_clipboard_text ("http://www.gnome.org", FALSE);
+
+ if (!test_utils_run_simple_test (fixture,
+ "mode:html\n"
+ "type:URL:\\n\n"
+ "undo:save\n" /* 1 */
+ "action:paste\n"
+ "type:\\n\n"
+ "undo:save\n" /* 2 */
+ "undo:undo:2\n"
+ "undo:test:2\n"
+ "undo:undo:5\n"
+ "undo:redo:7\n"
+ "undo:test\n",
+ HTML_PREFIX "<p>URL:</p><p><a
href=\"http://www.gnome.org\">http://www.gnome.org</a></p><p><br></p>" HTML_SUFFIX,
+ "URL:\nhttp://www.gnome.org\n"))
+ g_test_fail ();
+}
+
+static void
+test_undo_link_paste_plain (TestFixture *fixture)
+{
+ test_utils_set_clipboard_text ("http://www.gnome.org", FALSE);
+
+ if (!test_utils_run_simple_test (fixture,
+ "mode:plain\n"
+ "type:URL:\\n\n"
+ "undo:save\n" /* 1 */
+ "action:paste\n"
+ "type:\\n\n"
+ "undo:save\n" /* 2 */
+ "undo:undo:2\n"
+ "undo:test:2\n"
+ "undo:undo:5\n"
+ "undo:redo:7\n"
+ "undo:test\n",
+ HTML_PREFIX_PLAIN "<p style=\"width: 71ch;\">URL:</p>"
+ "<p style=\"width: 71ch;\"><a href=\"http://www.gnome.org\">http://www.gnome.org</a></p>"
+ "<p style=\"width: 71ch;\"><br></p>" HTML_SUFFIX,
+ "URL:\nhttp://www.gnome.org\n"))
+ g_test_fail ();
+}
+
+static void
+test_bug_726548 (TestFixture *fixture)
+{
+ gboolean success;
+ gchar *text;
+ const gchar *expected_plain =
+ "aaa\n"
+ " 1. a\n"
+ " 2. b\n"
+ " 3. c\n";
+
+ if (!test_utils_run_simple_test (fixture,
+ "mode:plain\n"
+ "type:aaa\\n\n"
+ "action:style-list-number\n"
+ "type:a\\nb\\nc\\n\\n\n"
+ "seq:C\n"
+ "type:ac\n"
+ "seq:c\n",
+ HTML_PREFIX_PLAIN "<p style=\"width: 71ch;\">aaa</p>"
+ "<ol data-evo-paragraph=\"\" style=\"width: 65ch;\">"
+ "<li>a</li><li>b</li><li>c</li></ol>"
+ "<p style=\"width: 71ch;\"><br></p>" HTML_SUFFIX,
+ expected_plain)) {
+ g_test_fail ();
+ return;
+ }
+
+ text = test_utils_get_clipboard_text (FALSE);
+ success = test_utils_html_equal (fixture, text, expected_plain);
+
+ if (!success) {
+ g_warning ("%s: clipboard Plain text \n---%s---\n does not match expected Plain\n---%s---",
+ G_STRFUNC, text, expected_plain);
+ g_free (text);
+ g_test_fail ();
+ } else {
+ g_free (text);
+ }
+}
+
+static void
+test_bug_750657 (TestFixture *fixture)
+{
+ if (!test_utils_process_commands (fixture,
+ "mode:html\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ test_utils_insert_content (fixture,
+ "<html><head></head><body>\n"
+ "<blockquote type=\"cite\">\n"
+ "<p>This is the first paragraph of a quoted text which has some long text to test. It has the
second sentence as well.</p>\n"
+ "<p><br></p>\n"
+ "<p>This is the third paragraph of a quoted text which has some long text to test. It has the
second sentence as well.</p>\n"
+ "<blockquote type=\"cite\">\n"
+ "<p>This is the first paragraph of a sub-quoted text which has some long text to test. It has
the second sentence as well.</p>\n"
+ "<br>\n"
+ "</blockquote>\n"
+ "<p>This is the fourth paragraph of a quoted text which has some long text to test. It has
the second sentence as well.</p>\n"
+ "</blockquote>\n"
+ "<p><br></p>\n"
+ "</body></html>\n",
+ E_CONTENT_EDITOR_INSERT_TEXT_HTML);
+
+ if (!test_utils_run_simple_test (fixture,
+ "seq:uuuSuusD\n",
+ HTML_PREFIX "\n"
+ "<blockquote type=\"cite\">\n"
+ "<p>This is the first paragraph of a quoted text which has some long text to test. It has the
second sentence as well.</p>\n"
+ "<p><br></p>\n"
+ "<p>This is the third paragraph of a quoted text which has some long text to test. It has the
second sentence as well.</p>\n"
+ "<p>This is the fourth paragraph of a quoted text which has some long text to test. It has
the second sentence as well.</p>\n"
+ "</blockquote>\n"
+ "<p><br></p>\n"
+ HTML_SUFFIX,
+ NULL)) {
+ g_test_fail ();
+ return;
+ }
+}
+
+static void
+test_bug_760989 (TestFixture *fixture)
+{
+ if (!test_utils_process_commands (fixture,
+ "mode:html\n"
+ "type:a\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ test_utils_insert_content (fixture,
+ "<html><head></head><body>\n"
+ "One line before quotation<br>\n"
+ "<blockquote type=\"cite\">\n"
+ "<p>Single line quoted.</p>\n"
+ "</blockquote>\n"
+ "</body></html>",
+ E_CONTENT_EDITOR_INSERT_TEXT_HTML);
+
+ if (!test_utils_run_simple_test (fixture,
+ "seq:ChcD\n",
+ HTML_PREFIX "<p>One line before quotation</p>\n"
+ "<blockquote type=\"cite\">\n"
+ "<p>Single line quoted.</p>\n"
+ "</blockquote>" HTML_SUFFIX,
+ "One line before quotation\n"
+ "> Single line quoted.")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "seq:Cecb\n",
+ HTML_PREFIX "<p>One line before quotation</p>\n"
+ "<blockquote type=\"cite\">\n"
+ "<p>Single line quoted</p>\n"
+ "</blockquote>" HTML_SUFFIX,
+ "One line before quotation\n"
+ "> Single line quoted")) {
+ g_test_fail ();
+ return;
+ }
+}
+
+static void
+test_bug_769708 (TestFixture *fixture)
+{
+ if (!test_utils_process_commands (fixture,
+ "mode:html\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ test_utils_insert_content (fixture,
+ "<html><head><style id=\"-x-evo-quote-style\" type=\"text/css\">.-x-evo-quoted {
-webkit-user-select: none; }</style>"
+ "<style id=\"-x-evo-style-a\" type=\"text/css\">a { cursor: text; }</style></head>"
+ "<body data-evo-plain-text=\"\" spellcheck=\"true\">"
+ "<p data-evo-paragraph=\"\" class=\"\" id=\"-x-evo-input-start\">aaa</p>"
+ "<div class=\"-x-evo-signature-wrapper\"><span class=\"-x-evo-signature\"
id=\"autogenerated\"><pre>-- <br></pre>"
+ "<p data-evo-paragraph=\"\" class=\"\">user <user@no.where></p>"
+ "</span></div></body></html>",
+ E_CONTENT_EDITOR_INSERT_REPLACE_ALL | E_CONTENT_EDITOR_INSERT_TEXT_HTML);
+
+ if (!test_utils_process_commands (fixture,
+ "mode:plain\n")) {
+ g_test_fail ();
+ return;
+ }
+
+ if (!test_utils_run_simple_test (fixture,
+ "",
+ HTML_PREFIX_PLAIN "<p style=\"width: 71ch;\">aaa</p><div><span><p style=\"width:
71ch;\">-- </p>"
+ "<p style=\"width: 71ch;\"<br></p><p style=\"width: 71ch;\">user
<user@no.where></p></span></div>" HTML_SUFFIX,
+ "aaa\n"
+ "-- \n"
+ "user <user@no.where>"))
+ g_test_fail ();
+}
+
+gint
+main (gint argc,
+ gchar *argv[])
+{
+ gint cmd_delay = -1;
+ GOptionEntry entries[] = {
+ { "cmd-delay", '\0', 0,
+ G_OPTION_ARG_INT, &cmd_delay,
+ "Specify delay, in milliseconds, to use during processing commands. Default is 5 ms.",
+ NULL },
+ { NULL }
+ };
+ GOptionContext *context;
+ GError *error = NULL;
+ GList *modules;
+ gint res;
+
+ setlocale (LC_ALL, "");
+
+ /* Force the memory GSettings backend, to not overwrite user settings
+ when playing with them. It also ensures that the test will run with
+ default settings, until changed. */
+ g_setenv ("GSETTINGS_BACKEND", "memory", TRUE);
+
+ g_test_init (&argc, &argv, NULL);
+ g_test_bug_base ("http://bugzilla.gnome.org/show_bug.cgi?id=");
+
+ gtk_init (&argc, &argv);
+
+ context = g_option_context_new (NULL);
+ g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
+ if (!g_option_context_parse (context, &argc, &argv, &error)) {
+ g_warning ("Failed to parse arguments: %s\n", error ? error->message : "Unknown error");
+ g_option_context_free (context);
+ g_clear_error (&error);
+ return -1;
+ }
+
+ g_option_context_free (context);
+
+ if (cmd_delay > 0)
+ test_utils_set_event_processing_delay_ms ((guint) cmd_delay);
+
+ e_util_init_main_thread (NULL);
+ e_passwords_init ();
+
+ modules = e_module_load_all_in_directory (EVOLUTION_MODULEDIR);
+ g_list_free_full (modules, (GDestroyNotify) g_type_module_unuse);
+
+ #define add_test(_name, _func) \
+ g_test_add (_name, TestFixture, NULL, \
+ test_utils_fixture_set_up, (ETestFixtureFunc) _func, test_utils_fixture_tear_down)
+
+ add_test ("/create/editor", test_create_editor);
+ add_test ("/style/bold/selection", test_style_bold_selection);
+ add_test ("/style/bold/typed", test_style_bold_typed);
+ add_test ("/style/italic/selection", test_style_italic_selection);
+ add_test ("/style/italic/typed", test_style_italic_typed);
+ add_test ("/style/underline/selection", test_style_underline_selection);
+ add_test ("/style/underline/typed", test_style_underline_typed);
+ add_test ("/style/strikethrough/selection", test_style_strikethrough_selection);
+ add_test ("/style/strikethrough/typed", test_style_strikethrough_typed);
+ add_test ("/style/monospace/selection", test_style_monospace_selection);
+ add_test ("/style/monospace/typed", test_style_monospace_typed);
+ add_test ("/justify/selection", test_justify_selection);
+ add_test ("/justify/typed", test_justify_typed);
+ add_test ("/indent/selection", test_indent_selection);
+ add_test ("/indent/typed", test_indent_typed);
+ add_test ("/font/size/selection", test_font_size_selection);
+ add_test ("/font/size/typed", test_font_size_typed);
+ add_test ("/font/color/selection", test_font_color_selection);
+ add_test ("/font/color/typed", test_font_color_typed);
+ add_test ("/list/bullet/plain", test_list_bullet_plain);
+ add_test ("/list/bullet/html", test_list_bullet_html);
+ add_test ("/list/bullet/html/from-block", test_list_bullet_html_from_block);
+ add_test ("/list/alpha/html", test_list_alpha_html);
+ add_test ("/list/alpha/plain", test_list_alpha_plain);
+ add_test ("/list/roman/html", test_list_roman_html);
+ add_test ("/list/roman/plain", test_list_roman_plain);
+ add_test ("/list/multi/html", test_list_multi_html);
+ add_test ("/list/multi/plain", test_list_multi_plain);
+ add_test ("/list/multi/change/html", test_list_multi_change_html);
+ add_test ("/list/multi/change/plain", test_list_multi_change_plain);
+ add_test ("/link/insert/dialog", test_link_insert_dialog);
+ add_test ("/link/insert/dialog/selection", test_link_insert_dialog_selection);
+ add_test ("/link/insert/dialog/remove-link", test_link_insert_dialog_remove_link);
+ add_test ("/link/insert/typed", test_link_insert_typed);
+ add_test ("/link/insert/typed/change-description", test_link_insert_typed_change_description);
+ add_test ("/link/insert/typed/append", test_link_insert_typed_append);
+ add_test ("/link/insert/typed/remove", test_link_insert_typed_remove);
+ add_test ("/h-rule/insert", test_h_rule_insert);
+ add_test ("/h-rule/insert-text-after", test_h_rule_insert_text_after);
+ add_test ("/emoticon/insert/typed", test_emoticon_insert_typed);
+ add_test ("/emoticon/insert/typed-dash", test_emoticon_insert_typed_dash);
+ add_test ("/paragraph/normal/selection", test_paragraph_normal_selection);
+ add_test ("/paragraph/normal/typed", test_paragraph_normal_typed);
+ add_test ("/paragraph/preformatted/selection", test_paragraph_preformatted_selection);
+ add_test ("/paragraph/preformatted/typed", test_paragraph_preformatted_typed);
+ add_test ("/paragraph/address/selection", test_paragraph_address_selection);
+ add_test ("/paragraph/address/typed", test_paragraph_address_typed);
+ add_test ("/paragraph/header1/selection", test_paragraph_header1_selection);
+ add_test ("/paragraph/header1/typed", test_paragraph_header1_typed);
+ add_test ("/paragraph/header2/selection", test_paragraph_header2_selection);
+ add_test ("/paragraph/header2/typed", test_paragraph_header2_typed);
+ add_test ("/paragraph/header3/selection", test_paragraph_header3_selection);
+ add_test ("/paragraph/header3/typed", test_paragraph_header3_typed);
+ add_test ("/paragraph/header4/selection", test_paragraph_header4_selection);
+ add_test ("/paragraph/header4/typed", test_paragraph_header4_typed);
+ add_test ("/paragraph/header5/selection", test_paragraph_header5_selection);
+ add_test ("/paragraph/header5/typed", test_paragraph_header5_typed);
+ add_test ("/paragraph/header6/selection", test_paragraph_header6_selection);
+ add_test ("/paragraph/header6/typed", test_paragraph_header6_typed);
+ add_test ("/paragraph/wrap-lines", test_paragraph_wrap_lines);
+ add_test ("/paste/singleline/html2html", test_paste_singleline_html2html);
+ add_test ("/paste/singleline/html2plain", test_paste_singleline_html2plain);
+ add_test ("/paste/singleline/plain2html", test_paste_singleline_plain2html);
+ add_test ("/paste/singleline/plain2plain", test_paste_singleline_plain2plain);
+ add_test ("/paste/multiline/html2html", test_paste_multiline_html2html);
+ add_test ("/paste/multiline/html2plain", test_paste_multiline_html2plain);
+ add_test ("/paste/multiline/div/html2html", test_paste_multiline_div_html2html);
+ add_test ("/paste/multiline/div/html2plain", test_paste_multiline_div_html2plain);
+ add_test ("/paste/multiline/p/html2html", test_paste_multiline_p_html2html);
+ add_test ("/paste/multiline/p/html2plain", test_paste_multiline_p_html2plain);
+ add_test ("/paste/multiline/plain2html", test_paste_multiline_plain2html);
+ add_test ("/paste/multiline/plain2plain", test_paste_multiline_plain2plain);
+ add_test ("/paste/quoted/singleline/html2html", test_paste_quoted_singleline_html2html);
+ add_test ("/paste/quoted/singleline/html2plain", test_paste_quoted_singleline_html2plain);
+ add_test ("/paste/quoted/singleline/plain2html", test_paste_quoted_singleline_plain2html);
+ add_test ("/paste/quoted/singleline/plain2plain", test_paste_quoted_singleline_plain2plain);
+ add_test ("/paste/quoted/multiline/html2html", test_paste_quoted_multiline_html2html);
+ add_test ("/paste/quoted/multiline/html2plain", test_paste_quoted_multiline_html2plain);
+ add_test ("/paste/quoted/multiline/plain2html", test_paste_quoted_multiline_plain2html);
+ add_test ("/paste/quoted/multiline/plain2plain", test_paste_quoted_multiline_plain2plain);
+ add_test ("/cite/html2plain", test_cite_html2plain);
+ add_test ("/cite/shortline", test_cite_shortline);
+ add_test ("/cite/longline", test_cite_longline);
+ add_test ("/cite/reply/html", test_cite_reply_html);
+ add_test ("/cite/reply/plain", test_cite_reply_plain);
+ add_test ("/undo/text/typed", test_undo_text_typed);
+ add_test ("/undo/text/forward-delete", test_undo_text_forward_delete);
+ add_test ("/undo/text/backward-delete", test_undo_text_backward_delete);
+ add_test ("/undo/text/cut", test_undo_text_cut);
+ add_test ("/undo/style", test_undo_style);
+ add_test ("/undo/justify", test_undo_justify);
+ add_test ("/undo/indent", test_undo_indent);
+ add_test ("/undo/link-paste/html", test_undo_link_paste_html);
+ add_test ("/undo/link-paste/plain", test_undo_link_paste_plain);
+ add_test ("/bug/726548", test_bug_726548);
+ add_test ("/bug/750657", test_bug_750657);
+ add_test ("/bug/760989", test_bug_760989);
+ add_test ("/bug/769708", test_bug_769708);
+
+ #undef add_test
+
+ res = g_test_run ();
+
+ e_util_cleanup_settings ();
+ e_spell_checker_free_global_memory ();
+
+ return res;
+}
diff --git a/e-util/test-html-editor.c b/e-util/test-html-editor.c
index e393f87..86502c4 100644
--- a/e-util/test-html-editor.c
+++ b/e-util/test-html-editor.c
@@ -27,15 +27,25 @@
#include <glib/gi18n-lib.h>
+/* Enable it, once printing is implemented (it doesn't work to do it
+ on a WebKit side, because the EContentEditor can be a different
+ structure. That might be why EMsgComposer uses a "print" signal,
+ which prints a constructed message, like within the message preview. */
+/* #define ENABLE_PRINT */
+
static const gchar *file_ui =
"<ui>\n"
" <menubar name='main-menu'>\n"
" <menu action='file-menu'>\n"
+" <menuitem action='new-editor'/>\n"
+" <separator/>\n"
" <menuitem action='save'/>\n"
" <menuitem action='save-as'/>\n"
+#ifdef ENABLE_PRINT
" <separator/>\n"
" <menuitem action='print-preview'/>\n"
" <menuitem action='print'/>\n"
+#endif /* ENABLE_PRINT */
" <separator/>\n"
" <menuitem action='disable-editor'/>\n"
" <separator/>\n"
@@ -51,11 +61,14 @@ static const gchar *view_ui =
" <menuitem action='view-html-output'/>\n"
" <menuitem action='view-html-source'/>\n"
" <menuitem action='view-plain-source'/>\n"
-" <menuitem action='view-inspector'/>\n"
+" <separator/>\n"
+" <menuitem action='view-webkit-inspector'/>\n"
" </menu>\n"
" </menubar>\n"
"</ui>";
+static void create_new_editor (void);
+
static void
handle_error (GError **error)
{
@@ -65,7 +78,8 @@ handle_error (GError **error)
}
}
-static GtkPrintOperationResult
+#ifdef ENABLE_PRINT
+static void
print (EHTMLEditor *editor,
GtkPrintOperationAction action)
{
@@ -78,13 +92,12 @@ print (EHTMLEditor *editor,
frame = webkit_web_view_get_main_frame (
WEBKIT_WEB_VIEW (e_html_editor_get_view (editor)));
- result = webkit_web_frame_print_full (frame, operation, action, NULL);
+ webkit_web_frame_print_full (frame, operation, action, NULL);
g_object_unref (operation);
handle_error (&error);
-
- return result;
}
+#endif
static gint
save_dialog (EHTMLEditor *editor)
@@ -139,8 +152,11 @@ view_source_dialog (EHTMLEditor *editor,
GtkWidget *content;
GtkWidget *content_area;
GtkWidget *scrolled_window;
+ EContentEditor *cnt_editor;
gchar * html;
+ cnt_editor = e_html_editor_get_content_editor (editor);
+
dialog = gtk_dialog_new_with_buttons (
title,
GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (editor))),
@@ -165,15 +181,17 @@ view_source_dialog (EHTMLEditor *editor,
gtk_window_set_default_size (GTK_WINDOW (dialog), 400, 300);
if (plain_text) {
- html = e_html_editor_view_get_text_plain (
- e_html_editor_get_view (editor));
+ html = e_content_editor_get_content (cnt_editor,
+ E_CONTENT_EDITOR_GET_PROCESSED | E_CONTENT_EDITOR_GET_TEXT_PLAIN,
+ NULL, NULL);
} else {
- GList *inline_images;
+ GSList *inline_images = NULL;
- html = e_html_editor_view_get_text_html (
- e_html_editor_get_view (editor), "test-domain", &inline_images);
+ html = e_content_editor_get_content (cnt_editor,
+ E_CONTENT_EDITOR_GET_PROCESSED | E_CONTENT_EDITOR_GET_TEXT_HTML |
E_CONTENT_EDITOR_GET_INLINE_IMAGES,
+ "test-domain", &inline_images);
- g_list_free_full (inline_images, g_object_unref);
+ g_slist_free_full (inline_images, g_object_unref);
}
if (show_source || plain_text) {
@@ -185,8 +203,7 @@ view_source_dialog (EHTMLEditor *editor,
gtk_text_view_set_editable (GTK_TEXT_VIEW (content), FALSE);
} else {
content = webkit_web_view_new ();
- webkit_web_view_load_string (
- WEBKIT_WEB_VIEW (content), html, NULL, NULL, NULL);
+ webkit_web_view_load_html (WEBKIT_WEB_VIEW (content), html, "evo-file://");
}
g_free (html);
@@ -198,6 +215,14 @@ view_source_dialog (EHTMLEditor *editor,
}
static void
+action_new_editor_cb (GtkAction *action,
+ EHTMLEditor *editor)
+{
+ create_new_editor ();
+}
+
+#ifdef ENABLE_PRINT
+static void
action_print_cb (GtkAction *action,
EHTMLEditor *editor)
{
@@ -210,6 +235,7 @@ action_print_preview_cb (GtkAction *action,
{
print (editor, GTK_PRINT_OPERATION_ACTION_PREVIEW);
}
+#endif /* ENABLE_PRINT */
static void
action_quit_cb (GtkAction *action,
@@ -231,7 +257,7 @@ action_save_cb (GtkAction *action,
return;
filename = e_html_editor_get_filename (editor);
- as_html = (e_html_editor_view_get_html_mode (e_html_editor_get_view (editor)));
+ as_html = (e_content_editor_get_html_mode (e_html_editor_get_content_editor (editor)));
e_html_editor_save (editor, filename, as_html, &error);
handle_error (&error);
@@ -249,7 +275,7 @@ action_save_as_cb (GtkAction *action,
return;
filename = e_html_editor_get_filename (editor);
- as_html = (e_html_editor_view_get_html_mode (e_html_editor_get_view (editor)));
+ as_html = (e_content_editor_get_html_mode (e_html_editor_get_content_editor (editor)));
e_html_editor_save (editor, filename, as_html, &error);
handle_error (&error);
@@ -259,12 +285,10 @@ static void
action_toggle_editor (GtkAction *action,
EHTMLEditor *editor)
{
- EHTMLEditorView *view;
+ EContentEditor *cnt_editor;
- view = e_html_editor_get_view (editor);
- webkit_web_view_set_editable (
- WEBKIT_WEB_VIEW (view),
- ! webkit_web_view_get_editable (WEBKIT_WEB_VIEW (view)));
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ e_content_editor_set_editable (cnt_editor, !e_content_editor_is_editable (cnt_editor));
}
static void
@@ -293,16 +317,26 @@ action_view_inspector (GtkAction *action,
EHTMLEditor *editor)
{
WebKitWebInspector *inspector;
- EHTMLEditorView *view;
+ EContentEditor *cnt_editor;
- view = e_html_editor_get_view (editor);
- inspector = webkit_web_view_get_inspector (WEBKIT_WEB_VIEW (view));
-
- webkit_web_inspector_show (inspector);
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ if (WEBKIT_IS_WEB_VIEW (cnt_editor)) {
+ inspector = webkit_web_view_get_inspector (WEBKIT_WEB_VIEW (cnt_editor));
+ webkit_web_inspector_show (inspector);
+ } else {
+ g_print ("Cannot show the inspector, the content editor is not a WebKitWebView descendant\n");
+ }
}
static GtkActionEntry file_entries[] = {
+ { "new-editor",
+ "document-new",
+ N_("_New editor"),
+ "<Control>N",
+ NULL,
+ G_CALLBACK (action_new_editor_cb) },
+#ifdef ENABLE_PRINT
{ "print",
"document-print",
N_("_Print..."),
@@ -316,6 +350,7 @@ static GtkActionEntry file_entries[] = {
"<Control><Shift>p",
NULL,
G_CALLBACK (action_print_preview_cb) },
+#endif /* ENABLE_PRINT */
{ "quit",
"application-exit",
@@ -376,11 +411,11 @@ static GtkActionEntry view_entries[] = {
NULL,
G_CALLBACK (action_view_plain_source) },
- { "view-inspector",
+ { "view-webkit-inspector",
NULL,
N_("Inspector"),
NULL,
- NULL,
+ "<Control><Shift>I",
G_CALLBACK (action_view_inspector) },
{ "view-menu",
@@ -391,53 +426,64 @@ static GtkActionEntry view_entries[] = {
NULL }
};
-static WebKitWebView *
-open_inspector (WebKitWebInspector *inspector,
- WebKitWebView *webview,
- gpointer user_data)
-{
- GtkWidget *window;
- GtkWidget *inspector_view;
-
- window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
- inspector_view = webkit_web_view_new ();
+static guint glob_editors = 0;
- gtk_container_add (GTK_CONTAINER (window), GTK_WIDGET (inspector_view));
+static void
+editor_destroyed_cb (GtkWidget *editor)
+{
+ g_return_if_fail (glob_editors > 0);
- gtk_widget_set_size_request (window, 600, 480);
- gtk_widget_show (window);
+ glob_editors--;
- return WEBKIT_WEB_VIEW (inspector_view);
+ if (!glob_editors)
+ gtk_main_quit ();
}
-gint
-main (gint argc,
- gchar **argv)
+static void
+create_new_editor_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
{
GtkActionGroup *action_group;
GtkUIManager *manager;
GtkWidget *container;
GtkWidget *widget;
EHTMLEditor *editor;
- EHTMLEditorView *view;
- WebKitWebInspector *inspector;
-
+ EContentEditor *cnt_editor;
GError *error = NULL;
- bindtextdomain (GETTEXT_PACKAGE, EVOLUTION_LOCALEDIR);
- bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
- textdomain (GETTEXT_PACKAGE);
+ widget = e_html_editor_new_finish (result, &error);
+ if (error) {
+ g_warning ("%s: Failed to create HTML editor: %s", G_STRFUNC, error->message);
+ g_clear_error (&error);
+ editor_destroyed_cb (NULL);
+ return;
+ }
- gtk_init (&argc, &argv);
+ editor = E_HTML_EDITOR (widget);
+ cnt_editor = e_html_editor_get_content_editor (editor);
+
+ g_object_set (G_OBJECT (editor),
+ "halign", GTK_ALIGN_FILL,
+ "hexpand", TRUE,
+ "valign", GTK_ALIGN_FILL,
+ "vexpand", TRUE,
+ NULL);
- editor = g_object_ref_sink (e_html_editor_new ());
- view = e_html_editor_get_view (editor);
+ g_object_set (G_OBJECT (cnt_editor),
+ "halign", GTK_ALIGN_FILL,
+ "hexpand", TRUE,
+ "valign", GTK_ALIGN_FILL,
+ "vexpand", TRUE,
+ NULL);
+
+ if (WEBKIT_IS_WEB_VIEW (cnt_editor)) {
+ WebKitSettings *web_settings;
- inspector = webkit_web_view_get_inspector (
- WEBKIT_WEB_VIEW (view));
- g_signal_connect (
- inspector, "inspect-web-view",
- G_CALLBACK (open_inspector), NULL);
+ web_settings = webkit_web_view_get_settings (WEBKIT_WEB_VIEW (cnt_editor));
+ webkit_settings_set_allow_file_access_from_file_urls (web_settings, TRUE);
+ webkit_settings_set_enable_developer_extras (web_settings, TRUE);
+ }
widget = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_widget_set_size_request (widget, 600, 400);
@@ -445,7 +491,7 @@ main (gint argc,
g_signal_connect_swapped (
widget, "destroy",
- G_CALLBACK (gtk_main_quit), NULL);
+ G_CALLBACK (editor_destroyed_cb), NULL);
container = widget;
@@ -467,6 +513,8 @@ main (gint argc,
gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
gtk_widget_show (widget);
+ gtk_widget_grab_focus (GTK_WIDGET (cnt_editor));
+
manager = e_html_editor_get_ui_manager (editor);
gtk_ui_manager_add_ui_from_string (manager, file_ui, -1, &error);
@@ -491,16 +539,48 @@ main (gint argc,
G_N_ELEMENTS (view_entries), editor);
gtk_ui_manager_insert_action_group (manager, action_group, 0);
+ if (!WEBKIT_IS_WEB_VIEW (cnt_editor)) {
+ GtkAction *action;
+
+ action = e_html_editor_get_action (editor, "view-webkit-inspector");
+ gtk_action_set_visible (action, FALSE);
+ }
+
gtk_ui_manager_ensure_update (manager);
+}
+
+static void
+create_new_editor (void)
+{
+ glob_editors++;
+
+ e_html_editor_new (create_new_editor_cb, NULL);
+}
+
+gint
+main (gint argc,
+ gchar **argv)
+{
+ GList *modules;
+
+ bindtextdomain (GETTEXT_PACKAGE, EVOLUTION_LOCALEDIR);
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+ textdomain (GETTEXT_PACKAGE);
+
+ gtk_init (&argc, &argv);
+
+ e_util_init_main_thread (NULL);
+ e_passwords_init ();
+
+ modules = e_module_load_all_in_directory (EVOLUTION_MODULEDIR);
+ g_list_free_full (modules, (GDestroyNotify) g_type_module_unuse);
- g_signal_connect (
- editor, "destroy",
- G_CALLBACK (gtk_main_quit), NULL);
+ create_new_editor ();
gtk_main ();
- g_object_unref (editor);
e_util_cleanup_settings ();
+ e_spell_checker_free_global_memory ();
return 0;
}
diff --git a/em-format/Makefile.am b/em-format/Makefile.am
index 7827d79..3f2c438 100644
--- a/em-format/Makefile.am
+++ b/em-format/Makefile.am
@@ -34,11 +34,11 @@ evolution_mail_formatter_include_HEADERS = \
e-mail-parser.h \
e-mail-part.h \
e-mail-part-attachment.h \
- e-mail-part-attachment-bar.h \
e-mail-part-audio.h \
e-mail-part-headers.h \
e-mail-part-image.h \
e-mail-part-list.h \
+ e-mail-part-secure-button.h \
e-mail-part-utils.h \
e-mail-stripsig-filter.h
@@ -69,7 +69,6 @@ libevolution_mail_formatter_la_SOURCES = \
e-mail-formatter-quote.c \
e-mail-formatter-utils.c \
e-mail-formatter-attachment.c \
- e-mail-formatter-attachment-bar.c \
e-mail-formatter-audio.c \
e-mail-formatter-enumtypes.c \
e-mail-formatter-error.c \
@@ -83,7 +82,6 @@ libevolution_mail_formatter_la_SOURCES = \
e-mail-formatter-text-html.c \
e-mail-formatter-text-plain.c \
e-mail-formatter-print-headers.c \
- e-mail-formatter-quote-attachment.c \
e-mail-formatter-quote-headers.c \
e-mail-formatter-quote-message-rfc822.c \
e-mail-formatter-quote-text-enriched.c \
@@ -92,7 +90,6 @@ libevolution_mail_formatter_la_SOURCES = \
e-mail-parser-extension.c \
e-mail-parser.c \
e-mail-parser-application-mbox.c \
- e-mail-parser-attachment-bar.c \
e-mail-parser-audio.c \
e-mail-parser-headers.c \
e-mail-parser-image.c \
@@ -116,11 +113,11 @@ libevolution_mail_formatter_la_SOURCES = \
e-mail-parser-text-plain.c \
e-mail-part.c \
e-mail-part-attachment.c \
- e-mail-part-attachment-bar.c \
e-mail-part-audio.c \
e-mail-part-headers.c \
e-mail-part-image.c \
e-mail-part-list.c \
+ e-mail-part-secure-button.c \
e-mail-part-utils.c \
e-mail-stripsig-filter.c \
$(SMIME_EXTENSIONS)
diff --git a/em-format/e-mail-formatter-attachment.c b/em-format/e-mail-formatter-attachment.c
index 2a2f2c9..86a39ef 100644
--- a/em-format/e-mail-formatter-attachment.c
+++ b/em-format/e-mail-formatter-attachment.c
@@ -26,7 +26,6 @@
#include "e-mail-formatter-extension.h"
#include "e-mail-inline-filter.h"
-#include "e-mail-part-attachment-bar.h"
#include "e-mail-part-attachment.h"
#include "e-mail-part-utils.h"
@@ -44,70 +43,10 @@ G_DEFINE_TYPE (
static const gchar *formatter_mime_types[] = {
E_MAIL_PART_ATTACHMENT_MIME_TYPE,
- "application/vnd.evolution.widget.attachment-button",
+ "application/vnd.evolution.attachment-button",
NULL
};
-static EAttachmentStore *
-find_attachment_store (EMailPartList *part_list,
- EMailPart *start)
-{
- EAttachmentStore *store = NULL;
- GQueue queue = G_QUEUE_INIT;
- GList *head, *link;
- const gchar *start_id;
- gchar *tmp, *pos;
- EMailPart *part;
- gchar *id;
-
- start_id = e_mail_part_get_id (start);
-
- e_mail_part_list_queue_parts (part_list, NULL, &queue);
-
- head = g_queue_peek_head_link (&queue);
-
- id = g_strconcat (start_id, ".attachment-bar", NULL);
- tmp = g_strdup (id);
- part = NULL;
- do {
- d (printf ("Looking up attachment bar as %s\n", id));
-
- for (link = head; link != NULL; link = g_list_next (link)) {
- EMailPart *p = link->data;
- const gchar *p_id;
-
- p_id = e_mail_part_get_id (p);
-
- if (g_strcmp0 (p_id, id) == 0) {
- part = p;
- break;
- }
- }
-
- pos = g_strrstr (tmp, ".");
- if (!pos)
- break;
-
- g_free (id);
- g_free (tmp);
- tmp = g_strndup (start_id, pos - tmp);
- id = g_strdup_printf ("%s.attachment-bar", tmp);
-
- } while (pos && !part);
-
- g_free (id);
- g_free (tmp);
-
- if (part != NULL)
- store = e_mail_part_attachment_bar_get_store (
- E_MAIL_PART_ATTACHMENT_BAR (part));
-
- while (!g_queue_is_empty (&queue))
- g_object_unref (g_queue_pop_head (&queue));
-
- return store;
-}
-
static gboolean
emfe_attachment_format (EMailFormatterExtension *extension,
EMailFormatter *formatter,
@@ -118,13 +57,16 @@ emfe_attachment_format (EMailFormatterExtension *extension,
{
gchar *text, *html;
gchar *button_id;
- EAttachmentStore *store;
EMailExtensionRegistry *registry;
GQueue *extensions;
EMailPartAttachment *empa;
CamelMimePart *mime_part;
CamelMimeFilterToHTMLFlags flags;
+ GOutputStream *content_stream = NULL;
GString *buffer;
+ gint icon_width, icon_height;
+ gchar *icon_uri;
+ gpointer attachment_ptr = NULL;
const gchar *attachment_part_id;
const gchar *part_id;
@@ -139,8 +81,8 @@ emfe_attachment_format (EMailFormatterExtension *extension,
EAttachment *attachment;
GList *head, *link;
- attachment = e_mail_part_attachment_ref_attachment (
- E_MAIL_PART_ATTACHMENT (part));
+ attachment = e_mail_part_attachment_ref_attachment (E_MAIL_PART_ATTACHMENT (part));
+ attachment_ptr = attachment;
head = g_queue_peek_head_link (&part->validities);
@@ -161,17 +103,9 @@ emfe_attachment_format (EMailFormatterExtension *extension,
pair->validity->encrypt.status);
}
- store = find_attachment_store (context->part_list, part);
- if (store) {
- GList *attachments = e_attachment_store_get_attachments (store);
- if (!g_list_find (attachments, attachment)) {
- e_attachment_store_add_attachment (
- store, attachment);
- }
- g_list_free_full (attachments, g_object_unref);
- } else {
- g_warning ("Failed to locate attachment-bar for %s", part_id);
- }
+ e_attachment_set_initially_shown (attachment, e_mail_part_should_show_inline (part));
+
+ e_mail_formatter_claim_attachment (formatter, attachment);
g_object_unref (attachment);
}
@@ -255,43 +189,29 @@ emfe_attachment_format (EMailFormatterExtension *extension,
g_free (text);
g_object_unref (mime_part);
- if (empa->attachment_view_part_id)
- attachment_part_id = empa->attachment_view_part_id;
+ if (empa->part_id_with_attachment)
+ attachment_part_id = empa->part_id_with_attachment;
else
attachment_part_id = part_id;
button_id = g_strconcat (attachment_part_id, ".attachment_button", NULL);
- /* XXX Wild guess at the initial size. */
- buffer = g_string_sized_new (8192);
-
- g_string_append_printf (
- buffer,
- "<div class=\"attachment\">"
- "<table width=\"100%%\" border=\"0\">"
- "<tr valign=\"middle\">"
- "<td align=\"left\" width=\"100\">"
- "<object type=\"application/vnd.evolution.widget.attachment-button\" "
- "height=\"20\" width=\"100\" data=\"%s\" id=\"%s\"></object>"
- "</td>"
- "<td align=\"left\">%s</td>"
- "</tr>", part_id, button_id, html);
-
- g_free (button_id);
- g_free (html);
+ if (!gtk_icon_size_lookup (GTK_ICON_SIZE_BUTTON, &icon_width, &icon_height)) {
+ icon_width = 16;
+ icon_height = 16;
+ }
if (extensions != NULL) {
- GOutputStream *content_stream;
gboolean success = FALSE;
content_stream = g_memory_output_stream_new_resizable ();
- if (empa->attachment_view_part_id != NULL) {
+ if (empa->part_id_with_attachment != NULL) {
EMailPart *attachment_view_part;
attachment_view_part = e_mail_part_list_ref_part (
context->part_list,
- empa->attachment_view_part_id);
+ empa->part_id_with_attachment);
/* Avoid recursion. */
if (attachment_view_part == part)
@@ -322,51 +242,85 @@ emfe_attachment_format (EMailFormatterExtension *extension,
}
}
- if (success) {
- gchar *wrapper_element_id;
- gconstpointer data;
- gsize size;
+ e_mail_part_attachment_set_expandable (empa, success);
+ }
- wrapper_element_id = g_strconcat (
- attachment_part_id, ".wrapper", NULL);
+ icon_uri = e_mail_part_build_uri (
+ e_mail_part_list_get_folder (context->part_list),
+ e_mail_part_list_get_message_uid (context->part_list),
+ "part_id", G_TYPE_STRING, part_id,
+ "attachment_icon", G_TYPE_POINTER, attachment_ptr,
+ "size", G_TYPE_INT, icon_width,
+ NULL);
- data = g_memory_output_stream_get_data (
- G_MEMORY_OUTPUT_STREAM (content_stream));
- size = g_memory_output_stream_get_data_size (
- G_MEMORY_OUTPUT_STREAM (content_stream));
+ /* XXX Wild guess at the initial size. */
+ buffer = g_string_sized_new (8192);
- g_string_append_printf (
- buffer,
- "<tr><td colspan=\"2\">"
- "<div class=\"attachment-wrapper\" id=\"%s\"",
- wrapper_element_id);
+ g_string_append_printf (
+ buffer,
+ "<div class=\"attachment\">"
+ "<table width=\"100%%\" border=\"0\">"
+ "<tr valign=\"middle\">"
+ "<td align=\"left\" width=\"1px\" style=\"white-space:pre;\">"
+ "<button type=\"button\" class=\"attachment-expander\" id=\"%s\" value=\"%p\" data=\"%s\"
style=\"vertical-align:middle; margin:0px;\" %s>"
+ "<img id=\"attachment-expander-img-%p\" src=\"gtk-stock://%s?size=%d\" width=\"%dpx\"
height=\"%dpx\" style=\"vertical-align:middle;\">"
+ "<img src=\"%s\" width=\"%dpx\" height=\"%dpx\" style=\"vertical-align:middle;\">"
+ "</button>"
+ "<button type=\"button\" class=\"attachment-menu\" id=\"%s\" value=\"%p\"
style=\"vertical-align:middle; margin:0px;\">"
+ "<img src=\"gtk-stock://x-evolution-arrow-down?size=%d\" width=\"%dpx\" height=\"%dpx\"
style=\"vertical-align:middle;\">"
+ "</button>"
+ "</td><td align=\"left\">%s</td></tr>",
+ part_id, attachment_ptr, html, e_mail_part_attachment_get_expandable (empa) ? "" : "disabled",
+ attachment_ptr, e_mail_part_should_show_inline (part) ? "go-down" : "go-next",
GTK_ICON_SIZE_BUTTON, icon_width, icon_height,
+ icon_uri, icon_width, icon_height,
+ part_id, attachment_ptr, GTK_ICON_SIZE_BUTTON, icon_width, icon_height,
+ html);
+
+ g_free (icon_uri);
+ g_free (button_id);
+ g_free (html);
- if (e_mail_part_should_show_inline (part)) {
- g_string_append (buffer, ">");
- g_string_append_len (buffer, data, size);
- } else {
- gchar *inner_html_data;
+ if (content_stream && e_mail_part_attachment_get_expandable (empa)) {
+ gchar *wrapper_element_id;
+ gconstpointer data;
+ gsize size;
- inner_html_data = g_markup_escape_text (data, size);
+ wrapper_element_id = g_strdup_printf ("attachment-wrapper-%p", attachment_ptr);
- g_string_append_printf (
- buffer,
- " inner-html-data=\"%s\">",
- inner_html_data);
+ data = g_memory_output_stream_get_data (
+ G_MEMORY_OUTPUT_STREAM (content_stream));
+ size = g_memory_output_stream_get_data_size (
+ G_MEMORY_OUTPUT_STREAM (content_stream));
- g_free (inner_html_data);
- }
+ g_string_append_printf (
+ buffer,
+ "<tr><td colspan=\"2\">"
+ "<div class=\"attachment-wrapper\" id=\"%s\"",
+ wrapper_element_id);
- g_string_append (buffer, "</div></td></tr>");
+ if (e_mail_part_should_show_inline (part)) {
+ g_string_append (buffer, ">");
+ g_string_append_len (buffer, data, size);
+ } else {
+ gchar *inner_html_data;
- e_mail_part_attachment_set_expandable (empa, TRUE);
+ inner_html_data = g_markup_escape_text (data, size);
- g_free (wrapper_element_id);
+ g_string_append_printf (
+ buffer,
+ " inner-html-data=\"%s\">",
+ inner_html_data);
+
+ g_free (inner_html_data);
}
- g_object_unref (content_stream);
+ g_string_append (buffer, "</div></td></tr>");
+
+ g_free (wrapper_element_id);
}
+ g_clear_object (&content_stream);
+
g_string_append (buffer, "</table></div>");
g_output_stream_write_all (
@@ -377,47 +331,6 @@ emfe_attachment_format (EMailFormatterExtension *extension,
return TRUE;
}
-static GtkWidget *
-emfe_attachment_get_widget (EMailFormatterExtension *extension,
- EMailPartList *context,
- EMailPart *part,
- GHashTable *params)
-{
- EAttachment *attachment;
- EAttachmentStore *store;
- EAttachmentView *view;
- GtkWidget *widget;
- const gchar *part_id;
-
- g_return_val_if_fail (E_IS_MAIL_PART_ATTACHMENT (part), NULL);
-
- attachment = e_mail_part_attachment_ref_attachment (
- E_MAIL_PART_ATTACHMENT (part));
-
- part_id = e_mail_part_get_id (part);
-
- store = find_attachment_store (context, part);
- widget = e_attachment_button_new ();
- g_object_set_data_full (
- G_OBJECT (widget),
- "uri", g_strdup (part_id),
- (GDestroyNotify) g_free);
- e_attachment_button_set_attachment (
- E_ATTACHMENT_BUTTON (widget), attachment);
-
- view = g_object_get_data (G_OBJECT (store), "attachment-bar");
- if (view != NULL)
- e_attachment_button_set_view (
- E_ATTACHMENT_BUTTON (widget), view);
-
- gtk_widget_set_can_focus (widget, TRUE);
- gtk_widget_show (widget);
-
- g_object_unref (attachment);
-
- return widget;
-}
-
static void
e_mail_formatter_attachment_class_init (EMailFormatterExtensionClass *class)
{
@@ -426,7 +339,6 @@ e_mail_formatter_attachment_class_init (EMailFormatterExtensionClass *class)
class->mime_types = formatter_mime_types;
class->priority = G_PRIORITY_LOW;
class->format = emfe_attachment_format;
- class->get_widget = emfe_attachment_get_widget;
}
static void
diff --git a/em-format/e-mail-formatter-audio.c b/em-format/e-mail-formatter-audio.c
index cf980f8..2837000 100644
--- a/em-format/e-mail-formatter-audio.c
+++ b/em-format/e-mail-formatter-audio.c
@@ -40,7 +40,7 @@ G_DEFINE_TYPE (
E_TYPE_MAIL_FORMATTER_EXTENSION)
static const gchar *formatter_mime_types[] = {
- "application/vnd.evolution.widget.audio",
+ "application/vnd.evolution.audio",
"audio/ac3",
"audio/x-ac3",
"audio/basic",
diff --git a/em-format/e-mail-formatter-enums.h b/em-format/e-mail-formatter-enums.h
index e7b1868..de64568 100644
--- a/em-format/e-mail-formatter-enums.h
+++ b/em-format/e-mail-formatter-enums.h
@@ -49,7 +49,6 @@ typedef enum {
E_MAIL_FORMATTER_MODE_NORMAL = 0,
E_MAIL_FORMATTER_MODE_SOURCE,
E_MAIL_FORMATTER_MODE_RAW,
- E_MAIL_FORMATTER_MODE_CID,
E_MAIL_FORMATTER_MODE_PRINTING,
E_MAIL_FORMATTER_MODE_ALL_HEADERS
} EMailFormatterMode;
diff --git a/em-format/e-mail-formatter-extension.c b/em-format/e-mail-formatter-extension.c
index 55b481b..3a2dd52 100644
--- a/em-format/e-mail-formatter-extension.c
+++ b/em-format/e-mail-formatter-extension.c
@@ -78,64 +78,3 @@ e_mail_formatter_extension_format (EMailFormatterExtension *extension,
return class->format (
extension, formatter, context, part, stream, cancellable);
}
-
-/**
- * e_mail_formatter_extension_has_widget:
- * @extension: an #EMailFormatterExtension
- *
- * Returns whether the extension can provide a GtkWidget.
- *
- * Returns: Returns %TRUE when @extension reimplements get_widget(), %FALSE
- * otherwise.
- */
-gboolean
-e_mail_formatter_extension_has_widget (EMailFormatterExtension *extension)
-{
- EMailFormatterExtensionClass *class;
-
- g_return_val_if_fail (E_IS_MAIL_FORMATTER_EXTENSION (extension), FALSE);
-
- class = E_MAIL_FORMATTER_EXTENSION_GET_CLASS (extension);
-
- return (class->get_widget != NULL);
-}
-
-/**
- * e_mail_formatter_extension_get_widget:
- * @extension: an #EMailFormatterExtension
- * @part: an #EMailPart
- * @params: a #GHashTable
- *
- * A virtual function reimplemented in some mail formatter extensions. The
- * function should construct a #GtkWidget for given @part. The @params hash
- * table can contain additional parameters listed in the <object> HTML
- * element that has requested the widget.
- *
- * When @bind_dom_func is not %NULL, the callee will set a callback function
- * which should be called when the webpage is completely rendered to setup
- * bindings between DOM events and the widget.
- *
- * Returns: Returns a #GtkWidget or %NULL, when error occurs or given
- * @extension does not reimplement this method.
- */
-GtkWidget *
-e_mail_formatter_extension_get_widget (EMailFormatterExtension *extension,
- EMailPartList *context,
- EMailPart *part,
- GHashTable *params)
-{
- EMailFormatterExtensionClass *class;
- GtkWidget *widget = NULL;
-
- g_return_val_if_fail (E_IS_MAIL_FORMATTER_EXTENSION (extension), NULL);
- g_return_val_if_fail (part != NULL, NULL);
- g_return_val_if_fail (params != NULL, NULL);
-
- class = E_MAIL_FORMATTER_EXTENSION_GET_CLASS (extension);
-
- if (class->get_widget != NULL)
- widget = class->get_widget (extension, context, part, params);
-
- return widget;
-}
-
diff --git a/em-format/e-mail-formatter-extension.h b/em-format/e-mail-formatter-extension.h
index adfe98f..8e46deb 100644
--- a/em-format/e-mail-formatter-extension.h
+++ b/em-format/e-mail-formatter-extension.h
@@ -83,10 +83,6 @@ struct _EMailFormatterExtensionClass {
EMailPart *part,
GOutputStream *stream,
GCancellable *cancellable);
- GtkWidget * (*get_widget) (EMailFormatterExtension *extension,
- EMailPartList *context,
- EMailPart *part,
- GHashTable *params);
};
GType e_mail_formatter_extension_get_type
@@ -98,13 +94,6 @@ gboolean e_mail_formatter_extension_format
EMailPart *part,
GOutputStream *stream,
GCancellable *cancellable);
-gboolean e_mail_formatter_extension_has_widget
- (EMailFormatterExtension *extension);
-GtkWidget * e_mail_formatter_extension_get_widget
- (EMailFormatterExtension *extension,
- EMailPartList *context,
- EMailPart *part,
- GHashTable *params);
G_END_DECLS
diff --git a/em-format/e-mail-formatter-headers.c b/em-format/e-mail-formatter-headers.c
index 42d2e9e..2affbe1 100644
--- a/em-format/e-mail-formatter-headers.c
+++ b/em-format/e-mail-formatter-headers.c
@@ -522,7 +522,7 @@ emfe_headers_format (EMailFormatterExtension *extension,
g_string_append_printf (
buffer,
"%s id=\"%s\"><table class=\"-e-mail-formatter-header-color\" border=\"0\" width=\"100%%\" "
- "style=\"direction: %s\">"
+ "style=\"direction: %s; border-spacing: 0px\">"
"<tr>",
(context->mode != E_MAIL_FORMATTER_MODE_PRINTING) ?
"<div class=\"headers -e-mail-formatter-body-color\"" :
@@ -533,7 +533,7 @@ emfe_headers_format (EMailFormatterExtension *extension,
if (is_collapsable)
g_string_append_printf (
buffer,
- "<td valign=\"top\" width=\"16\">"
+ "<td valign=\"top\" width=\"16\" style=\"padding-left: 0px\">"
"<img src=\"evo-file://%s/%s\" class=\"navigable\" "
" id=\"__evo-collapse-headers-img\" />"
"</td>",
diff --git a/em-format/e-mail-formatter-message-rfc822.c b/em-format/e-mail-formatter-message-rfc822.c
index 8884cbc..7f8d6ef 100644
--- a/em-format/e-mail-formatter-message-rfc822.c
+++ b/em-format/e-mail-formatter-message-rfc822.c
@@ -157,10 +157,6 @@ emfe_message_rfc822_format (EMailFormatterExtension *extension,
EMailPart *p = link->data;
const gchar *p_id;
- /* Skip attachment bar */
- if (e_mail_part_id_has_suffix (part, ".attachment-bar"))
- continue;
-
p_id = e_mail_part_get_id (p);
/* Check for nested rfc822 messages */
diff --git a/em-format/e-mail-formatter-quote-message-rfc822.c
b/em-format/e-mail-formatter-quote-message-rfc822.c
index 180a283..7ed0bd4 100644
--- a/em-format/e-mail-formatter-quote-message-rfc822.c
+++ b/em-format/e-mail-formatter-quote-message-rfc822.c
@@ -89,10 +89,6 @@ emfqe_message_rfc822_format (EMailFormatterExtension *extension,
p_id = e_mail_part_get_id (p);
- /* Skip attachment bar */
- if (e_mail_part_id_has_suffix (p, ".attachment-bar"))
- continue;
-
if (e_mail_part_id_has_suffix (p, ".headers.")) {
if (qc->qf_flags & E_MAIL_FORMATTER_QUOTE_FLAG_HEADERS) {
e_mail_formatter_format_as (
diff --git a/em-format/e-mail-formatter-quote.c b/em-format/e-mail-formatter-quote.c
index adbe223..24abcbb 100644
--- a/em-format/e-mail-formatter-quote.c
+++ b/em-format/e-mail-formatter-quote.c
@@ -38,7 +38,6 @@ struct _EMailFormatterQuotePrivate {
};
/* internal formatter extensions */
-GType e_mail_formatter_quote_attachment_get_type (void);
GType e_mail_formatter_quote_headers_get_type (void);
GType e_mail_formatter_quote_message_rfc822_get_type (void);
GType e_mail_formatter_quote_text_enriched_get_type (void);
@@ -161,7 +160,6 @@ static void
e_mail_formatter_quote_base_init (EMailFormatterQuoteClass *class)
{
/* Register internal extensions. */
- g_type_ensure (e_mail_formatter_quote_attachment_get_type ());
g_type_ensure (e_mail_formatter_quote_headers_get_type ());
g_type_ensure (e_mail_formatter_quote_message_rfc822_get_type ());
g_type_ensure (e_mail_formatter_quote_text_enriched_get_type ());
diff --git a/em-format/e-mail-formatter-secure-button.c b/em-format/e-mail-formatter-secure-button.c
index d4f6a96..80cfb09 100644
--- a/em-format/e-mail-formatter-secure-button.c
+++ b/em-format/e-mail-formatter-secure-button.c
@@ -23,11 +23,6 @@
#include <e-util/e-util.h>
-#if defined (HAVE_NSS) && defined (ENABLE_SMIME)
-#include "certificate-manager.h"
-#include "e-cert-db.h"
-#endif
-
#include "e-mail-formatter-extension.h"
typedef EMailFormatterExtension EMailFormatterSecureButton;
@@ -41,7 +36,7 @@ G_DEFINE_TYPE (
E_TYPE_MAIL_FORMATTER_EXTENSION)
static const gchar *formatter_mime_types[] = {
- "application/vnd.evolution.widget.secure-button",
+ "application/vnd.evolution.secure-button",
NULL
};
@@ -76,139 +71,25 @@ static const GdkRGBA smime_sign_colour[6] = {
{ 0.0, 0.0, 0.0, 1.0 }
};
-static gboolean
-emfe_secure_button_format (EMailFormatterExtension *extension,
- EMailFormatter *formatter,
- EMailFormatterContext *context,
- EMailPart *part,
- GOutputStream *stream,
- GCancellable *cancellable)
-{
- gchar *str;
+/* This is awkward, but there is no header file for it. On the other hand,
+ the functions are meant private, where they really are, being defined this way. */
+const gchar *e_mail_formatter_secure_button_get_encrypt_description (CamelCipherValidityEncrypt status);
+const gchar *e_mail_formatter_secure_button_get_sign_description (CamelCipherValiditySign status);
- if ((context->mode != E_MAIL_FORMATTER_MODE_NORMAL) &&
- (context->mode != E_MAIL_FORMATTER_MODE_RAW) &&
- (context->mode != E_MAIL_FORMATTER_MODE_ALL_HEADERS))
- return FALSE;
-
- str = g_strdup_printf (
- "<object type=\"application/vnd.evolution.widget.secure-button\" "
- "height=\"20\" width=\"100%%\" data=\"%s\" id=\"%s\"></object>",
- e_mail_part_get_id (part),
- e_mail_part_get_id (part));
-
- g_output_stream_write_all (
- stream, str, strlen (str), NULL, cancellable, NULL);
-
- g_free (str);
-
- return TRUE;
-}
-
-#if defined (HAVE_NSS) && defined (ENABLE_SMIME)
-static void
-viewcert_clicked (GtkWidget *button,
- GtkWidget *grid)
+const gchar *
+e_mail_formatter_secure_button_get_sign_description (CamelCipherValiditySign status)
{
- CamelCipherCertInfo *info = g_object_get_data ((GObject *) button, "e-cert-info");
- ECert *ec = NULL;
-
- if (info->cert_data)
- ec = e_cert_new (CERT_DupCertificate (info->cert_data));
+ g_return_val_if_fail (status >= 0 && status < G_N_ELEMENTS (smime_sign_table), NULL);
- if (ec != NULL) {
- GtkWidget *dialog, *parent;
-
- parent = gtk_widget_get_toplevel (grid);
- if (!parent || !GTK_IS_WINDOW (parent))
- parent = NULL;
-
- dialog = e_cert_manager_new_certificate_viewer ((GtkWindow *) parent, ec);
-
- gtk_widget_show (dialog);
- g_signal_connect (
- dialog, "response",
- G_CALLBACK (gtk_widget_destroy), NULL);
-
- g_object_unref (ec);
- } else {
- g_warning (
- "can't find certificate for %s <%s>",
- info->name ? info->name : "",
- info->email ? info->email : "");
- }
+ return _(smime_sign_table[status].description);
}
-#endif
-static void
-info_response (GtkWidget *widget,
- guint button,
- gpointer user_data)
-{
- gtk_widget_destroy (widget);
-}
-
-static void
-add_cert_table (GtkWidget *grid,
- GQueue *certlist,
- gpointer user_data)
+const gchar *
+e_mail_formatter_secure_button_get_encrypt_description (CamelCipherValidityEncrypt status)
{
- GList *head, *link;
- GtkTable *table;
- gint n = 0;
-
- table = (GtkTable *) gtk_table_new (certlist->length, 2, FALSE);
-
- head = g_queue_peek_head_link (certlist);
-
- for (link = head; link != NULL; link = g_list_next (link)) {
- CamelCipherCertInfo *info = link->data;
- gchar *la = NULL;
- const gchar *l = NULL;
-
- if (info->name) {
- if (info->email && strcmp (info->name, info->email) != 0)
- l = la = g_strdup_printf ("%s <%s>", info->name, info->email);
- else
- l = info->name;
- } else {
- if (info->email)
- l = info->email;
- }
-
- if (l) {
- GtkWidget *w;
-#if defined (HAVE_NSS) && defined (ENABLE_SMIME)
- ECert *ec = NULL;
-#endif
- w = gtk_label_new (l);
- gtk_misc_set_alignment ((GtkMisc *) w, 0.0, 0.5);
- g_free (la);
- gtk_table_attach (table, w, 0, 1, n, n + 1, GTK_FILL, GTK_FILL, 3, 3);
-#if defined (HAVE_NSS) && defined (ENABLE_SMIME)
- w = gtk_button_new_with_mnemonic (_("_View Certificate"));
- gtk_table_attach (table, w, 1, 2, n, n + 1, 0, 0, 3, 3);
- g_object_set_data ((GObject *) w, "e-cert-info", info);
- g_signal_connect (
- w, "clicked",
- G_CALLBACK (viewcert_clicked), grid);
-
- if (info->cert_data)
- ec = e_cert_new (CERT_DupCertificate (info->cert_data));
-
- if (ec == NULL)
- gtk_widget_set_sensitive (w, FALSE);
- else
- g_object_unref (ec);
-#else
- w = gtk_label_new (_("This certificate is not viewable"));
- gtk_table_attach (table, w, 1, 2, n, n + 1, 0, 0, 3, 3);
-#endif
- n++;
- }
- }
+ g_return_val_if_fail (status >= 0 && status < G_N_ELEMENTS (smime_encrypt_table), NULL);
- gtk_container_add (GTK_CONTAINER (grid), GTK_WIDGET (table));
+ return _(smime_encrypt_table[status].description);
}
static void
@@ -246,9 +127,9 @@ format_cert_infos (GQueue *cert_infos,
g_string_append (output_buffer, cinfo->name);
if (cinfo->email != NULL && *cinfo->email != '\0') {
- g_string_append (output_buffer, " <");
+ g_string_append (output_buffer, " <");
g_string_append (output_buffer, cinfo->email);
- g_string_append (output_buffer, ">");
+ g_string_append (output_buffer, ">");
}
} else if (cinfo->email != NULL && *cinfo->email != '\0') {
@@ -263,130 +144,22 @@ format_cert_infos (GQueue *cert_infos,
}
static void
-secure_button_clicked_cb (GtkWidget *widget,
- CamelCipherValidity *validity)
-{
- GtkBuilder *builder;
- GtkWidget *grid, *w;
- GtkWidget *dialog;
-
- g_return_if_fail (validity != NULL);
-
- /* Make sure our custom widget classes are registered with
- * GType before we load the GtkBuilder definition file. */
- g_type_ensure (E_TYPE_DATE_EDIT);
-
- builder = gtk_builder_new ();
- e_load_ui_builder_definition (builder, "mail-dialogs.ui");
-
- dialog = e_builder_get_widget (builder, "message_security_dialog");
-
- grid = e_builder_get_widget (builder, "signature_grid");
- w = gtk_label_new (_(smime_sign_table[validity->sign.status].description));
- gtk_misc_set_alignment ((GtkMisc *) w, 0.0, 0.5);
- gtk_label_set_line_wrap ((GtkLabel *) w, TRUE);
- gtk_label_set_max_width_chars (GTK_LABEL (w), 80);
- gtk_container_add (GTK_CONTAINER (grid), w);
- if (validity->sign.description) {
- GtkTextBuffer *buffer;
-
- buffer = gtk_text_buffer_new (NULL);
- gtk_text_buffer_set_text (
- buffer, validity->sign.description,
- strlen (validity->sign.description));
- w = g_object_new (
- gtk_scrolled_window_get_type (),
- "hscrollbar_policy", GTK_POLICY_AUTOMATIC,
- "vscrollbar_policy", GTK_POLICY_AUTOMATIC,
- "shadow_type", GTK_SHADOW_IN,
- "expand", TRUE,
- "child", g_object_new (gtk_text_view_get_type (),
- "buffer", buffer,
- "cursor_visible", FALSE,
- "editable", FALSE,
- NULL),
- "width_request", 500,
- "height_request", 80,
- NULL);
- g_object_unref (buffer);
-
- gtk_container_add (GTK_CONTAINER (grid), w);
- }
-
- if (!g_queue_is_empty (&validity->sign.signers))
- add_cert_table (
- grid, &validity->sign.signers, NULL);
-
- gtk_widget_show_all (grid);
-
- grid = e_builder_get_widget (builder, "encryption_grid");
- w = gtk_label_new (_(smime_encrypt_table[validity->encrypt.status].description));
- gtk_misc_set_alignment ((GtkMisc *) w, 0.0, 0.5);
- gtk_label_set_line_wrap ((GtkLabel *) w, TRUE);
- gtk_label_set_max_width_chars (GTK_LABEL (w), 80);
- gtk_container_add (GTK_CONTAINER (grid), w);
- if (validity->encrypt.description) {
- GtkTextBuffer *buffer;
-
- buffer = gtk_text_buffer_new (NULL);
- gtk_text_buffer_set_text (
- buffer, validity->encrypt.description,
- strlen (validity->encrypt.description));
- w = g_object_new (
- gtk_scrolled_window_get_type (),
- "hscrollbar_policy", GTK_POLICY_AUTOMATIC,
- "vscrollbar_policy", GTK_POLICY_AUTOMATIC,
- "shadow_type", GTK_SHADOW_IN,
- "expand", TRUE,
- "child", g_object_new (gtk_text_view_get_type (),
- "buffer", buffer,
- "cursor_visible", FALSE,
- "editable", FALSE,
- NULL),
- "width_request", 500,
- "height_request", 80,
- NULL);
- g_object_unref (buffer);
-
- gtk_container_add (GTK_CONTAINER (grid), w);
- }
-
- if (!g_queue_is_empty (&validity->encrypt.encrypters))
- add_cert_table (grid, &validity->encrypt.encrypters, NULL);
-
- gtk_widget_show_all (grid);
-
- g_object_unref (builder);
-
- g_signal_connect (
- dialog, "response",
- G_CALLBACK (info_response), NULL);
-
- gtk_widget_show (dialog);
-}
-
-static void
add_photo_cb (gpointer data,
gpointer user_data)
{
CamelCipherCertInfo *cert_info = data;
gint width, height;
- GtkWidget *image;
- GdkPixbuf *pixbuf, *scaled;
- GtkBox *box = user_data;
+ GString *html = user_data;
const gchar *photo_filename;
+ gchar *uri;
g_return_if_fail (cert_info != NULL);
- g_return_if_fail (GTK_IS_BOX (box));
+ g_return_if_fail (html != NULL);
photo_filename = camel_cipher_certinfo_get_property (cert_info,
CAMEL_CIPHER_CERT_INFO_PROPERTY_PHOTO_FILENAME);
if (!photo_filename || !g_file_test (photo_filename, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR))
return;
- pixbuf = gdk_pixbuf_new_from_file (photo_filename, NULL);
- if (!pixbuf)
- return;
-
if (!gtk_icon_size_lookup (GTK_ICON_SIZE_DND, &width, &height)) {
width = 32;
height = 32;
@@ -397,30 +170,25 @@ add_photo_cb (gpointer data,
if (height < 32)
height = 32;
- scaled = e_icon_factory_pixbuf_scale (pixbuf, width, height);
- g_object_unref (pixbuf);
+ uri = g_filename_to_uri (photo_filename, NULL, NULL);
- if (!scaled)
- return;
-
- image = gtk_image_new_from_pixbuf (scaled);
- g_object_unref (scaled);
+ g_string_append_printf (html, "<img src=\"evo-%s\" width=\"%dpx\" height=\"%dpx\"
style=\"vertical-align:middle; margin-right:4px;\">",
+ uri, width, height);
- if (!image)
- return;
-
- gtk_box_pack_start (box, image, FALSE, FALSE, 0);
+ g_free (uri);
}
-static GtkWidget *
-secure_button_get_widget_for_validity (CamelCipherValidity *validity)
+static void
+secure_button_format_validity (EMailPart *part,
+ CamelCipherValidity *validity,
+ GString *html)
{
- GtkWidget *box, *button, *layout, *widget;
const gchar *icon_name;
gchar *description;
+ gint icon_width, icon_height;
GString *buffer;
- g_return_val_if_fail (validity != NULL, NULL);
+ g_return_if_fail (validity != NULL);
buffer = g_string_new ("");
@@ -441,7 +209,7 @@ secure_button_get_widget_for_validity (CamelCipherValidity *validity)
gint status;
if (validity->sign.status != CAMEL_CIPHER_VALIDITY_SIGN_NONE)
- g_string_append (buffer, "\n");
+ g_string_append (buffer, "<br>\n");
status = validity->encrypt.status;
desc = smime_encrypt_table[status].shortdesc;
@@ -451,90 +219,70 @@ secure_button_get_widget_for_validity (CamelCipherValidity *validity)
description = g_string_free (buffer, FALSE);
/* FIXME: need to have it based on encryption and signing too */
- if (validity->sign.status != 0)
+ if (validity->sign.status != CAMEL_CIPHER_VALIDITY_SIGN_NONE)
icon_name = smime_sign_table[validity->sign.status].icon;
else
icon_name = smime_encrypt_table[validity->encrypt.status].icon;
- box = gtk_event_box_new ();
- if (validity->sign.status != 0)
- gtk_widget_override_background_color (
- box, GTK_STATE_FLAG_NORMAL,
- &smime_sign_colour[validity->sign.status]);
-
- layout = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5);
- gtk_container_add (GTK_CONTAINER (box), layout);
-
- button = gtk_button_new ();
- gtk_box_pack_start (GTK_BOX (layout), button, FALSE, FALSE, 0);
- g_signal_connect (
- button, "clicked",
- G_CALLBACK (secure_button_clicked_cb), validity);
-
- widget = gtk_image_new_from_icon_name (
- icon_name, GTK_ICON_SIZE_LARGE_TOOLBAR);
- gtk_button_set_image (GTK_BUTTON (button), widget);
-
- g_queue_foreach (&validity->sign.signers, add_photo_cb, layout);
- g_queue_foreach (&validity->encrypt.encrypters, add_photo_cb, layout);
-
- widget = gtk_label_new (description);
- g_object_set (G_OBJECT (widget),
- "wrap", TRUE,
- "width-chars", 20,
- "max-width-chars", 80,
- "xalign", 0.0,
- "halign", GTK_ALIGN_FILL,
- "hexpand", TRUE,
- NULL);
- /* make sure the text color doesn't change with theme */
- gtk_widget_override_color (widget, GTK_STATE_FLAG_NORMAL, &smime_sign_colour[5]);
- gtk_box_pack_start (GTK_BOX (layout), widget, TRUE, TRUE, 0);
+ if (!gtk_icon_size_lookup (GTK_ICON_SIZE_LARGE_TOOLBAR, &icon_width, &icon_height)) {
+ icon_width = 24;
+ icon_height = 24;
+ }
- g_free (description);
+ g_string_append (html, "<table width=\"100%\" style=\"vertical-align:middle;");
+ if (validity->sign.status != CAMEL_CIPHER_VALIDITY_SIGN_NONE &&
+ smime_sign_colour[validity->sign.status].alpha > 1e-9)
+ g_string_append_printf (html, " background:#%06x;",
+ e_rgba_to_value (&smime_sign_colour[validity->sign.status]));
+ g_string_append (html, "\"><tr>");
+
+ g_string_append_printf (html,
+ "<td style=\"width:1px;\"><button type=\"button\" class=\"secure-button\"
id=\"secure-button\" value=\"%p:%p\" accesskey=\"\" style=\"vertical-align:middle;\">"
+ "<img src=\"gtk-stock://%s?size=%d\" width=\"%dpx\" height=\"%dpx\"
style=\"vertical-align:middle;\"></button></td><td><span style=\"color:#%06x; vertical-align:middle;\">",
+ part, validity, icon_name, GTK_ICON_SIZE_LARGE_TOOLBAR,
+ icon_width, icon_height, e_rgba_to_value (&smime_sign_colour[5]));
+
+ g_queue_foreach (&validity->sign.signers, add_photo_cb, html);
+ g_queue_foreach (&validity->encrypt.encrypters, add_photo_cb, html);
+
+ g_string_append_printf (html, "%s</span></td></tr></table>\n", description);
- return box;
+ g_free (description);
}
-static GtkWidget *
-emfe_secure_button_get_widget (EMailFormatterExtension *extension,
- EMailPartList *context,
- EMailPart *part,
- GHashTable *params)
+static gboolean
+emfe_secure_button_format (EMailFormatterExtension *extension,
+ EMailFormatter *formatter,
+ EMailFormatterContext *context,
+ EMailPart *part,
+ GOutputStream *stream,
+ GCancellable *cancellable)
{
- GtkWidget *grid;
GList *head, *link;
+ GString *html;
- g_return_val_if_fail (part != NULL, NULL);
-
- grid = g_object_new (
- GTK_TYPE_GRID,
- "orientation", GTK_ORIENTATION_VERTICAL,
- "row-spacing", 2,
- "halign", GTK_ALIGN_FILL,
- "hexpand", TRUE,
- NULL);
+ if ((context->mode != E_MAIL_FORMATTER_MODE_NORMAL) &&
+ (context->mode != E_MAIL_FORMATTER_MODE_RAW) &&
+ (context->mode != E_MAIL_FORMATTER_MODE_ALL_HEADERS))
+ return FALSE;
+ html = g_string_new ("");
head = g_queue_peek_head_link (&part->validities);
for (link = head; link != NULL; link = g_list_next (link)) {
EMailPartValidityPair *pair = link->data;
- GtkWidget *widget;
- if (pair == NULL)
+ if (!pair)
continue;
- widget = secure_button_get_widget_for_validity (pair->validity);
- if (widget != NULL) {
- gtk_widget_set_halign (widget, GTK_ALIGN_FILL);
- gtk_widget_set_hexpand (widget, TRUE);
- gtk_container_add (GTK_CONTAINER (grid), widget);
- }
+ secure_button_format_validity (part, pair->validity, html);
}
- gtk_widget_show_all (grid);
+ g_output_stream_write_all (stream, html->str, html->len, NULL, cancellable, NULL);
- return grid;
+ g_string_free (html, TRUE);
+
+ return TRUE;
}
static void
@@ -543,7 +291,6 @@ e_mail_formatter_secure_button_class_init (EMailFormatterExtensionClass *class)
class->mime_types = formatter_mime_types;
class->priority = G_PRIORITY_LOW;
class->format = emfe_secure_button_format;
- class->get_widget = emfe_secure_button_get_widget;
}
static void
diff --git a/em-format/e-mail-formatter.c b/em-format/e-mail-formatter.c
index 668b2ef..13e68c5 100644
--- a/em-format/e-mail-formatter.c
+++ b/em-format/e-mail-formatter.c
@@ -34,7 +34,7 @@
#define E_MAIL_FORMATTER_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE \
- ((obj), E_TYPE_MAIL_FORMATTER, EMailFormatterPrivate))\
+ ((obj), E_TYPE_MAIL_FORMATTER, EMailFormatterPrivate))
#define STYLESHEET_URI \
"evo-file://" EVOLUTION_PRIVDATADIR "/theme/webview.css"
@@ -63,7 +63,6 @@ struct _AsyncContext {
/* internal formatter extensions */
GType e_mail_formatter_attachment_get_type (void);
-GType e_mail_formatter_attachment_bar_get_type (void);
GType e_mail_formatter_audio_get_type (void);
GType e_mail_formatter_error_get_type (void);
GType e_mail_formatter_headers_get_type (void);
@@ -96,6 +95,7 @@ enum {
enum {
NEED_REDRAW,
+ CLAIM_ATTACHMENT,
LAST_SIGNAL
};
@@ -451,8 +451,7 @@ mail_formatter_run (EMailFormatter *formatter,
if (!ok) {
/* We don't want to source these */
- if (e_mail_part_id_has_suffix (part, ".headers") ||
- e_mail_part_id_has_suffix (part, "attachment-bar"))
+ if (e_mail_part_id_has_suffix (part, ".headers"))
continue;
e_mail_formatter_format_as (
@@ -560,7 +559,6 @@ e_mail_formatter_base_init (EMailFormatterClass *class)
/* Register internal extensions. */
g_type_ensure (e_mail_formatter_attachment_get_type ());
- g_type_ensure (e_mail_formatter_attachment_bar_get_type ());
g_type_ensure (e_mail_formatter_audio_get_type ());
g_type_ensure (e_mail_formatter_error_get_type ());
g_type_ensure (e_mail_formatter_headers_get_type ());
@@ -773,6 +771,14 @@ e_mail_formatter_class_init (EMailFormatterClass *class)
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS));
+ signals[CLAIM_ATTACHMENT] = g_signal_new (
+ "claim-attachment",
+ E_TYPE_MAIL_FORMATTER,
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (EMailFormatterClass, claim_attachment),
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 1, E_TYPE_ATTACHMENT);
+
signals[NEED_REDRAW] = g_signal_new (
"need-redraw",
E_TYPE_MAIL_FORMATTER,
@@ -837,6 +843,16 @@ e_mail_formatter_get_type (void)
}
void
+e_mail_formatter_claim_attachment (EMailFormatter *formatter,
+ EAttachment *attachment)
+{
+ g_return_if_fail (E_IS_MAIL_FORMATTER (formatter));
+ g_return_if_fail (E_IS_ATTACHMENT (attachment));
+
+ g_signal_emit (formatter, signals[CLAIM_ATTACHMENT], 0, attachment);
+}
+
+void
e_mail_formatter_format_sync (EMailFormatter *formatter,
EMailPartList *part_list,
GOutputStream *stream,
@@ -1117,7 +1133,6 @@ e_mail_formatter_format_text (EMailFormatter *formatter,
g_output_stream_flush (stream, cancellable, NULL);
g_object_unref (stream);
-
g_clear_object (&windows);
g_clear_object (&mime_part);
}
@@ -1131,9 +1146,9 @@ e_mail_formatter_get_sub_html_header (EMailFormatter *formatter)
"<meta name=\"generator\" content=\"Evolution Mail\"/>\n"
"<title>Evolution Mail Display</title>\n"
"<link type=\"text/css\" rel=\"stylesheet\" "
- " href=\"" STYLESHEET_URI "\"/>\n"
+ " href=\"" STYLESHEET_URI "\"/>\n"
"<style type=\"text/css\">\n"
- " table th { font-weight: bold; }\n"
+ " table th { font-weight: bold; }\n"
"</style>\n"
"</head>"
"<body class=\"-e-web-view-background-color -e-web-view-text-color\">";
@@ -1149,9 +1164,9 @@ e_mail_formatter_get_html_header (EMailFormatter *formatter)
"<meta name=\"generator\" content=\"Evolution Mail\"/>\n"
"<title>Evolution Mail Display</title>\n"
"<link type=\"text/css\" rel=\"stylesheet\" "
- " href=\"" STYLESHEET_URI "\"/>\n"
+ " href=\"" STYLESHEET_URI "\"/>\n"
"<style type=\"text/css\">\n"
- " table th { font-weight: bold; }\n"
+ " table th { font-weight: bold; }\n"
"</style>\n"
"</head>"
"<body class=\"-e-mail-formatter-body-color "
diff --git a/em-format/e-mail-formatter.h b/em-format/e-mail-formatter.h
index a05755c..777e31a 100644
--- a/em-format/e-mail-formatter.h
+++ b/em-format/e-mail-formatter.h
@@ -85,13 +85,17 @@ struct _EMailFormatterClass {
/* Signals */
void (*need_redraw) (EMailFormatter *formatter);
+ void (*claim_attachment) (EMailFormatter *formatter,
+ EAttachment *attachment);
};
GType e_mail_formatter_get_type (void);
EMailFormatter *
e_mail_formatter_new (void);
-
+void e_mail_formatter_claim_attachment
+ (EMailFormatter *formatter,
+ EAttachment *attachment);
void e_mail_formatter_format_sync (EMailFormatter *formatter,
EMailPartList *part_list,
GOutputStream *stream,
diff --git a/em-format/e-mail-parser-application-smime.c b/em-format/e-mail-parser-application-smime.c
index 95f07b4..f3673bf 100644
--- a/em-format/e-mail-parser-application-smime.c
+++ b/em-format/e-mail-parser-application-smime.c
@@ -120,7 +120,7 @@ empe_app_smime_parse (EMailParserExtension *extension,
e_mail_parser_parse_part_as (
parser, part, part_id,
- "application/vnd.evolution.widget.secure-button",
+ "application/vnd.evolution.secure-button",
cancellable, &work_queue);
mail_part = g_queue_peek_head (&work_queue);
diff --git a/em-format/e-mail-parser-inlinepgp-encrypted.c b/em-format/e-mail-parser-inlinepgp-encrypted.c
index 56d5fc5..bdabcb8 100644
--- a/em-format/e-mail-parser-inlinepgp-encrypted.c
+++ b/em-format/e-mail-parser-inlinepgp-encrypted.c
@@ -148,7 +148,7 @@ empe_inlinepgp_encrypted_parse (EMailParserExtension *extension,
e_mail_parser_parse_part_as (
parser, part, part_id,
- "application/vnd.evolution.widget.secure-button",
+ "application/vnd.evolution.secure-button",
cancellable, &work_queue);
mail_part = g_queue_peek_head (&work_queue);
diff --git a/em-format/e-mail-parser-inlinepgp-signed.c b/em-format/e-mail-parser-inlinepgp-signed.c
index 9f08583..84f38bd 100644
--- a/em-format/e-mail-parser-inlinepgp-signed.c
+++ b/em-format/e-mail-parser-inlinepgp-signed.c
@@ -160,7 +160,7 @@ empe_inlinepgp_signed_parse (EMailParserExtension *extension,
e_mail_parser_parse_part_as (
parser, part, part_id,
- "application/vnd.evolution.widget.secure-button",
+ "application/vnd.evolution.secure-button",
cancellable, &work_queue);
mail_part = g_queue_peek_head (&work_queue);
diff --git a/em-format/e-mail-parser-message.c b/em-format/e-mail-parser-message.c
index 282cef4..0a3b77f 100644
--- a/em-format/e-mail-parser-message.c
+++ b/em-format/e-mail-parser-message.c
@@ -63,12 +63,6 @@ empe_message_parse (EMailParserExtension *extension,
"application/vnd.evolution.headers",
cancellable, out_mail_parts);
- /* Attachment Bar */
- e_mail_parser_parse_part_as (
- parser, part, part_id,
- "application/vnd.evolution.widget.attachment-bar",
- cancellable, out_mail_parts);
-
ct = camel_mime_part_get_content_type (part);
mime_type = camel_content_type_simple (ct);
diff --git a/em-format/e-mail-parser-multipart-encrypted.c b/em-format/e-mail-parser-multipart-encrypted.c
index dff97b3..6c8a65e 100644
--- a/em-format/e-mail-parser-multipart-encrypted.c
+++ b/em-format/e-mail-parser-multipart-encrypted.c
@@ -143,7 +143,7 @@ empe_mp_encrypted_parse (EMailParserExtension *extension,
e_mail_parser_parse_part_as (
parser, part, part_id,
- "application/vnd.evolution.widget.secure-button",
+ "application/vnd.evolution.secure-button",
cancellable, &work_queue);
mail_part = g_queue_peek_head (&work_queue);
diff --git a/em-format/e-mail-parser-multipart-signed.c b/em-format/e-mail-parser-multipart-signed.c
index c467ec7..f90d645 100644
--- a/em-format/e-mail-parser-multipart-signed.c
+++ b/em-format/e-mail-parser-multipart-signed.c
@@ -188,7 +188,7 @@ empe_mp_signed_parse (EMailParserExtension *extension,
e_mail_parser_parse_part_as (
parser, part, part_id,
- "application/vnd.evolution.widget.secure-button",
+ "application/vnd.evolution.secure-button",
cancellable, &work_queue);
mail_part = g_queue_peek_head (&work_queue);
diff --git a/em-format/e-mail-parser-secure-button.c b/em-format/e-mail-parser-secure-button.c
index 61832a0..e458598 100644
--- a/em-format/e-mail-parser-secure-button.c
+++ b/em-format/e-mail-parser-secure-button.c
@@ -23,6 +23,7 @@
#include <e-util/e-util.h>
+#include "e-mail-part-secure-button.h"
#include "e-mail-parser-extension.h"
typedef EMailParserExtension EMailParserSecureButton;
@@ -36,7 +37,7 @@ G_DEFINE_TYPE (
E_TYPE_MAIL_PARSER_EXTENSION)
static const gchar *parser_mime_types[] = {
- "application/vnd.evolution.widget.secure-button",
+ "application/vnd.evolution.secure-button",
NULL
};
@@ -53,7 +54,7 @@ empe_secure_button_parse (EMailParserExtension *extension,
len = part_id->len;
g_string_append (part_id, ".secure_button");
- mail_part = e_mail_part_new (part, part_id->str);
+ mail_part = e_mail_part_secure_button_new (part, part_id->str);
e_mail_part_set_mime_type (mail_part, parser_mime_types[0]);
g_string_truncate (part_id, len);
diff --git a/em-format/e-mail-parser-text-plain.c b/em-format/e-mail-parser-text-plain.c
index ccb371d..aa5c55a 100644
--- a/em-format/e-mail-parser-text-plain.c
+++ b/em-format/e-mail-parser-text-plain.c
@@ -185,7 +185,7 @@ empe_text_plain_parse (EMailParserExtension *extension,
empa->shown = FALSE;
attachment = e_mail_part_attachment_ref_attachment (empa);
- e_attachment_set_shown (attachment, FALSE);
+ e_attachment_set_initially_shown (attachment, FALSE);
e_attachment_set_can_show (attachment, FALSE);
att_part = e_attachment_ref_mime_part (attachment);
diff --git a/em-format/e-mail-parser.c b/em-format/e-mail-parser.c
index c78cb70..b5fe91e 100644
--- a/em-format/e-mail-parser.c
+++ b/em-format/e-mail-parser.c
@@ -53,7 +53,6 @@ enum {
/* internal parser extensions */
GType e_mail_parser_application_mbox_get_type (void);
-GType e_mail_parser_attachment_bar_get_type (void);
GType e_mail_parser_audio_get_type (void);
GType e_mail_parser_headers_get_type (void);
GType e_mail_parser_message_get_type (void);
@@ -221,7 +220,6 @@ e_mail_parser_base_init (EMailParserClass *class)
/* Register internal extensions. */
g_type_ensure (e_mail_parser_application_mbox_get_type ());
- g_type_ensure (e_mail_parser_attachment_bar_get_type ());
g_type_ensure (e_mail_parser_audio_get_type ());
g_type_ensure (e_mail_parser_headers_get_type ());
g_type_ensure (e_mail_parser_message_get_type ());
@@ -714,13 +712,13 @@ e_mail_parser_wrap_as_attachment (EMailParser *parser,
first_part = g_queue_peek_head (parts_queue);
if (first_part != NULL) {
const gchar *id = e_mail_part_get_id (first_part);
- empa->attachment_view_part_id = g_strdup (id);
+ empa->part_id_with_attachment = g_strdup (id);
first_part->is_hidden = TRUE;
}
attachment = e_mail_part_attachment_ref_attachment (empa);
- e_attachment_set_shown (attachment, empa->shown);
+ e_attachment_set_initially_shown (attachment, empa->shown);
e_attachment_set_can_show (
attachment,
extensions && !g_queue_is_empty (extensions));
diff --git a/em-format/e-mail-part-attachment.c b/em-format/e-mail-part-attachment.c
index e12e555..3490c3d 100644
--- a/em-format/e-mail-part-attachment.c
+++ b/em-format/e-mail-part-attachment.c
@@ -98,7 +98,7 @@ mail_part_attachment_finalize (GObject *object)
{
EMailPartAttachment *part = E_MAIL_PART_ATTACHMENT (object);
- g_free (part->attachment_view_part_id);
+ g_free (part->part_id_with_attachment);
/* Chain up to parent's finalize() method. */
G_OBJECT_CLASS (e_mail_part_attachment_parent_class)->
diff --git a/em-format/e-mail-part-attachment.h b/em-format/e-mail-part-attachment.h
index bdf859c..818ab30 100644
--- a/em-format/e-mail-part-attachment.h
+++ b/em-format/e-mail-part-attachment.h
@@ -52,7 +52,7 @@ struct _EMailPartAttachment {
EMailPart parent;
EMailPartAttachmentPrivate *priv;
- gchar *attachment_view_part_id;
+ gchar *part_id_with_attachment;
gboolean shown;
const gchar *snoop_mime_type;
diff --git a/em-format/e-mail-part-headers.c b/em-format/e-mail-part-headers.c
index 5c494cd..1cc4ebb 100644
--- a/em-format/e-mail-part-headers.c
+++ b/em-format/e-mail-part-headers.c
@@ -218,29 +218,21 @@ mail_part_headers_constructed (GObject *object)
static void
mail_part_headers_bind_dom_element (EMailPart *part,
- WebKitDOMElement *element)
+ GDBusProxy *web_extension,
+ guint64 page_id,
+ const gchar *element_id)
{
- WebKitDOMDocument *document;
- WebKitDOMElement *photo;
- gchar *addr, *uri;
-
- document = webkit_dom_node_get_owner_document (
- WEBKIT_DOM_NODE (element));
- photo = webkit_dom_document_get_element_by_id (
- document, "__evo-contact-photo");
-
- /* Contact photos disabled, the <img> tag is not there. */
- if (photo == NULL)
- return;
-
- addr = webkit_dom_element_get_attribute (photo, "data-mailaddr");
- uri = g_strdup_printf ("mail://contact-photo?mailaddr=%s", addr);
-
- webkit_dom_html_image_element_set_src (
- WEBKIT_DOM_HTML_IMAGE_ELEMENT (photo), uri);
-
- g_free (addr);
- g_free (uri);
+ if (web_extension) {
+ g_dbus_proxy_call (
+ web_extension,
+ "EMailPartHeadersBindDOMElement",
+ g_variant_new ("(ts)", page_id, element_id),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+ }
}
static void
diff --git a/em-format/e-mail-part-secure-button.c b/em-format/e-mail-part-secure-button.c
new file mode 100644
index 0000000..2455303
--- /dev/null
+++ b/em-format/e-mail-part-secure-button.c
@@ -0,0 +1,321 @@
+/*
+ * 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.
+ *
+ * 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 General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib/gi18n-lib.h>
+
+#include <e-util/e-util.h>
+
+#if defined (HAVE_NSS) && defined (ENABLE_SMIME)
+#include "certificate-manager.h"
+#include "e-cert-db.h"
+#endif
+
+#include "e-mail-part-secure-button.h"
+
+G_DEFINE_TYPE (EMailPartSecureButton, e_mail_part_secure_button, E_TYPE_MAIL_PART)
+
+const gchar *e_mail_formatter_secure_button_get_encrypt_description (CamelCipherValidityEncrypt status);
+const gchar *e_mail_formatter_secure_button_get_sign_description (CamelCipherValiditySign status);
+
+
+#if defined (HAVE_NSS) && defined (ENABLE_SMIME)
+static void
+viewcert_clicked (GtkWidget *button,
+ GtkWidget *grid)
+{
+ CamelCipherCertInfo *info = g_object_get_data ((GObject *) button, "e-cert-info");
+ ECert *ec = NULL;
+
+ if (info->cert_data)
+ ec = e_cert_new (CERT_DupCertificate (info->cert_data));
+
+ if (ec != NULL) {
+ GtkWidget *dialog, *parent;
+
+ parent = gtk_widget_get_toplevel (grid);
+ if (!parent || !GTK_IS_WINDOW (parent))
+ parent = NULL;
+
+ dialog = e_cert_manager_new_certificate_viewer ((GtkWindow *) parent, ec);
+
+ gtk_widget_show (dialog);
+ g_signal_connect (
+ dialog, "response",
+ G_CALLBACK (gtk_widget_destroy), NULL);
+
+ g_object_unref (ec);
+ } else {
+ g_warning (
+ "can't find certificate for %s <%s>",
+ info->name ? info->name : "",
+ info->email ? info->email : "");
+ }
+}
+#endif
+
+static void
+info_response (GtkWidget *widget,
+ guint button,
+ gpointer user_data)
+{
+ gtk_widget_destroy (widget);
+}
+
+static void
+add_cert_table (GtkWidget *grid,
+ GQueue *certlist,
+ gpointer user_data)
+{
+ GList *head, *link;
+ GtkTable *table;
+ gint n = 0;
+
+ table = (GtkTable *) gtk_table_new (certlist->length, 2, FALSE);
+
+ head = g_queue_peek_head_link (certlist);
+
+ for (link = head; link != NULL; link = g_list_next (link)) {
+ CamelCipherCertInfo *info = link->data;
+ gchar *la = NULL;
+ const gchar *l = NULL;
+
+ if (info->name) {
+ if (info->email && strcmp (info->name, info->email) != 0)
+ l = la = g_strdup_printf ("%s <%s>", info->name, info->email);
+ else
+ l = info->name;
+ } else {
+ if (info->email)
+ l = info->email;
+ }
+
+ if (l) {
+ GtkWidget *w;
+#if defined (HAVE_NSS) && defined (ENABLE_SMIME)
+ ECert *ec = NULL;
+#endif
+ w = gtk_label_new (l);
+ gtk_misc_set_alignment ((GtkMisc *) w, 0.0, 0.5);
+ g_free (la);
+ gtk_table_attach (table, w, 0, 1, n, n + 1, GTK_FILL, GTK_FILL, 3, 3);
+#if defined (HAVE_NSS) && defined (ENABLE_SMIME)
+ w = gtk_button_new_with_mnemonic (_("_View Certificate"));
+ gtk_table_attach (table, w, 1, 2, n, n + 1, 0, 0, 3, 3);
+ g_object_set_data ((GObject *) w, "e-cert-info", info);
+ g_signal_connect (
+ w, "clicked",
+ G_CALLBACK (viewcert_clicked), grid);
+
+ if (info->cert_data)
+ ec = e_cert_new (CERT_DupCertificate (info->cert_data));
+
+ if (ec == NULL)
+ gtk_widget_set_sensitive (w, FALSE);
+ else
+ g_object_unref (ec);
+#else
+ w = gtk_label_new (_("This certificate is not viewable"));
+ gtk_table_attach (table, w, 1, 2, n, n + 1, 0, 0, 3, 3);
+#endif
+ n++;
+ }
+ }
+
+ gtk_container_add (GTK_CONTAINER (grid), GTK_WIDGET (table));
+}
+
+static void
+secure_button_show_validity_dialog (EWebView *web_view,
+ CamelCipherValidity *validity)
+{
+ GtkBuilder *builder;
+ GtkWidget *grid, *w;
+ GtkWidget *dialog;
+
+ g_return_if_fail (validity != NULL);
+
+ /* Make sure our custom widget classes are registered with
+ * GType before we load the GtkBuilder definition file. */
+ g_type_ensure (E_TYPE_DATE_EDIT);
+
+ builder = gtk_builder_new ();
+ e_load_ui_builder_definition (builder, "mail-dialogs.ui");
+
+ dialog = e_builder_get_widget (builder, "message_security_dialog");
+
+ w = gtk_widget_get_toplevel (GTK_WIDGET (web_view));
+ if (GTK_IS_WINDOW (w))
+ gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (w));
+
+ grid = e_builder_get_widget (builder, "signature_grid");
+ w = gtk_label_new (e_mail_formatter_secure_button_get_sign_description (validity->sign.status));
+ gtk_misc_set_alignment ((GtkMisc *) w, 0.0, 0.5);
+ gtk_label_set_line_wrap ((GtkLabel *) w, TRUE);
+ gtk_container_add (GTK_CONTAINER (grid), w);
+ if (validity->sign.description) {
+ GtkTextBuffer *buffer;
+
+ buffer = gtk_text_buffer_new (NULL);
+ gtk_text_buffer_set_text (
+ buffer, validity->sign.description,
+ strlen (validity->sign.description));
+ w = g_object_new (
+ gtk_scrolled_window_get_type (),
+ "hscrollbar_policy", GTK_POLICY_AUTOMATIC,
+ "vscrollbar_policy", GTK_POLICY_AUTOMATIC,
+ "shadow_type", GTK_SHADOW_IN,
+ "expand", TRUE,
+ "child", g_object_new (gtk_text_view_get_type (),
+ "buffer", buffer,
+ "cursor_visible", FALSE,
+ "editable", FALSE,
+ NULL),
+ "width_request", 500,
+ "height_request", 80,
+ NULL);
+ g_object_unref (buffer);
+
+ gtk_container_add (GTK_CONTAINER (grid), w);
+ }
+
+ if (!g_queue_is_empty (&validity->sign.signers))
+ add_cert_table (grid, &validity->sign.signers, NULL);
+
+ gtk_widget_show_all (grid);
+
+ grid = e_builder_get_widget (builder, "encryption_grid");
+ w = gtk_label_new (e_mail_formatter_secure_button_get_encrypt_description (validity->encrypt.status));
+ gtk_misc_set_alignment ((GtkMisc *) w, 0.0, 0.5);
+ gtk_label_set_line_wrap ((GtkLabel *) w, TRUE);
+ gtk_container_add (GTK_CONTAINER (grid), w);
+ if (validity->encrypt.description) {
+ GtkTextBuffer *buffer;
+
+ buffer = gtk_text_buffer_new (NULL);
+ gtk_text_buffer_set_text (
+ buffer, validity->encrypt.description,
+ strlen (validity->encrypt.description));
+ w = g_object_new (
+ gtk_scrolled_window_get_type (),
+ "hscrollbar_policy", GTK_POLICY_AUTOMATIC,
+ "vscrollbar_policy", GTK_POLICY_AUTOMATIC,
+ "shadow_type", GTK_SHADOW_IN,
+ "expand", TRUE,
+ "child", g_object_new (gtk_text_view_get_type (),
+ "buffer", buffer,
+ "cursor_visible", FALSE,
+ "editable", FALSE,
+ NULL),
+ "width_request", 500,
+ "height_request", 80,
+ NULL);
+ g_object_unref (buffer);
+
+ gtk_container_add (GTK_CONTAINER (grid), w);
+ }
+
+ if (!g_queue_is_empty (&validity->encrypt.encrypters))
+ add_cert_table (grid, &validity->encrypt.encrypters, NULL);
+
+ gtk_widget_show_all (grid);
+
+ g_object_unref (builder);
+
+ g_signal_connect (
+ dialog, "response",
+ G_CALLBACK (info_response), NULL);
+
+ gtk_widget_show (dialog);
+}
+
+static void
+secure_button_clicked_cb (EWebView *web_view,
+ const gchar *element_class,
+ const gchar *element_value,
+ const GtkAllocation *element_position,
+ gpointer user_data)
+{
+ EMailPart *mail_part = user_data;
+ GList *head, *link;
+ gboolean can_use;
+ gchar *tmp;
+
+ g_return_if_fail (E_IS_MAIL_PART_SECURE_BUTTON (mail_part));
+
+ tmp = g_strdup_printf ("%p:", mail_part);
+ can_use = element_value && g_str_has_prefix (element_value, tmp);
+ if (can_use)
+ element_value += strlen (tmp);
+ g_free (tmp);
+
+ if (!can_use)
+ return;
+
+ head = g_queue_peek_head_link (&mail_part->validities);
+ for (link = head; link != NULL; link = g_list_next (link)) {
+ EMailPartValidityPair *pair = link->data;
+
+ if (!pair)
+ continue;
+
+ tmp = g_strdup_printf ("%p", pair->validity);
+ can_use = g_strcmp0 (element_value, tmp) == 0;
+ g_free (tmp);
+
+ if (can_use) {
+ secure_button_show_validity_dialog (web_view, pair->validity);
+ break;
+ }
+ }
+}
+
+static void
+mail_part_secure_button_web_view_loaded (EMailPart *mail_part,
+ EWebView *web_view)
+{
+ g_return_if_fail (E_IS_MAIL_PART_SECURE_BUTTON (mail_part));
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+ e_web_view_register_element_clicked (web_view, "secure-button", secure_button_clicked_cb, mail_part);
+}
+
+static void
+e_mail_part_secure_button_class_init (EMailPartSecureButtonClass *class)
+{
+ EMailPartClass *mail_part_class;
+
+ mail_part_class = E_MAIL_PART_CLASS (class);
+ mail_part_class->web_view_loaded = mail_part_secure_button_web_view_loaded;
+}
+
+static void
+e_mail_part_secure_button_init (EMailPartSecureButton *part)
+{
+}
+
+EMailPart *
+e_mail_part_secure_button_new (CamelMimePart *mime_part,
+ const gchar *id)
+{
+ g_return_val_if_fail (id != NULL, NULL);
+
+ return g_object_new (
+ E_TYPE_MAIL_PART_SECURE_BUTTON,
+ "id", id, "mime-part", mime_part, NULL);
+}
diff --git a/em-format/e-mail-part-secure-button.h b/em-format/e-mail-part-secure-button.h
new file mode 100644
index 0000000..b40a0d3
--- /dev/null
+++ b/em-format/e-mail-part-secure-button.h
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ *
+ * 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 General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef E_MAIL_PART_SECURE_BUTTON_H
+#define E_MAIL_PART_SECURE_BUTTON_H
+
+#include <em-format/e-mail-part.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MAIL_PART_SECURE_BUTTON \
+ (e_mail_part_secure_button_get_type ())
+#define E_MAIL_PART_SECURE_BUTTON(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_MAIL_PART_SECURE_BUTTON, EMailPartSecureButton))
+#define E_MAIL_PART_SECURE_BUTTON_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_MAIL_PART_SECURE_BUTTON, EMailPartSecureButtonClass))
+#define E_IS_MAIL_PART_SECURE_BUTTON(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_MAIL_PART_SECURE_BUTTON))
+#define E_IS_MAIL_PART_SECURE_BUTTON_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_MAIL_PART_SECURE_BUTTON))
+#define E_MAIL_PART_SECURE_BUTTON_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_MAIL_PART_SECURE_BUTTON, EMailPartSecureButtonClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EMailPartSecureButton EMailPartSecureButton;
+typedef struct _EMailPartSecureButtonClass EMailPartSecureButtonClass;
+typedef struct _EMailPartSecureButtonPrivate EMailPartSecureButtonPrivate;
+
+struct _EMailPartSecureButton {
+ EMailPart parent;
+ EMailPartSecureButtonPrivate *priv;
+};
+
+struct _EMailPartSecureButtonClass {
+ EMailPartClass parent_class;
+};
+
+GType e_mail_part_secure_button_get_type (void) G_GNUC_CONST;
+EMailPart * e_mail_part_secure_button_new (CamelMimePart *mime_part,
+ const gchar *id);
+
+G_END_DECLS
+
+#endif /* E_MAIL_PART_SECURE_BUTTON_H */
diff --git a/em-format/e-mail-part-utils.c b/em-format/e-mail-part-utils.c
index b0899ee..0568a35 100644
--- a/em-format/e-mail-part-utils.c
+++ b/em-format/e-mail-part-utils.c
@@ -488,6 +488,11 @@ e_mail_part_build_uri (CamelFolder *folder,
g_free (escaped);
break;
}
+ case G_TYPE_POINTER: {
+ gpointer val = va_arg (ap, gpointer);
+ tmp2 = g_strdup_printf ("%s%c%s=%p", tmp, separator, name, val);
+ break;
+ }
default:
g_warning ("Invalid param type %s", g_type_name (type));
va_end (ap);
diff --git a/em-format/e-mail-part.c b/em-format/e-mail-part.c
index 432481c..fbfb332 100644
--- a/em-format/e-mail-part.c
+++ b/em-format/e-mail-part.c
@@ -585,17 +585,36 @@ e_mail_part_set_is_attachment (EMailPart *part,
void
e_mail_part_bind_dom_element (EMailPart *part,
- WebKitDOMElement *element)
+ GDBusProxy *web_extension,
+ guint64 page_id,
+ const gchar *element_id)
{
EMailPartClass *class;
g_return_if_fail (E_IS_MAIL_PART (part));
- g_return_if_fail (WEBKIT_DOM_IS_ELEMENT (element));
+ g_return_if_fail (web_extension);
+ g_return_if_fail (page_id != 0);
+ g_return_if_fail (element_id && *element_id);
class = E_MAIL_PART_GET_CLASS (part);
if (class->bind_dom_element != NULL)
- class->bind_dom_element (part, element);
+ class->bind_dom_element (part, web_extension, page_id, element_id);
+}
+
+void
+e_mail_part_web_view_loaded (EMailPart *part,
+ EWebView *web_view)
+{
+ EMailPartClass *klass;
+
+ g_return_if_fail (E_IS_MAIL_PART (part));
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+ klass = E_MAIL_PART_GET_CLASS (part);
+
+ if (klass->web_view_loaded)
+ klass->web_view_loaded (part, web_view);
}
static EMailPartValidityPair *
diff --git a/em-format/e-mail-part.h b/em-format/e-mail-part.h
index cb46042..72e17ad 100644
--- a/em-format/e-mail-part.h
+++ b/em-format/e-mail-part.h
@@ -19,7 +19,6 @@
#define E_MAIL_PART_H
#include <camel/camel.h>
-#include <webkit/webkitdom.h>
#include <e-util/e-util.h>
@@ -87,7 +86,11 @@ struct _EMailPartClass {
GObjectClass parent_class;
void (*bind_dom_element) (EMailPart *part,
- WebKitDOMElement *element);
+ GDBusProxy *web_extension,
+ guint64 page_id,
+ const gchar *element_id);
+ void (*web_view_loaded) (EMailPart *part,
+ EWebView *web_view);
};
GType e_mail_part_get_type (void) G_GNUC_CONST;
@@ -121,7 +124,11 @@ gboolean e_mail_part_get_is_attachment (EMailPart *part);
void e_mail_part_set_is_attachment (EMailPart *part,
gboolean is_attachment);
void e_mail_part_bind_dom_element (EMailPart *part,
- WebKitDOMElement *element);
+ GDBusProxy *web_extension,
+ guint64 page_id,
+ const gchar *element_id);
+void e_mail_part_web_view_loaded (EMailPart *part,
+ EWebView *web_view);
void e_mail_part_update_validity (EMailPart *part,
CamelCipherValidity *validity,
EMailPartValidityFlags validity_type);
diff --git a/mail/Makefile.am b/mail/Makefile.am
index 06aa259..acf784f 100644
--- a/mail/Makefile.am
+++ b/mail/Makefile.am
@@ -52,6 +52,7 @@ libevolution_mail_la_CPPFLAGS = \
$(NULL)
mailinclude_HEADERS = \
+ e-cid-request.h \
e-http-request.h \
e-mail.h \
e-mail-account-manager.h \
@@ -135,6 +136,7 @@ mailinclude_HEADERS = \
message-list.h
libevolution_mail_la_SOURCES = \
+ e-cid-request.c \
e-http-request.c \
e-mail-account-manager.c \
e-mail-account-store.c \
diff --git a/mail/e-cid-request.c b/mail/e-cid-request.c
new file mode 100644
index 0000000..e7529f7
--- /dev/null
+++ b/mail/e-cid-request.c
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2016 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library 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.
+ *
+ * This library 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 this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#include "e-mail-display.h"
+#include "e-cid-request.h"
+
+struct _ECidRequestPrivate {
+ gint dummy;
+};
+
+static void e_cid_request_content_request_init (EContentRequestInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (ECidRequest, e_cid_request, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (E_TYPE_CONTENT_REQUEST, e_cid_request_content_request_init))
+
+static gboolean
+e_cid_request_can_process_uri (EContentRequest *request,
+ const gchar *uri)
+{
+ g_return_val_if_fail (E_IS_CID_REQUEST (request), FALSE);
+ g_return_val_if_fail (uri != NULL, FALSE);
+
+ return g_ascii_strncasecmp (uri, "cid:", 4) == 0;
+}
+
+static gboolean
+e_cid_request_process_sync (EContentRequest *request,
+ const gchar *uri,
+ GObject *requester,
+ GInputStream **out_stream,
+ gint64 *out_stream_length,
+ gchar **out_mime_type,
+ GCancellable *cancellable,
+ GError **error)
+{
+ EMailDisplay *display;
+ EMailPartList *part_list;
+ EMailPart *part;
+ GByteArray *byte_array;
+ CamelStream *output_stream;
+ CamelDataWrapper *dw;
+ CamelMimePart *mime_part;
+ gboolean success = FALSE;
+
+ g_return_val_if_fail (E_IS_CID_REQUEST (request), FALSE);
+ g_return_val_if_fail (uri != NULL, FALSE);
+
+ if (g_cancellable_set_error_if_cancelled (cancellable, error))
+ return FALSE;
+
+ if (!E_IS_MAIL_DISPLAY (requester))
+ return FALSE;
+
+ display = E_MAIL_DISPLAY (requester);
+
+ part_list = e_mail_display_get_part_list (display);
+ if (!part_list)
+ return FALSE;
+
+ part = e_mail_part_list_ref_part (part_list, uri);
+ if (!part)
+ return FALSE;
+
+ mime_part = e_mail_part_ref_mime_part (part);
+ dw = camel_medium_get_content (CAMEL_MEDIUM (mime_part));
+
+ g_return_val_if_fail (dw != NULL, FALSE);
+
+ byte_array = g_byte_array_new ();
+ output_stream = camel_stream_mem_new ();
+
+ /* We retain ownership of the byte array. */
+ camel_stream_mem_set_byte_array (CAMEL_STREAM_MEM (output_stream), byte_array);
+
+ if (camel_data_wrapper_decode_to_stream_sync (dw, output_stream, cancellable, error)) {
+ GBytes *bytes;
+ gchar *mime_type;
+
+ bytes = g_byte_array_free_to_bytes (byte_array);
+
+ success = TRUE;
+
+ *out_stream = g_memory_input_stream_new_from_bytes (bytes);
+ *out_stream_length = g_bytes_get_size (bytes);
+
+ mime_type = camel_data_wrapper_get_mime_type (dw);
+ if (mime_type && *mime_type)
+ *out_mime_type = mime_type;
+ else {
+ g_free (mime_type);
+ *out_mime_type = g_strdup (e_mail_part_get_mime_type (part));
+ }
+
+ g_bytes_unref (bytes);
+ }
+
+ g_object_unref (mime_part);
+ g_object_unref (part);
+
+ return success;
+}
+
+static void
+e_cid_request_content_request_init (EContentRequestInterface *iface)
+{
+ iface->can_process_uri = e_cid_request_can_process_uri;
+ iface->process_sync = e_cid_request_process_sync;
+}
+
+static void
+e_cid_request_class_init (ECidRequestClass *class)
+{
+ g_type_class_add_private (class, sizeof (ECidRequestPrivate));
+}
+
+static void
+e_cid_request_init (ECidRequest *request)
+{
+ request->priv = G_TYPE_INSTANCE_GET_PRIVATE (request, E_TYPE_CID_REQUEST, ECidRequestPrivate);
+}
+
+EContentRequest *
+e_cid_request_new (void)
+{
+ return g_object_new (E_TYPE_CID_REQUEST, NULL);
+}
diff --git a/mail/e-cid-request.h b/mail/e-cid-request.h
new file mode 100644
index 0000000..0ed6e4b
--- /dev/null
+++ b/mail/e-cid-request.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2016 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library 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.
+ *
+ * This library 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 this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef E_CID_REQUEST_H
+#define E_CID_REQUEST_H
+
+#include <e-util/e-util.h>
+
+/* Standard GObject macros */
+#define E_TYPE_CID_REQUEST \
+ (e_cid_request_get_type ())
+#define E_CID_REQUEST(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_CID_REQUEST, ECidRequest))
+#define E_CID_REQUEST_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_CID_REQUEST, ECidRequestClass))
+#define E_IS_CID_REQUEST(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_CID_REQUEST))
+#define E_IS_CID_REQUEST_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_CID_REQUEST))
+#define E_CID_REQUEST_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_CID_REQUEST, ECidRequestClass))
+
+G_BEGIN_DECLS
+
+typedef struct _ECidRequest ECidRequest;
+typedef struct _ECidRequestClass ECidRequestClass;
+typedef struct _ECidRequestPrivate ECidRequestPrivate;
+
+struct _ECidRequest {
+ GObject parent;
+ ECidRequestPrivate *priv;
+};
+
+struct _ECidRequestClass {
+ GObjectClass parent;
+};
+
+GType e_cid_request_get_type (void) G_GNUC_CONST;
+EContentRequest *
+ e_cid_request_new (void);
+
+G_END_DECLS
+
+#endif /* E_CID_REQUEST_H */
diff --git a/mail/e-http-request.c b/mail/e-http-request.c
index 488732a..9e7711b 100644
--- a/mail/e-http-request.c
+++ b/mail/e-http-request.c
@@ -15,9 +15,10 @@
*
*/
-#include "e-http-request.h"
-
+#ifdef HAVE_CONFIG_H
#include <config.h>
+#endif
+
#include <string.h>
#define LIBSOUP_USE_UNSTABLE_REQUEST_API
@@ -25,7 +26,7 @@
#include <libsoup/soup-requester.h>
#include <libsoup/soup-request-http.h>
#include <camel/camel.h>
-#include <webkit/webkit.h>
+#include <webkit2/webkit2.h>
#include <e-util/e-util.h>
#include <libemail-engine/libemail-engine.h>
@@ -35,19 +36,31 @@
#include <shell/e-shell.h>
#include "e-mail-ui-session.h"
+#include "e-http-request.h"
#define d(x)
-#define E_HTTP_REQUEST_GET_PRIVATE(obj) \
- (G_TYPE_INSTANCE_GET_PRIVATE \
- ((obj), E_TYPE_HTTP_REQUEST, EHTTPRequestPrivate))
-
struct _EHTTPRequestPrivate {
- gchar *content_type;
- gint content_length;
+ gint dummy;
};
-G_DEFINE_TYPE (EHTTPRequest, e_http_request, SOUP_TYPE_REQUEST)
+static void e_http_request_content_request_init (EContentRequestInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (EHTTPRequest, e_http_request, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (E_TYPE_CONTENT_REQUEST, e_http_request_content_request_init))
+
+static gboolean
+e_http_request_can_process_uri (EContentRequest *request,
+ const gchar *uri)
+{
+ g_return_val_if_fail (E_IS_HTTP_REQUEST (request), FALSE);
+ g_return_val_if_fail (uri != NULL, FALSE);
+
+ return g_ascii_strncasecmp (uri, "evo-http:", 9) == 0 ||
+ g_ascii_strncasecmp (uri, "evo-https:", 10) == 0 ||
+ g_ascii_strncasecmp (uri, "http:", 5) == 0 ||
+ g_ascii_strncasecmp (uri, "https:", 6) == 0;
+}
static gssize
copy_stream_to_stream (GIOStream *file_io_stream,
@@ -162,16 +175,18 @@ http_request_cancelled_cb (GCancellable *cancellable,
soup_session_abort (session);
}
-static void
-handle_http_request (GSimpleAsyncResult *res,
- GObject *source_object,
- GCancellable *cancellable)
+static gboolean
+e_http_request_process_sync (EContentRequest *request,
+ const gchar *uri,
+ GObject *requester,
+ GInputStream **out_stream,
+ gint64 *out_stream_length,
+ gchar **out_mime_type,
+ GCancellable *cancellable,
+ GError **error)
{
- EHTTPRequestPrivate *priv;
SoupURI *soup_uri;
- SoupRequest *soup_request;
- SoupSession *soup_session;
- gchar *evo_uri, *uri;
+ gchar *evo_uri, *use_uri;
gchar *mail_uri = NULL;
GInputStream *stream;
gboolean force_load_images = FALSE;
@@ -183,15 +198,16 @@ handle_http_request (GSimpleAsyncResult *res,
CamelDataCache *cache;
GIOStream *cache_stream;
gint uri_len;
+ gboolean success = FALSE;
- if (g_cancellable_is_cancelled (cancellable))
- return;
+ g_return_val_if_fail (E_IS_HTTP_REQUEST (request), FALSE);
+ g_return_val_if_fail (uri != NULL, FALSE);
- priv = E_HTTP_REQUEST_GET_PRIVATE (source_object);
+ if (g_cancellable_set_error_if_cancelled (cancellable, error))
+ return FALSE;
- soup_request = SOUP_REQUEST (source_object);
- soup_session = soup_request_get_session (soup_request);
- soup_uri = soup_request_get_uri (soup_request);
+ soup_uri = soup_uri_new (uri);
+ g_return_val_if_fail (soup_uri != NULL, FALSE);
/* Remove the __evo-mail query */
soup_query = soup_uri_get_query (soup_uri);
@@ -224,24 +240,31 @@ handle_http_request (GSimpleAsyncResult *res,
/* Remove the "evo-" prefix from scheme */
uri_len = (evo_uri != NULL) ? strlen (evo_uri) : 0;
- uri = NULL;
+ use_uri = NULL;
if (evo_uri != NULL && (uri_len > 5)) {
+ gint inc = 0;
+
+ if (g_str_has_prefix (evo_uri, "evo-"))
+ inc = 4;
/* Remove trailing "?" if there is no URI query */
if (evo_uri[uri_len - 1] == '?') {
- uri = g_strndup (evo_uri + 4, uri_len - 5);
+ use_uri = g_strndup (evo_uri + inc, uri_len - 1 - inc);
} else {
- uri = g_strdup (evo_uri + 4);
+ use_uri = g_strdup (evo_uri + inc);
}
- g_free (evo_uri);
}
- g_return_if_fail (uri && *uri);
+ g_free (evo_uri);
+
+ g_return_val_if_fail (use_uri && *use_uri, FALSE);
+
+ *out_stream_length = -1;
/* Use MD5 hash of the URI as a filname of the resourec cache file.
* We were previously using the URI as a filename but the URI is
* sometimes too long for a filename. */
- uri_md5 = g_compute_checksum_for_string (G_CHECKSUM_MD5, uri, -1);
+ uri_md5 = g_compute_checksum_for_string (G_CHECKSUM_MD5, use_uri, -1);
/* Open Evolution's cache */
user_cache_dir = e_get_user_cache_dir ();
@@ -251,27 +274,23 @@ handle_http_request (GSimpleAsyncResult *res,
camel_data_cache_set_expire_access (cache, 2 * 60 * 60);
cache_stream = camel_data_cache_get (cache, "http", uri_md5, NULL);
- } else {
+ } else
cache_stream = NULL;
- }
- /* Found item in cache! */
if (cache_stream != NULL) {
gssize len;
stream = g_memory_input_stream_new ();
- len = copy_stream_to_stream (
- cache_stream,
- G_MEMORY_INPUT_STREAM (stream), cancellable);
- priv->content_length = len;
+ len = copy_stream_to_stream (cache_stream, G_MEMORY_INPUT_STREAM (stream), cancellable);
+ *out_stream_length = len;
g_object_unref (cache_stream);
/* When succesfully read some data from cache then
* get mimetype and return the stream to WebKit.
* Otherwise try to fetch the resource again from the network. */
- if ((len != -1) && (priv->content_length > 0)) {
+ if (len != -1 && *out_stream_length > 0) {
GFile *file;
GFileInfo *info;
gchar *path;
@@ -284,13 +303,12 @@ handle_http_request (GSimpleAsyncResult *res,
0, cancellable, NULL);
if (info) {
- priv->content_type = g_strdup (
- g_file_info_get_content_type (info));
+ *out_mime_type = g_strdup (g_file_info_get_content_type (info));
d (
printf ("'%s' found in cache (%d bytes, %s)\n",
- uri, priv->content_length,
- priv->content_type));
+ use_uri, (gint) *out_stream_length,
+ *out_mime_type));
}
g_clear_object (&info);
@@ -298,12 +316,12 @@ handle_http_request (GSimpleAsyncResult *res,
g_free (path);
/* Set result and quit the thread */
- g_simple_async_result_set_op_res_gpointer (
- res, stream, g_object_unref);
+ *out_stream = stream;
+ success = TRUE;
goto cleanup;
} else {
- d (printf ("Failed to load '%s' from cache.\n", uri));
+ d (printf ("Failed to load '%s' from cache.\n", use_uri));
g_object_unref (stream);
}
}
@@ -337,7 +355,6 @@ handle_http_request (GSimpleAsyncResult *res,
CamelInternetAddress *addr;
CamelMimeMessage *message;
gboolean known_address = FALSE;
- GError *error = NULL;
shell_backend =
e_shell_get_backend_by_name (shell, "mail");
@@ -347,14 +364,13 @@ handle_http_request (GSimpleAsyncResult *res,
message = e_mail_part_list_get_message (part_list);
addr = camel_mime_message_get_from (message);
- e_mail_ui_session_check_known_address_sync (
+ if (!e_mail_ui_session_check_known_address_sync (
E_MAIL_UI_SESSION (session),
addr, FALSE, cancellable,
- &known_address, &error);
-
- if (error != NULL) {
- g_warning ("%s: %s", G_STRFUNC, error->message);
- g_error_free (error);
+ &known_address, error)) {
+ g_object_unref (part_list);
+ g_free (decoded_uri);
+ goto cleanup;
}
if (known_address)
@@ -368,20 +384,19 @@ handle_http_request (GSimpleAsyncResult *res,
if ((image_policy == E_IMAGE_LOADING_POLICY_ALWAYS) ||
force_load_images) {
-
+ ESource *proxy_source;
SoupSession *temp_session;
SoupMessage *message;
GIOStream *cache_stream;
- GError *error;
GMainContext *context;
gulong cancelled_id = 0;
- if (g_cancellable_is_cancelled (cancellable))
+ if (g_cancellable_set_error_if_cancelled (cancellable, error))
goto cleanup;
- message = soup_message_new (SOUP_METHOD_GET, uri);
+ message = soup_message_new (SOUP_METHOD_GET, use_uri);
if (!message) {
- g_debug ("%s: Skipping invalid URI '%s'", G_STRFUNC, uri);
+ g_debug ("%s: Skipping invalid URI '%s'", G_STRFUNC, use_uri);
goto cleanup;
}
@@ -391,10 +406,15 @@ handle_http_request (GSimpleAsyncResult *res,
temp_session = soup_session_new_with_options (
SOUP_SESSION_TIMEOUT, 90, NULL);
- e_binding_bind_property (
- soup_session, "proxy-resolver",
- temp_session, "proxy-resolver",
- G_BINDING_SYNC_CREATE);
+ proxy_source = e_source_registry_ref_builtin_proxy (e_shell_get_registry (shell));
+
+ g_object_set (
+ temp_session,
+ SOUP_SESSION_PROXY_RESOLVER,
+ G_PROXY_RESOLVER (proxy_source),
+ NULL);
+
+ g_object_unref (proxy_source);
soup_message_headers_append (
message->request_headers,
@@ -409,65 +429,68 @@ handle_http_request (GSimpleAsyncResult *res,
g_cancellable_disconnect (cancellable, cancelled_id);
if (!SOUP_STATUS_IS_SUCCESSFUL (message->status_code)) {
- g_debug ("Failed to request %s (code %d)", uri, message->status_code);
+ g_debug ("Failed to request %s (code %d)", use_uri, message->status_code);
g_object_unref (message);
g_object_unref (temp_session);
g_main_context_unref (context);
goto cleanup;
}
- /* Write the response body to cache */
- error = NULL;
if (cache) {
+ GError *local_error = NULL;
+
cache_stream = camel_data_cache_add (
- cache, "http", uri_md5, &error);
- if (error != NULL) {
+ cache, "http", uri_md5, &local_error);
+ if (local_error) {
g_warning (
"Failed to create cache file for '%s': %s",
- uri, error->message);
- g_clear_error (&error);
+ uri, local_error->message);
+ g_clear_error (&local_error);
} else {
GOutputStream *output_stream;
output_stream =
g_io_stream_get_output_stream (cache_stream);
- g_output_stream_write_all (
+ success = g_output_stream_write_all (
output_stream,
message->response_body->data,
message->response_body->length,
- NULL, cancellable, &error);
+ NULL, cancellable, &local_error);
g_io_stream_close (cache_stream, NULL, NULL);
g_object_unref (cache_stream);
- if (error != NULL) {
- if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ if (local_error != NULL) {
+ if (!g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
g_warning (
"Failed to write data to cache stream: %s",
- error->message);
- g_clear_error (&error);
+ local_error->message);
+ g_clear_error (&local_error);
g_object_unref (message);
g_object_unref (temp_session);
g_main_context_unref (context);
goto cleanup;
}
+
+ if (success) {
+ /* Send the response body to WebKit */
+ stream = g_memory_input_stream_new_from_data (
+ g_memdup (
+ message->response_body->data,
+ message->response_body->length),
+ message->response_body->length,
+ (GDestroyNotify) g_free);
+
+ *out_stream = stream;
+ *out_stream_length = message->response_body->length;
+ *out_mime_type = g_strdup (
+ soup_message_headers_get_content_type (
+ message->response_headers, NULL));
+ }
}
}
- /* Send the response body to WebKit */
- stream = g_memory_input_stream_new_from_data (
- g_memdup (
- message->response_body->data,
- message->response_body->length),
- message->response_body->length,
- (GDestroyNotify) g_free);
-
- priv->content_length = message->response_body->length;
- priv->content_type = g_strdup (
- soup_message_headers_get_content_type (
- message->response_headers, NULL));
-
g_object_unref (message);
g_object_unref (temp_session);
g_main_context_unref (context);
@@ -476,150 +499,42 @@ handle_http_request (GSimpleAsyncResult *res,
"Content-Type: %s\n"
"Content-Length: %d bytes\n"
"URI MD5: %s:\n",
- uri, priv->content_type,
- priv->content_length, uri_md5));
-
- g_simple_async_result_set_op_res_gpointer (res, stream, g_object_unref);
-
- goto cleanup;
+ use_uri, *out_mime_type ? *out_mime_type : "[null]",
+ (gint) *out_stream_length, uri_md5));
}
-cleanup:
+ cleanup:
g_clear_object (&cache);
- g_free (uri);
+ g_free (use_uri);
g_free (uri_md5);
g_free (mail_uri);
-}
-
-static void
-http_request_finalize (GObject *object)
-{
- EHTTPRequest *request = E_HTTP_REQUEST (object);
-
- if (request->priv->content_type) {
- g_free (request->priv->content_type);
- request->priv->content_type = NULL;
- }
-
- G_OBJECT_CLASS (e_http_request_parent_class)->finalize (object);
-}
+ soup_uri_free (soup_uri);
-static gboolean
-http_request_check_uri (SoupRequest *request,
- SoupURI *uri,
- GError **error)
-{
- return ((strcmp (uri->scheme, "evo-http") == 0) ||
- (strcmp (uri->scheme, "evo-https") == 0));
+ return success;
}
static void
-http_request_send_async (SoupRequest *request,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- GSimpleAsyncResult *simple;
-
- d ({
- const gchar *soup_query;
- SoupURI *uri;
-
- uri = soup_request_get_uri (request);
- soup_query = soup_uri_get_query (uri);
-
- if (soup_query) {
- gchar *uri_str;
- GHashTable *query;
-
- query = soup_form_decode (soup_uri_get_query (uri));
- uri_str = soup_uri_to_string (uri, FALSE);
- printf ("received request for %s\n", uri_str);
- g_free (uri_str);
- g_hash_table_destroy (query);
- }
- });
-
- simple = g_simple_async_result_new (
- G_OBJECT (request), callback,
- user_data, http_request_send_async);
-
- g_simple_async_result_set_check_cancellable (simple, cancellable);
-
- e_util_run_simple_async_result_in_thread (
- simple, handle_http_request,
- cancellable);
-
- g_object_unref (simple);
-}
-
-static GInputStream *
-http_request_send_finish (SoupRequest *request,
- GAsyncResult *result,
- GError **error)
-{
- GInputStream *stream;
-
- stream = g_simple_async_result_get_op_res_gpointer (
- G_SIMPLE_ASYNC_RESULT (result));
-
- /* Reset the stream before passing it back to webkit */
- if (stream && G_IS_SEEKABLE (stream))
- g_seekable_seek (G_SEEKABLE (stream), 0, G_SEEK_SET, NULL, NULL);
-
- if (!stream) /* We must always return something */
- stream = g_memory_input_stream_new ();
- else
- g_object_ref (stream);
-
- return stream;
-}
-
-static goffset
-http_request_get_content_length (SoupRequest *request)
-{
- EHTTPRequest *efr = E_HTTP_REQUEST (request);
-
- d (printf ("Content-Length: %d bytes\n", efr->priv->content_length));
- return efr->priv->content_length;
-}
-
-static const gchar *
-http_request_get_content_type (SoupRequest *request)
+e_http_request_content_request_init (EContentRequestInterface *iface)
{
- EHTTPRequest *efr = E_HTTP_REQUEST (request);
-
- d (printf ("Content-Type: %s\n", efr->priv->content_type));
-
- return efr->priv->content_type;
+ iface->can_process_uri = e_http_request_can_process_uri;
+ iface->process_sync = e_http_request_process_sync;
}
-static const gchar *data_schemes[] = { "evo-http", "evo-https", NULL };
-
static void
e_http_request_class_init (EHTTPRequestClass *class)
{
- GObjectClass *object_class;
- SoupRequestClass *request_class;
-
g_type_class_add_private (class, sizeof (EHTTPRequestPrivate));
-
- object_class = G_OBJECT_CLASS (class);
- object_class->finalize = http_request_finalize;
-
- request_class = SOUP_REQUEST_CLASS (class);
- request_class->schemes = data_schemes;
- request_class->send_async = http_request_send_async;
- request_class->send_finish = http_request_send_finish;
- request_class->get_content_type = http_request_get_content_type;
- request_class->get_content_length = http_request_get_content_length;
- request_class->check_uri = http_request_check_uri;
}
static void
e_http_request_init (EHTTPRequest *request)
{
- request->priv = E_HTTP_REQUEST_GET_PRIVATE (request);
+ request->priv = G_TYPE_INSTANCE_GET_PRIVATE (request, E_TYPE_HTTP_REQUEST, EHTTPRequestPrivate);
}
+EContentRequest *
+e_http_request_new (void)
+{
+ return g_object_new (E_TYPE_HTTP_REQUEST, NULL);
+}
diff --git a/mail/e-http-request.h b/mail/e-http-request.h
index de4cb23..bdbf009 100644
--- a/mail/e-http-request.h
+++ b/mail/e-http-request.h
@@ -18,10 +18,7 @@
#ifndef E_HTTP_REQUEST_H
#define E_HTTP_REQUEST_H
-#define LIBSOUP_USE_UNSTABLE_REQUEST_API
-
-#include <libsoup/soup.h>
-#include <libsoup/soup-request.h>
+#include <e-util/e-util.h>
/* Standard GObject macros */
#define E_TYPE_HTTP_REQUEST \
@@ -49,15 +46,18 @@ typedef struct _EHTTPRequestClass EHTTPRequestClass;
typedef struct _EHTTPRequestPrivate EHTTPRequestPrivate;
struct _EHTTPRequest {
- SoupRequest parent;
+ GObject parent;
EHTTPRequestPrivate *priv;
};
struct _EHTTPRequestClass {
- SoupRequestClass parent;
+ GObjectClass parent;
};
GType e_http_request_get_type (void) G_GNUC_CONST;
+EContentRequest *
+ e_http_request_new (void);
+
G_END_DECLS
diff --git a/mail/e-mail-browser.c b/mail/e-mail-browser.c
index 1130c9c..9293803 100644
--- a/mail/e-mail-browser.c
+++ b/mail/e-mail-browser.c
@@ -607,6 +607,7 @@ mail_browser_constructed (GObject *object)
EShellBackend *shell_backend;
EShell *shell;
EFocusTracker *focus_tracker;
+ EAttachmentStore *attachment_store;
GtkAccelGroup *accel_group;
GtkActionGroup *action_group;
GtkAction *action;
@@ -755,6 +756,18 @@ mail_browser_constructed (GObject *object)
browser->priv->preview_pane,
TRUE, TRUE, 0);
+ attachment_store = e_mail_display_get_attachment_store (E_MAIL_DISPLAY (display));
+ widget = GTK_WIDGET (e_mail_display_get_attachment_view (E_MAIL_DISPLAY (display)));
+ gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
+ gtk_widget_show (widget);
+
+ e_binding_bind_property_full (
+ attachment_store, "num-attachments",
+ widget, "visible",
+ G_BINDING_SYNC_CREATE,
+ e_attachment_store_transform_num_attachments_to_visible_boolean,
+ NULL, NULL, NULL);
+
id = "org.gnome.evolution.mail.browser";
e_plugin_ui_register_manager (ui_manager, id, object);
e_plugin_ui_enable_manager (ui_manager, id);
@@ -766,47 +779,9 @@ static gboolean
mail_browser_key_press_event (GtkWidget *widget,
GdkEventKey *event)
{
- EMailDisplay *mail_display;
-
- g_return_val_if_fail (E_IS_MAIL_BROWSER (widget), FALSE);
-
- mail_display = e_mail_reader_get_mail_display (E_MAIL_READER (widget));
-
- switch (event->keyval) {
- case GDK_KEY_Escape:
- e_mail_browser_close (E_MAIL_BROWSER (widget));
- return TRUE;
-
- case GDK_KEY_Home:
- case GDK_KEY_Left:
- case GDK_KEY_Up:
- case GDK_KEY_Right:
- case GDK_KEY_Down:
- case GDK_KEY_Next:
- case GDK_KEY_End:
- case GDK_KEY_Begin:
- /* If Caret mode is enabled don't try to process these keys */
- if (e_web_view_get_caret_mode (E_WEB_VIEW (mail_display)))
- break;
- case GDK_KEY_Prior:
- if (!e_mail_display_needs_key (mail_display, FALSE) &&
- webkit_web_view_get_main_frame (WEBKIT_WEB_VIEW (mail_display)) !=
- webkit_web_view_get_focused_frame (WEBKIT_WEB_VIEW (mail_display))) {
- WebKitDOMDocument *document;
- WebKitDOMDOMWindow *window;
-
- document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (mail_display));
- window = webkit_dom_document_get_default_view (document);
-
- /* Workaround WebKit bug for key navigation, when inner IFRAME is focused.
- * EMailView's inner IFRAMEs have disabled scrolling, but WebKit doesn't post
- * key navigation events to parent's frame, thus the view doesn't scroll.
- * This is a poor workaround for this issue, the main frame is focused,
- * which has scrolling enabled.
- */
- webkit_dom_dom_window_focus (window);
- }
- break;
+ if (event->keyval == GDK_KEY_Escape) {
+ e_mail_browser_close (E_MAIL_BROWSER (widget));
+ return TRUE;
}
/* Chain up to parent's key_press_event() method. */
diff --git a/mail/e-mail-config-identity-page.c b/mail/e-mail-config-identity-page.c
index 8b1a8fe..5baa5f5 100644
--- a/mail/e-mail-config-identity-page.c
+++ b/mail/e-mail-config-identity-page.c
@@ -80,17 +80,35 @@ mail_config_identity_page_is_email (const gchar *email_address)
}
static void
+mail_config_identity_page_signature_editor_created_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GtkWidget *editor;
+ GError *error = NULL;
+
+ g_return_if_fail (result != NULL);
+
+ editor = e_mail_signature_editor_new_finish (result, &error);
+ if (error) {
+ g_warning ("%s: Failed to create signature editor: %s", G_STRFUNC, error->message);
+ g_clear_error (&error);
+ } else {
+ gtk_window_set_position (GTK_WINDOW (editor), GTK_WIN_POS_CENTER);
+ gtk_widget_show (editor);
+ }
+}
+
+static void
mail_config_identity_page_add_signature_cb (GtkButton *button,
EMailConfigIdentityPage *page)
{
ESourceRegistry *registry;
- GtkWidget *editor;
registry = e_mail_config_identity_page_get_registry (page);
- editor = e_mail_signature_editor_new (registry, NULL);
- gtk_window_set_position (GTK_WINDOW (editor), GTK_WIN_POS_CENTER);
- gtk_widget_show (editor);
+ e_mail_signature_editor_new (registry, NULL,
+ mail_config_identity_page_signature_editor_created_cb, NULL);
}
static void
diff --git a/mail/e-mail-display-popup-extension.c b/mail/e-mail-display-popup-extension.c
index e95dc3e..2f9e919 100644
--- a/mail/e-mail-display-popup-extension.c
+++ b/mail/e-mail-display-popup-extension.c
@@ -33,14 +33,14 @@ e_mail_display_popup_extension_default_init (EMailDisplayPopupExtensionInterface
* e_mail_display_popup_extension_update_actions:
*
* @extension: An object derived from #EMailDisplayPopupExtension
- * @context: A #WebKitHitTestResult describing context of the popup menu
+ * @popup_document_uri: Document URI on top of which the popup menu had been invoked
*
* When #EMailDisplay is about to display a popup menu, it calls this function
* on every extension so that they can add their items to the menu.
*/
void
e_mail_display_popup_extension_update_actions (EMailDisplayPopupExtension *extension,
- WebKitHitTestResult *context)
+ const gchar *popup_document_uri)
{
EMailDisplayPopupExtensionInterface *iface;
@@ -49,5 +49,5 @@ e_mail_display_popup_extension_update_actions (EMailDisplayPopupExtension *exten
iface = E_MAIL_DISPLAY_POPUP_EXTENSION_GET_INTERFACE (extension);
g_return_if_fail (iface->update_actions != NULL);
- iface->update_actions (extension, context);
+ iface->update_actions (extension, popup_document_uri);
}
diff --git a/mail/e-mail-display-popup-extension.h b/mail/e-mail-display-popup-extension.h
index 67c1374..bedd23e 100644
--- a/mail/e-mail-display-popup-extension.h
+++ b/mail/e-mail-display-popup-extension.h
@@ -19,7 +19,6 @@
#define E_MAIL_DISPLAY_POPUP_EXTENSION_H
#include <glib-object.h>
-#include <webkit/webkit.h>
/* Standard GObject macros */
#define E_TYPE_MAIL_DISPLAY_POPUP_EXTENSION \
@@ -49,14 +48,14 @@ struct _EMailDisplayPopupExtensionInterface {
GTypeInterface parent_interface;
void (*update_actions) (EMailDisplayPopupExtension *extension,
- WebKitHitTestResult *context);
+ const gchar *popup_document_uri);
};
GType e_mail_display_popup_extension_get_type (void);
void e_mail_display_popup_extension_update_actions
(EMailDisplayPopupExtension *extension,
- WebKitHitTestResult *context);
+ const gchar *popup_document_uri);
G_END_DECLS
diff --git a/mail/e-mail-display.c b/mail/e-mail-display.c
index 1e475ca..eed7d74 100644
--- a/mail/e-mail-display.c
+++ b/mail/e-mail-display.c
@@ -34,20 +34,36 @@
#include <em-format/e-mail-part-attachment.h>
#include <em-format/e-mail-part-utils.h>
+#include "e-cid-request.h"
#include "e-http-request.h"
#include "e-mail-display-popup-extension.h"
#include "e-mail-notes.h"
#include "e-mail-request.h"
+#include "e-mail-ui-session.h"
#include "em-composer-utils.h"
#include "em-utils.h"
+#include <web-extensions/e-web-extension-names.h>
+
#define d(x)
#define E_MAIL_DISPLAY_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE \
((obj), E_TYPE_MAIL_DISPLAY, EMailDisplayPrivate))
+typedef enum {
+ E_ATTACHMENT_FLAG_VISIBLE = (1 << 0),
+ E_ATTACHMENT_FLAG_ZOOMED_TO_100 = (1 << 1)
+} EAttachmentFlags;
+
struct _EMailDisplayPrivate {
+ EAttachmentStore *attachment_store;
+ EAttachmentView *attachment_view;
+ GHashTable *attachment_flags; /* EAttachment * ~> guint bit-or of EAttachmentFlags */
+ guint attachment_inline_ui_id;
+
+ GtkActionGroup *attachment_inline_group;
+
EMailPartList *part_list;
EMailFormatterMode mode;
EMailFormatter *formatter;
@@ -58,8 +74,6 @@ struct _EMailDisplayPrivate {
GSettings *settings;
- GHashTable *widgets;
-
guint scheduled_reload;
GHashTable *old_settings;
@@ -67,10 +81,16 @@ struct _EMailDisplayPrivate {
GMutex remote_content_lock;
EMailRemoteContent *remote_content;
GHashTable *skipped_remote_content_sites;
+
+ guint web_extension_headers_collapsed_signal_id;
+
+ GtkAllocation attachment_popup_position;
};
enum {
PROP_0,
+ PROP_ATTACHMENT_STORE,
+ PROP_ATTACHMENT_VIEW,
PROP_FORMATTER,
PROP_HEADERS_COLLAPSABLE,
PROP_HEADERS_COLLAPSED,
@@ -142,6 +162,21 @@ G_DEFINE_TYPE (
e_mail_display,
E_TYPE_WEB_VIEW);
+static const gchar *attachment_popup_ui =
+"<ui>"
+" <popup name='context'>"
+" <placeholder name='inline-actions'>"
+" <menuitem action='zoom-to-100'/>"
+" <menuitem action='zoom-to-window'/>"
+" <menuitem action='show'/>"
+" <menuitem action='show-all'/>"
+" <separator/>"
+" <menuitem action='hide'/>"
+" <menuitem action='hide-all'/>"
+" </placeholder>"
+" </popup>"
+"</ui>";
+
static void
e_mail_display_claim_skipped_uri (EMailDisplay *mail_display,
const gchar *uri)
@@ -259,37 +294,6 @@ formatter_image_loading_policy_changed_cb (GObject *object,
e_mail_display_reload (display);
}
-static gboolean
-mail_display_image_exists_in_cache (const gchar *image_uri)
-{
- gchar *filename;
- gchar *hash;
- gboolean exists = FALSE;
-
- if (!emd_global_http_cache)
- return FALSE;
-
- hash = g_compute_checksum_for_string (G_CHECKSUM_MD5, image_uri, -1);
- filename = camel_data_cache_get_filename (
- emd_global_http_cache, "http", hash);
-
- if (filename != NULL) {
- struct stat st;
-
- exists = g_file_test (filename, G_FILE_TEST_EXISTS);
- if (exists && g_stat (filename, &st) == 0) {
- exists = st.st_size != 0;
- } else {
- exists = FALSE;
- }
- g_free (filename);
- }
-
- g_free (hash);
-
- return exists;
-}
-
static void
mail_display_update_formatter_colors (EMailDisplay *display)
{
@@ -303,29 +307,6 @@ mail_display_update_formatter_colors (EMailDisplay *display)
e_mail_formatter_update_style (formatter, state_flags);
}
-static void
-mail_display_plugin_widget_disconnect_children (GtkWidget *widget,
- gpointer mail_display)
-{
- g_signal_handlers_disconnect_by_data (widget, mail_display);
-}
-
-static void
-mail_display_plugin_widget_disconnect (gpointer widget_uri,
- gpointer widget,
- gpointer mail_display)
-{
- if (E_IS_ATTACHMENT_BAR (widget))
- g_signal_handlers_disconnect_by_data (widget, mail_display);
- else if (E_IS_ATTACHMENT_BUTTON (widget))
- g_signal_handlers_disconnect_by_data (widget, mail_display);
- else if (GTK_IS_CONTAINER (widget))
- gtk_container_foreach (
- widget,
- mail_display_plugin_widget_disconnect_children,
- mail_display);
-}
-
static gboolean
mail_display_process_mailto (EWebView *web_view,
const gchar *mailto_uri,
@@ -355,14 +336,28 @@ mail_display_process_mailto (EWebView *web_view,
}
static gboolean
-mail_display_link_clicked (WebKitWebView *web_view,
- WebKitWebFrame *frame,
- WebKitNetworkRequest *request,
- WebKitWebNavigationAction *navigation_action,
- WebKitWebPolicyDecision *policy_decision,
- gpointer user_data)
+decide_policy_cb (WebKitWebView *web_view,
+ WebKitPolicyDecision *decision,
+ WebKitPolicyDecisionType type)
{
- const gchar *uri = webkit_network_request_get_uri (request);
+ WebKitNavigationPolicyDecision *navigation_decision;
+ WebKitNavigationAction *navigation_action;
+ WebKitURIRequest *request;
+ const gchar *uri;
+
+ if (type != WEBKIT_POLICY_DECISION_TYPE_NAVIGATION_ACTION)
+ return FALSE;
+
+ navigation_decision = WEBKIT_NAVIGATION_POLICY_DECISION (decision);
+ navigation_action = webkit_navigation_policy_decision_get_navigation_action (navigation_decision);
+ request = webkit_navigation_action_get_request (navigation_action);
+
+ uri = webkit_uri_request_get_uri (request);
+
+ if (!uri || !*uri) {
+ webkit_policy_decision_ignore (decision);
+ return TRUE;
+ }
if (g_str_has_prefix (uri, "file://")) {
gchar *filename;
@@ -370,8 +365,9 @@ mail_display_link_clicked (WebKitWebView *web_view,
filename = g_filename_from_uri (uri, NULL, NULL);
if (g_file_test (filename, G_FILE_TEST_IS_DIR)) {
- webkit_web_policy_decision_ignore (policy_decision);
- webkit_network_request_set_uri (request, "about:blank");
+ webkit_policy_decision_ignore (decision);
+ /* FIXME WK2 Not sure if the request will be changed there */
+ webkit_uri_request_set_uri (request, "about:blank");
g_free (filename);
return TRUE;
}
@@ -381,17 +377,17 @@ mail_display_link_clicked (WebKitWebView *web_view,
if (mail_display_process_mailto (E_WEB_VIEW (web_view), uri, NULL)) {
/* do nothing, function handled the "mailto:" uri already */
- webkit_web_policy_decision_ignore (policy_decision);
+ webkit_policy_decision_ignore (decision);
return TRUE;
} else if (g_ascii_strncasecmp (uri, "thismessage:", 12) == 0) {
/* ignore */
- webkit_web_policy_decision_ignore (policy_decision);
+ webkit_policy_decision_ignore (decision);
return TRUE;
} else if (g_ascii_strncasecmp (uri, "cid:", 4) == 0) {
/* ignore */
- webkit_web_policy_decision_ignore (policy_decision);
+ webkit_policy_decision_ignore (decision);
return TRUE;
}
@@ -401,942 +397,808 @@ mail_display_link_clicked (WebKitWebView *web_view,
}
static void
-mail_display_resource_requested (WebKitWebView *web_view,
- WebKitWebFrame *frame,
- WebKitWebResource *resource,
- WebKitNetworkRequest *request,
- WebKitNetworkResponse *response,
- gpointer user_data)
+add_color_css_rule_for_web_view (EWebView *view,
+ const gchar *color_name,
+ const gchar *color_value)
{
- const gchar *original_uri;
-
- original_uri = webkit_network_request_get_uri (request);
+ gchar *selector;
+ gchar *style;
- if (original_uri != NULL) {
- gchar *redirected_uri;
+ selector = g_strconcat (".-e-mail-formatter-", color_name, NULL);
- redirected_uri = e_web_view_redirect_uri (
- E_WEB_VIEW (web_view), original_uri);
+ if (g_strstr_len (color_name, -1, "header")) {
+ style = g_strconcat (
+ "color: ", color_value, " !important;", NULL);
+ } else if (g_strstr_len (color_name, -1, "frame")) {
+ style = g_strconcat (
+ "border-color: ", color_value, NULL);
+ } else {
+ style = g_strconcat (
+ "background-color: ", color_value, " !important;", NULL);
+ }
- webkit_network_request_set_uri (request, redirected_uri);
+ e_web_view_add_css_rule_into_style_sheet (
+ view,
+ "-e-mail-formatter-style-sheet",
+ selector,
+ style);
- g_free (redirected_uri);
- }
+ g_free (style);
+ g_free (selector);
}
-static WebKitDOMElement *
-find_element_by_id (WebKitDOMDocument *document,
- const gchar *id)
+static void
+initialize_web_view_colors (EMailDisplay *display)
{
- WebKitDOMNodeList *frames;
- WebKitDOMElement *element = NULL;
- gulong ii, length;
-
- if (!WEBKIT_DOM_IS_DOCUMENT (document))
- return NULL;
+ EMailFormatter *formatter;
+ GtkTextDirection direction;
+ const gchar *style;
+ gint ii;
- /* Try to look up the element in this DOM document */
- element = webkit_dom_document_get_element_by_id (document, id);
- if (element != NULL)
- return element;
+ const gchar *color_names[] = {
+ "body-color",
+ "citation-color",
+ "frame-color",
+ "header-color",
+ NULL
+ };
- /* If the element is not here then recursively scan all frames */
- frames = webkit_dom_document_get_elements_by_tag_name (
- document, "iframe");
- length = webkit_dom_node_list_get_length (frames);
- for (ii = 0; ii < length; ii++) {
- WebKitDOMHTMLIFrameElement *iframe;
- WebKitDOMDocument *frame_doc;
+ formatter = e_mail_display_get_formatter (display);
- iframe = WEBKIT_DOM_HTML_IFRAME_ELEMENT (
- webkit_dom_node_list_item (frames, ii));
+ for (ii = 0; color_names[ii]; ii++) {
+ GdkRGBA *color = NULL;
+ gchar *color_value;
- frame_doc = webkit_dom_html_iframe_element_get_content_document (iframe);
+ g_object_get (formatter, color_names[ii], &color, NULL);
+ color_value = g_strdup_printf ("#%06x", e_rgba_to_value (color));
- element = find_element_by_id (frame_doc, id);
+ add_color_css_rule_for_web_view (
+ E_WEB_VIEW (display),
+ color_names[ii],
+ color_value);
- g_object_unref (iframe);
- if (element != NULL)
- break;
+ gdk_rgba_free (color);
+ g_free (color_value);
}
- g_object_unref (frames);
-
- return element;
-}
+ e_web_view_add_css_rule_into_style_sheet (
+ E_WEB_VIEW (display),
+ "-e-mail-formatter-style-sheet",
+ ".-e-mail-formatter-frame-security-none",
+ "border-width: 1px; border-style: solid");
-static void
-mail_display_plugin_widget_resize (GtkWidget *widget,
- gpointer dummy,
- EMailDisplay *display)
-{
- WebKitDOMElement *parent_element;
- gchar *dim;
- gint height, width;
- gfloat scale;
-
- parent_element = g_object_get_data (
- G_OBJECT (widget), "parent_element");
-
- if (!WEBKIT_DOM_IS_ELEMENT (parent_element)) {
- d (
- printf ("%s: %s does not have (valid) parent element!\n",
- G_STRFUNC, (gchar *) g_object_get_data (G_OBJECT (widget), "uri")));
- return;
- }
+ /* the rgba values below were copied from e-formatter-secure-button */
+ direction = gtk_widget_get_default_direction ();
- scale = webkit_web_view_get_zoom_level (WEBKIT_WEB_VIEW (display));
- width = gtk_widget_get_allocated_width (widget);
- gtk_widget_get_preferred_height_for_width (widget, width, &height, NULL);
+ if (direction == GTK_TEXT_DIR_RTL)
+ style = "border-width: 1px 1px 1px 4px; border-style: solid; border-color: rgba(53%, 73%,
53%, 1.0)";
+ else
+ style = "border-width: 1px 4px 1px 1px; border-style: solid; border-color: rgba(53%, 73%,
53%, 1.0)";
+ e_web_view_add_css_rule_into_style_sheet (
+ E_WEB_VIEW (display),
+ "-e-mail-formatter-style-sheet",
+ ".-e-mail-formatter-frame-security-good",
+ style);
- /* When zooming WebKit does not change dimensions of the elements,
- * but only scales them on the canvas. GtkWidget can't be scaled
- * though so we need to cope with the dimension changes to keep the
- * the widgets the correct size. Due to inaccuracy in rounding
- * (float -> int) it still acts a bit funny, but at least it does
- * not cause widgets in WebKit to go crazy when zooming. */
- height = height * (1 / scale);
+ if (direction == GTK_TEXT_DIR_RTL)
+ style = "border-width: 1px 1px 1px 4px; border-style: solid; border-color: rgba(73%, 53%,
53%, 1.0)";
+ else
+ style = "border-width: 1px 4px 1px 1px; border-style: solid; border-color: rgba(73%, 53%,
53%, 1.0)";
+ e_web_view_add_css_rule_into_style_sheet (
+ E_WEB_VIEW (display),
+ "-e-mail-formatter-style-sheet",
+ ".-e-mail-formatter-frame-security-bad",
+ style);
- /* Int -> Str */
- dim = g_strdup_printf ("%d", height);
+ if (direction == GTK_TEXT_DIR_RTL)
+ style = "border-width: 1px 1px 1px 4px; border-style: solid; border-color: rgba(91%, 82%,
13%, 1.0)";
+ else
+ style = "border-width: 1px 4px 1px 1px; border-style: solid; border-color: rgba(91%, 82%,
13%, 1.0)";
+ e_web_view_add_css_rule_into_style_sheet (
+ E_WEB_VIEW (display),
+ "-e-mail-formatter-style-sheet",
+ ".-e-mail-formatter-frame-security-unknown",
+ style);
- /* Set height of the containment <object> to match height of the
- * GtkWidget it contains */
- webkit_dom_html_object_element_set_height (
- WEBKIT_DOM_HTML_OBJECT_ELEMENT (parent_element), dim);
- g_free (dim);
+ if (direction == GTK_TEXT_DIR_RTL)
+ style = "border-width: 1px 1px 1px 4px; border-style: solid; border-color: rgba(91%, 82%,
13%, 1.0)";
+ else
+ style = "border-width: 1px 4px 1px 1px; border-style: solid; border-color: rgba(91%, 82%,
13%, 1.0)";
+ e_web_view_add_css_rule_into_style_sheet (
+ E_WEB_VIEW (display),
+ "-e-mail-formatter-style-sheet",
+ ".-e-mail-formatter-frame-security-need-key",
+ style);
}
static void
-plugin_widget_set_parent_element (GtkWidget *widget,
- EMailDisplay *display)
+headers_collapsed_signal_cb (GDBusConnection *connection,
+ const gchar *sender_name,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *signal_name,
+ GVariant *parameters,
+ EMailDisplay *display)
{
- const gchar *uri;
- WebKitDOMDocument *document;
- WebKitDOMElement *element;
+ gboolean expanded;
- uri = g_object_get_data (G_OBJECT (widget), "uri");
- if (uri == NULL || *uri == '\0')
+ if (g_strcmp0 (signal_name, "HeadersCollapsed") != 0)
return;
- document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (display));
- element = find_element_by_id (document, uri);
+ if (parameters)
+ g_variant_get (parameters, "(b)", &expanded);
- if (!WEBKIT_DOM_IS_ELEMENT (element)) {
- g_warning ("Failed to find parent <object> for '%s' - no ID set?", uri);
- return;
- }
+ e_mail_display_set_headers_collapsed (display, expanded);
+}
- /* Assign the WebKitDOMElement to "parent_element" data of the
- * GtkWidget and the GtkWidget to "widget" data of the DOM Element. */
- g_object_set_data (G_OBJECT (widget), "parent_element", element);
- g_object_set_data (G_OBJECT (element), "widget", widget);
+static void
+setup_dom_bindings (EMailDisplay *display)
+{
+ GDBusProxy *web_extension;
+
+ web_extension = e_web_view_get_web_extension_proxy (E_WEB_VIEW (display));
+
+ if (web_extension) {
+ if (display->priv->web_extension_headers_collapsed_signal_id == 0) {
+ display->priv->web_extension_headers_collapsed_signal_id =
+ g_dbus_connection_signal_subscribe (
+ g_dbus_proxy_get_connection (web_extension),
+ g_dbus_proxy_get_name (web_extension),
+ E_WEB_EXTENSION_INTERFACE,
+ "HeadersCollapsed",
+ E_WEB_EXTENSION_OBJECT_PATH,
+ NULL,
+ G_DBUS_SIGNAL_FLAGS_NONE,
+ (GDBusSignalCallback) headers_collapsed_signal_cb,
+ display,
+ NULL);
+ }
- e_binding_bind_property (
- element, "hidden",
- widget, "visible",
- G_BINDING_SYNC_CREATE |
- G_BINDING_INVERT_BOOLEAN);
+ g_dbus_proxy_call (
+ web_extension,
+ "EMailDisplayBindDOM",
+ g_variant_new (
+ "(t)",
+ webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (display))),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+ }
}
static void
-attachment_button_expanded (GObject *object,
- GParamSpec *pspec,
- gpointer user_data)
+mail_display_change_one_attachment_visibility (EMailDisplay *display,
+ EAttachment *attachment,
+ gboolean show,
+ gboolean flip)
{
- EAttachmentButton *button = E_ATTACHMENT_BUTTON (object);
- EMailDisplay *display = user_data;
- WebKitDOMDocument *document;
- WebKitDOMElement *element, *iframe;
- WebKitDOMCSSStyleDeclaration *css;
- const gchar *attachment_part_id;
gchar *element_id;
- gboolean expanded;
-
- d (
- printf ("Attachment button %s has been %s!\n",
- (gchar *) g_object_get_data (object, "uri"),
- (e_attachment_button_get_expanded (button) ? "expanded" : "collapsed")));
-
- expanded =
- e_attachment_button_get_expanded (button) &&
- gtk_widget_get_visible (GTK_WIDGET (button));
+ gchar *uri;
+ guint flags;
- document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (display));
- attachment_part_id = g_object_get_data (object, "attachment_id");
+ g_return_if_fail (E_IS_MAIL_DISPLAY (display));
+ g_return_if_fail (E_IS_ATTACHMENT (attachment));
+ g_return_if_fail (g_hash_table_contains (display->priv->attachment_flags, attachment));
- element_id = g_strconcat (attachment_part_id, ".wrapper", NULL);
- element = find_element_by_id (document, element_id);
- g_free (element_id);
+ flags = GPOINTER_TO_UINT (g_hash_table_lookup (display->priv->attachment_flags, attachment));
+ if (flip)
+ show = !(flags & E_ATTACHMENT_FLAG_VISIBLE);
- if (!WEBKIT_DOM_IS_ELEMENT (element)) {
- d (
- printf ("%s: Content <div> of attachment %s does not exist!!\n",
- G_STRFUNC, (gchar *) g_object_get_data (object, "uri")));
+ if ((((flags & E_ATTACHMENT_FLAG_VISIBLE) != 0) ? 1 : 0) == (show ? 1 : 0))
return;
- }
-
- if (WEBKIT_DOM_IS_HTML_ELEMENT (element) && expanded &&
- webkit_dom_element_get_child_element_count (element) == 0) {
- gchar *inner_html_data;
- inner_html_data = webkit_dom_element_get_attribute (element, "inner-html-data");
- if (inner_html_data && *inner_html_data) {
- WebKitDOMHTMLElement *html_element;
+ if (show)
+ flags = flags | E_ATTACHMENT_FLAG_VISIBLE;
+ else
+ flags = flags & (~E_ATTACHMENT_FLAG_VISIBLE);
+ g_hash_table_insert (display->priv->attachment_flags, attachment, GUINT_TO_POINTER (flags));
- html_element = WEBKIT_DOM_HTML_ELEMENT (element);
- webkit_dom_html_element_set_inner_html (html_element, inner_html_data, NULL);
+ element_id = g_strdup_printf ("attachment-wrapper-%p", attachment);
+ e_web_view_set_element_hidden (E_WEB_VIEW (display), element_id, !show);
+ g_free (element_id);
- webkit_dom_element_remove_attribute (element, "inner-html-data");
- }
+ element_id = g_strdup_printf ("attachment-expander-img-%p", attachment);
+ uri = g_strdup_printf ("gtk-stock://%s?size=%d", show ? "go-down" : "go-next", GTK_ICON_SIZE_BUTTON);
- g_free (inner_html_data);
- }
+ e_web_view_set_element_attribute (E_WEB_VIEW (display), element_id, NULL, "src", uri);
- /* Hide/Show all the GtkWidgets inside an attachment, otherwise they could
- * be visible even if the wrapper is hidden. */
- if ((iframe = webkit_dom_element_query_selector (element, "iframe", NULL))) {
- WebKitDOMDocument *content_document;
+ g_free (element_id);
+ g_free (uri);
+}
- content_document = webkit_dom_html_iframe_element_get_content_document
- (WEBKIT_DOM_HTML_IFRAME_ELEMENT (iframe));
+static void
+mail_display_change_attachment_visibility (EMailDisplay *display,
+ gboolean all,
+ gboolean show)
+{
+ EAttachmentView *view;
+ GList *attachments, *link;
- if (content_document) {
- gint length, ii;
- WebKitDOMNodeList *list;
+ g_return_if_fail (E_IS_MAIL_DISPLAY (display));
- list = webkit_dom_document_get_elements_by_tag_name (content_document, "object");
- length = webkit_dom_node_list_get_length (list);
+ view = e_mail_display_get_attachment_view (display);
+ g_return_if_fail (view != NULL);
- for (ii = 0; ii < length; ii++) {
- WebKitDOMNode *item;
+ if (all)
+ attachments = e_attachment_store_get_attachments (display->priv->attachment_store);
+ else
+ attachments = view ? e_attachment_view_get_selected_attachments (view) : NULL;
- item = webkit_dom_node_list_item (list, ii);
+ for (link = attachments; link; link = g_list_next (link)) {
+ EAttachment *attachment = link->data;
- css = webkit_dom_element_get_style (WEBKIT_DOM_ELEMENT (item));
- if (expanded)
- g_free (webkit_dom_css_style_declaration_remove_property (css,
"display", NULL));
- else
- webkit_dom_css_style_declaration_set_property (css, "display",
"none", "", NULL);
- g_clear_object (&css);
- }
- g_object_unref (list);
- }
+ if (e_attachment_get_can_show (attachment))
+ mail_display_change_one_attachment_visibility (display, attachment, show, FALSE);
}
- /* Show or hide the DIV which contains
- * the attachment (iframe, image...). */
- css = webkit_dom_element_get_style (element);
- webkit_dom_css_style_declaration_set_property (
- css, "display", expanded ? "block" : "none", "", NULL);
- g_object_unref (css);
+ g_list_free_full (attachments, g_object_unref);
}
static void
-attachment_button_zoom_to_window_cb (GObject *object,
- GParamSpec *pspec,
- gpointer user_data)
+mail_attachment_change_zoom (EMailDisplay *display,
+ gboolean to_100_percent)
{
- EAttachmentButton *button = E_ATTACHMENT_BUTTON (object);
- EMailDisplay *display = user_data;
- WebKitDOMDocument *document;
- WebKitDOMElement *element, *child;
- WebKitDOMCSSStyleDeclaration *css;
- const gchar *attachment_part_id;
- gchar *element_id;
- gboolean zoom_to_window;
+ EAttachmentView *view;
+ GList *attachments, *link;
- d (
- printf ("Attachment button %s has been set to %s!\n",
- (gchar *) g_object_get_data (object, "uri"),
- (e_attachment_botton_get_zoom_to_window (attachment) ? "zoom-to-window" : "zoom to 100%")));
-
- if (!gtk_widget_get_visible (GTK_WIDGET (button)))
- return;
+ g_return_if_fail (E_IS_MAIL_DISPLAY (display));
- zoom_to_window = e_attachment_button_get_zoom_to_window (button);
+ view = e_mail_display_get_attachment_view (display);
+ g_return_if_fail (view != NULL);
- document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (display));
- attachment_part_id = g_object_get_data (object, "attachment_id");
+ attachments = view ? e_attachment_view_get_selected_attachments (view) : NULL;
- element_id = g_strconcat (attachment_part_id, ".wrapper", NULL);
- element = find_element_by_id (document, element_id);
- g_free (element_id);
-
- if (!WEBKIT_DOM_IS_ELEMENT (element)) {
- d (
- printf ("%s: Content <div> of attachment %s does not exist!!\n",
- G_STRFUNC, (gchar *) g_object_get_data (object, "uri")));
- return;
- }
+ for (link = attachments; link; link = g_list_next (link)) {
+ EAttachment *attachment = link->data;
+ gchar *element_id;
+ const gchar *max_width;
+ guint flags;
- child = webkit_dom_element_get_first_element_child (element);
- if (!child || !WEBKIT_DOM_IS_HTML_IMAGE_ELEMENT (child)) {
- d (
- printf ("%s: Content <div> of attachment %s does not contain image, but %s\n",
- G_STRFUNC, (gchar *) g_object_get_data (object, "uri"),
- child ? G_OBJECT_TYPE_NAME (child) : "[null]"));
- g_clear_object (&child);
- return;
- }
+ if (!E_IS_ATTACHMENT (attachment) ||
+ !g_hash_table_contains (display->priv->attachment_flags, attachment))
+ continue;
- css = webkit_dom_element_get_style (child);
- if (zoom_to_window) {
- webkit_dom_css_style_declaration_set_property (css, "max-width", "100%", "", NULL);
- } else {
- g_free (webkit_dom_css_style_declaration_remove_property (css, "max-width", NULL));
- }
- g_object_unref (css);
- g_clear_object (&child);
-}
+ flags = GPOINTER_TO_UINT (g_hash_table_lookup (display->priv->attachment_flags, attachment));
+ if ((((flags & E_ATTACHMENT_FLAG_ZOOMED_TO_100) != 0) ? 1 : 0) == (to_100_percent ? 1 : 0))
+ continue;
-static void
-mail_display_attachment_count_changed (EAttachmentStore *store,
- GParamSpec *pspec,
- GtkWidget *box)
-{
- WebKitDOMHTMLElement *element;
- GList *children;
+ if (to_100_percent)
+ flags = flags | E_ATTACHMENT_FLAG_ZOOMED_TO_100;
+ else
+ flags = flags & (~E_ATTACHMENT_FLAG_ZOOMED_TO_100);
+ g_hash_table_insert (display->priv->attachment_flags, attachment, GUINT_TO_POINTER (flags));
- children = gtk_container_get_children (GTK_CONTAINER (box));
- g_return_if_fail (children && children->data);
+ if (to_100_percent)
+ max_width = NULL;
+ else
+ max_width = "100%";
- element = g_object_get_data (children->data, "parent_element");
- g_list_free (children);
+ element_id = g_strdup_printf ("attachment-wrapper-%p::child", attachment);
- g_return_if_fail (WEBKIT_DOM_IS_HTML_ELEMENT (element));
+ e_web_view_set_element_style_property (E_WEB_VIEW (display), element_id, "max-width",
max_width, "");
- if (e_attachment_store_get_num_attachments (store) == 0) {
- gtk_widget_hide (box);
- webkit_dom_html_element_set_hidden (element, TRUE);
- } else {
- gtk_widget_show (box);
- webkit_dom_html_element_set_hidden (element, FALSE);
+ g_free (element_id);
}
-}
-typedef struct _NumAttachmentsData {
- EAttachmentStore *store;
- gulong handler_id;
-} NumAttachmentsData;
+ g_list_free_full (attachments, g_object_unref);
+}
static void
-attachment_bar_box_gone_cb (gpointer data,
- GObject *gone_box)
+action_attachment_show_cb (GtkAction *action,
+ EMailDisplay *display)
{
- NumAttachmentsData *nad = data;
+ g_return_if_fail (E_IS_MAIL_DISPLAY (display));
- if (nad) {
- g_signal_handler_disconnect (nad->store, nad->handler_id);
- g_object_unref (nad->store);
- g_free (nad);
- }
+ mail_display_change_attachment_visibility (display, FALSE, TRUE);
}
-static GtkWidget *
-mail_display_plugin_widget_requested (WebKitWebView *web_view,
- gchar *mime_type,
- gchar *uri,
- GHashTable *param,
- gpointer user_data)
+static void
+action_attachment_show_all_cb (GtkAction *action,
+ EMailDisplay *display)
{
- EMailDisplay *display;
- EMailExtensionRegistry *reg;
- EMailFormatterExtension *extension;
- GQueue *extensions;
- GList *head, *link;
- EMailPart *part = NULL;
- GtkWidget *widget = NULL;
- GWeakRef *weakref;
- gchar *part_id, *type, *object_uri;
+ g_return_if_fail (E_IS_MAIL_DISPLAY (display));
- part_id = g_hash_table_lookup (param, "data");
- if (part_id == NULL || !g_str_has_prefix (uri, "mail://"))
- return NULL;
+ mail_display_change_attachment_visibility (display, TRUE, TRUE);
+}
- type = g_hash_table_lookup (param, "type");
- if (type == NULL)
- return NULL;
+static void
+action_attachment_hide_cb (GtkAction *action,
+ EMailDisplay *display)
+{
+ g_return_if_fail (E_IS_MAIL_DISPLAY (display));
- display = E_MAIL_DISPLAY (web_view);
+ mail_display_change_attachment_visibility (display, FALSE, FALSE);
+}
- weakref = g_hash_table_lookup (display->priv->widgets, part_id);
- if (weakref)
- widget = g_weak_ref_get (weakref);
+static void
+action_attachment_hide_all_cb (GtkAction *action,
+ EMailDisplay *display)
+{
+ g_return_if_fail (E_IS_MAIL_DISPLAY (display));
- if (widget != NULL) {
- /* This cannot be the last reference; thread-safety is assured,
- because this runs in the main thread only. */
- g_object_unref (widget);
- d (printf ("Handled %s widget request from cache\n", part_id));
- return widget;
- }
+ mail_display_change_attachment_visibility (display, TRUE, FALSE);
+}
- /* Find the EMailPart representing the requested widget. */
- part = e_mail_part_list_ref_part (display->priv->part_list, part_id);
- if (part == NULL)
- return NULL;
+static void
+action_attachment_zoom_to_100_cb (GtkAction *action,
+ EMailDisplay *display)
+{
+ g_return_if_fail (E_IS_MAIL_DISPLAY (display));
- reg = e_mail_formatter_get_extension_registry (display->priv->formatter);
- extensions = e_mail_extension_registry_get_for_mime_type (reg, type);
- if (extensions == NULL)
- goto exit;
+ mail_attachment_change_zoom (display, TRUE);
+}
- extension = NULL;
- head = g_queue_peek_head_link (extensions);
- for (link = head; link != NULL; link = g_list_next (link)) {
- extension = link->data;
+static void
+action_attachment_zoom_to_window_cb (GtkAction *action,
+ EMailDisplay *display)
+{
+ g_return_if_fail (E_IS_MAIL_DISPLAY (display));
- if (extension == NULL)
- continue;
+ mail_attachment_change_zoom (display, FALSE);
+}
- if (e_mail_formatter_extension_has_widget (extension))
- break;
- }
+static GtkActionEntry attachment_inline_entries[] = {
- if (extension == NULL)
- goto exit;
-
- /* Get the widget from formatter */
- widget = e_mail_formatter_extension_get_widget (
- extension, display->priv->part_list, part, param);
- d (
- printf ("Created widget %s (%p) for part %s\n",
- G_OBJECT_TYPE_NAME (widget), widget, part_id));
-
- /* Should not happen! WebKit will display an ugly 'Plug-in not
- * available' placeholder instead of hiding the <object> element. */
- if (widget == NULL)
- goto exit;
-
- /* Attachment button has URI different then the actual PURI because
- * that URI identifies the attachment itself */
- if (E_IS_ATTACHMENT_BUTTON (widget)) {
- EMailPartAttachment *empa = (EMailPartAttachment *) part;
- EAttachment *attachment;
- gchar *attachment_part_id;
+ { "hide",
+ NULL,
+ N_("_Hide"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_attachment_hide_cb) },
- if (empa->attachment_view_part_id)
- attachment_part_id = empa->attachment_view_part_id;
- else
- attachment_part_id = part_id;
+ { "hide-all",
+ NULL,
+ N_("Hid_e All"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_attachment_hide_all_cb) },
- object_uri = g_strconcat (
- attachment_part_id, ".attachment_button", NULL);
- g_object_set_data_full (
- G_OBJECT (widget), "attachment_id",
- g_strdup (attachment_part_id),
- (GDestroyNotify) g_free);
+ { "show",
+ NULL,
+ N_("_View Inline"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_attachment_show_cb) },
- attachment = e_mail_part_attachment_ref_attachment (empa);
- if (attachment && e_attachment_is_mail_note (attachment)) {
- CamelFolder *folder;
- const gchar *message_uid;
+ { "show-all",
+ NULL,
+ N_("Vie_w All Inline"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_attachment_show_all_cb) },
- folder = e_mail_part_list_get_folder (display->priv->part_list);
- message_uid = e_mail_part_list_get_message_uid (display->priv->part_list);
+ { "zoom-to-100",
+ NULL,
+ N_("_Zoom to 100%"),
+ NULL,
+ N_("Zoom the image to its natural size"),
+ G_CALLBACK (action_attachment_zoom_to_100_cb) },
- if (folder && message_uid) {
- CamelMessageInfo *info;
+ { "zoom-to-window",
+ NULL,
+ N_("_Zoom to window"),
+ NULL,
+ N_("Zoom large images to not be wider than the window width"),
+ G_CALLBACK (action_attachment_zoom_to_window_cb) }
+};
- info = camel_folder_get_message_info (folder, message_uid);
- if (info) {
- if (!camel_message_info_get_user_flag (info, E_MAIL_NOTES_USER_FLAG))
- camel_message_info_set_user_flag (info,
E_MAIL_NOTES_USER_FLAG, TRUE);
- camel_message_info_unref (info);
- }
- }
- }
+static EAttachment *
+mail_display_ref_attachment_from_element (EMailDisplay *display,
+ const gchar *element_value)
+{
+ EAttachment *attachment = NULL;
+ GQueue queue = G_QUEUE_INIT;
+ GList *head, *link;
- g_clear_object (&attachment);
- } else {
- object_uri = g_strdup (part_id);
- }
+ g_return_val_if_fail (E_IS_MAIL_DISPLAY (display), NULL);
+ g_return_val_if_fail (element_value != NULL, NULL);
- /* Store the uri as data of the widget */
- g_object_set_data_full (
- G_OBJECT (widget), "uri",
- object_uri, (GDestroyNotify) g_free);
+ e_mail_part_list_queue_parts (display->priv->part_list, NULL, &queue);
+ head = g_queue_peek_head_link (&queue);
- /* Set pointer to the <object> element as GObject data
- * "parent_element" and set pointer to the widget as GObject
- * data "widget" to the <object> element. */
- plugin_widget_set_parent_element (widget, display);
+ for (link = head; link != NULL; link = g_list_next (link)) {
+ EMailPart *part = E_MAIL_PART (link->data);
- /* Resizing a GtkWidget requires changing size of parent
- * <object> HTML element in DOM. */
- g_signal_connect (
- widget, "size-allocate",
- G_CALLBACK (mail_display_plugin_widget_resize), display);
+ if (E_IS_MAIL_PART_ATTACHMENT (part)) {
+ EAttachment *adept;
+ gboolean can_use;
+ gchar *tmp;
- if (E_IS_ATTACHMENT_BAR (widget)) {
- GtkWidget *box = NULL;
- EAttachmentStore *store;
- NumAttachmentsData *nad;
+ adept = e_mail_part_attachment_ref_attachment (E_MAIL_PART_ATTACHMENT (part));
- /* Only when packed in box (grid does not work),
- * EAttachmentBar reports correct height */
- box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
- gtk_box_pack_start (GTK_BOX (box), widget, TRUE, TRUE, 0);
+ tmp = g_strdup_printf ("%p", adept);
+ can_use = g_strcmp0 (tmp, element_value) == 0;
+ g_free (tmp);
- /* When EAttachmentBar is expanded/collapsed it does not
- * emit size-allocate signal despite it changes it's height. */
- g_signal_connect (
- widget, "notify::expanded",
- G_CALLBACK (mail_display_plugin_widget_resize),
- display);
- g_signal_connect (
- widget, "notify::active-view",
- G_CALLBACK (mail_display_plugin_widget_resize),
- display);
-
- /* Always hide an attachment bar without attachments */
- store = e_attachment_bar_get_store (E_ATTACHMENT_BAR (widget));
-
- nad = g_new0 (NumAttachmentsData, 1);
- nad->store = g_object_ref (store);
- nad->handler_id = g_signal_connect (
- store, "notify::num-attachments",
- G_CALLBACK (mail_display_attachment_count_changed),
- box);
-
- g_object_weak_ref (G_OBJECT (box), attachment_bar_box_gone_cb, nad);
-
- gtk_widget_show (widget);
- gtk_widget_show (box);
-
- /* Initial sync */
- mail_display_attachment_count_changed (store, NULL, box);
-
- widget = box;
-
- } else if (E_IS_ATTACHMENT_BUTTON (widget)) {
-
- /* Bind visibility of DOM element containing related
- * attachment with 'expanded' property of this
- * attachment button. */
- EMailPartAttachment *empa = (EMailPartAttachment *) part;
-
- e_attachment_button_set_expandable (E_ATTACHMENT_BUTTON (widget),
- e_mail_part_attachment_get_expandable (empa));
-
- if (e_mail_part_attachment_get_expandable (empa)) {
- /* Show/hide the attachment when the EAttachmentButton
- * is expanded/collapsed or shown/hidden. */
- g_signal_connect (
- widget, "notify::expanded",
- G_CALLBACK (attachment_button_expanded),
- display);
- g_signal_connect (
- widget, "notify::visible",
- G_CALLBACK (attachment_button_expanded),
- display);
- g_signal_connect (
- widget, "notify::zoom-to-window",
- G_CALLBACK (attachment_button_zoom_to_window_cb),
- display);
-
- if (e_mail_part_should_show_inline (part)) {
- e_attachment_button_set_expanded (
- E_ATTACHMENT_BUTTON (widget), TRUE);
- } else {
- e_attachment_button_set_expanded (
- E_ATTACHMENT_BUTTON (widget), FALSE);
- attachment_button_expanded (
- G_OBJECT (widget), NULL, display);
+ if (can_use) {
+ attachment = adept;
+ break;
}
+
+ g_clear_object (&adept);
}
}
- g_hash_table_insert (
- display->priv->widgets,
- g_strdup (object_uri), e_weak_ref_new (widget));
-
-exit:
- if (part != NULL)
- g_object_unref (part);
+ while (!g_queue_is_empty (&queue))
+ g_object_unref (g_queue_pop_head (&queue));
- return widget;
+ return attachment;
}
static void
-toggle_headers_visibility (WebKitDOMElement *button,
- WebKitDOMEvent *event,
- WebKitWebView *web_view)
+mail_display_attachment_expander_clicked_cb (EWebView *web_view,
+ const gchar *element_class,
+ const gchar *element_value,
+ const GtkAllocation *element_position,
+ gpointer user_data)
{
- WebKitDOMDocument *document;
- WebKitDOMElement *short_headers = NULL, *full_headers = NULL;
- WebKitDOMCSSStyleDeclaration *css_short = NULL, *css_full = NULL;
- gboolean expanded;
- const gchar *path;
- gchar *css_value;
+ EMailDisplay *display;
+ EAttachment *attachment;
- document = webkit_web_view_get_dom_document (web_view);
+ g_return_if_fail (E_IS_MAIL_DISPLAY (web_view));
+ g_return_if_fail (element_class != NULL);
+ g_return_if_fail (element_value != NULL);
+ g_return_if_fail (element_position != NULL);
- short_headers = webkit_dom_document_get_element_by_id (
- document, "__evo-short-headers");
- if (short_headers == NULL)
- return;
-
- css_short = webkit_dom_element_get_style (short_headers);
+ display = E_MAIL_DISPLAY (web_view);
+ attachment = mail_display_ref_attachment_from_element (display, element_value);
- full_headers = webkit_dom_document_get_element_by_id (
- document, "__evo-full-headers");
- if (full_headers == NULL)
- goto clean;
+ if (attachment) {
+ /* Flip the current 'visible' state */
+ mail_display_change_one_attachment_visibility (display, attachment, FALSE, TRUE);
+ }
- css_full = webkit_dom_element_get_style (full_headers);
- css_value = webkit_dom_css_style_declaration_get_property_value (
- css_full, "display");
- expanded = (g_strcmp0 (css_value, "table") == 0);
- g_free (css_value);
+ g_clear_object (&attachment);
+}
- webkit_dom_css_style_declaration_set_property (
- css_full, "display",
- expanded ? "none" : "table", "", NULL);
- webkit_dom_css_style_declaration_set_property (
- css_short, "display",
- expanded ? "table" : "none", "", NULL);
+static void
+mail_display_attachment_inline_update_actions (EMailDisplay *display)
+{
+ GtkActionGroup *action_group;
+ GtkAction *action;
+ GList *attachments, *link;
+ EAttachmentView *view;
+ guint n_shown = 0;
+ guint n_hidden = 0;
+ guint n_selected = 0;
+ gboolean can_show = FALSE;
+ gboolean shown = FALSE;
+ gboolean is_image = FALSE;
+ gboolean zoomed_to_100 = FALSE;
+ gboolean visible;
- if (expanded)
- path = "evo-file://" EVOLUTION_IMAGESDIR "/plus.png";
- else
- path = "evo-file://" EVOLUTION_IMAGESDIR "/minus.png";
+ g_return_if_fail (E_IS_MAIL_DISPLAY (display));
- webkit_dom_html_image_element_set_src (
- WEBKIT_DOM_HTML_IMAGE_ELEMENT (button), path);
+ action_group = display->priv->attachment_inline_group;
+ g_return_if_fail (action_group != NULL);
- e_mail_display_set_headers_collapsed (
- E_MAIL_DISPLAY (web_view), expanded);
+ attachments = e_attachment_store_get_attachments (display->priv->attachment_store);
- d (printf ("Headers %s!\n", expanded ? "collapsed" : "expanded"));
- clean:
- g_clear_object (&short_headers);
- g_clear_object (&css_short);
- g_clear_object (&full_headers);
- g_clear_object (&css_full);
-}
+ for (link = attachments; link; link = g_list_next (link)) {
+ EAttachment *attachment = link->data;
+ guint32 flags;
-static void
-toggle_address_visibility (WebKitDOMElement *button,
- WebKitDOMEvent *event)
-{
- WebKitDOMElement *full_addr = NULL, *ellipsis = NULL;
- WebKitDOMElement *parent = NULL, *bold = NULL;
- WebKitDOMCSSStyleDeclaration *css_full = NULL, *css_ellipsis = NULL;
- const gchar *path;
- gchar *property_value;
- gboolean expanded;
+ if (!e_attachment_get_can_show (attachment))
+ continue;
- /* <b> element */
- bold = webkit_dom_node_get_parent_element (WEBKIT_DOM_NODE (button));
- /* <td> element */
- parent = webkit_dom_node_get_parent_element (WEBKIT_DOM_NODE (bold));
- g_object_unref (bold);
+ flags = GPOINTER_TO_UINT (g_hash_table_lookup (display->priv->attachment_flags, attachment));
+ if ((flags & E_ATTACHMENT_FLAG_VISIBLE) != 0)
+ n_shown++;
+ else
+ n_hidden++;
+ }
- full_addr = webkit_dom_element_query_selector (parent, "#__evo-moreaddr", NULL);
+ g_list_free_full (attachments, g_object_unref);
- if (!full_addr)
- goto clean;
+ view = e_mail_display_get_attachment_view (display);
+ attachments = view ? e_attachment_view_get_selected_attachments (view) : NULL;
+ n_selected = g_list_length (attachments);
- css_full = webkit_dom_element_get_style (full_addr);
+ if (n_selected == 1) {
+ EAttachment *attachment;
+ gchar *mime_type;
+ guint32 flags;
- ellipsis = webkit_dom_element_query_selector (parent, "#__evo-moreaddr-ellipsis", NULL);
+ attachment = attachments->data;
+ mime_type = e_attachment_dup_mime_type (attachment);
+ can_show = e_attachment_get_can_show (attachment);
+ is_image = can_show && mime_type && g_ascii_strncasecmp (mime_type, "image/", 6) == 0;
- if (!ellipsis)
- goto clean;
+ flags = GPOINTER_TO_UINT (g_hash_table_lookup (display->priv->attachment_flags, attachment));
+ shown = (flags & E_ATTACHMENT_FLAG_VISIBLE) != 0;
+ zoomed_to_100 = (flags & E_ATTACHMENT_FLAG_ZOOMED_TO_100) != 0;
- css_ellipsis = webkit_dom_element_get_style (ellipsis);
+ g_free (mime_type);
+ }
+ g_list_free_full (attachments, g_object_unref);
- property_value = webkit_dom_css_style_declaration_get_property_value (css_full, "display");
- expanded = g_strcmp0 (property_value, "inline") == 0;
- g_free (property_value);
+ action = gtk_action_group_get_action (action_group, "show");
+ gtk_action_set_visible (action, can_show && !shown);
- webkit_dom_css_style_declaration_set_property (
- css_full, "display", (expanded ? "none" : "inline"), "", NULL);
- webkit_dom_css_style_declaration_set_property (
- css_ellipsis, "display", (expanded ? "inline" : "none"), "", NULL);
+ /* Show this action if there are multiple viewable
+ * attachments, and at least one of them is hidden. */
+ visible = (n_shown + n_hidden > 1) && (n_hidden > 0);
+ action = gtk_action_group_get_action (action_group, "show-all");
+ gtk_action_set_visible (action, visible);
- if (expanded)
- path = "evo-file://" EVOLUTION_IMAGESDIR "/plus.png";
- else
- path = "evo-file://" EVOLUTION_IMAGESDIR "/minus.png";
+ action = gtk_action_group_get_action (action_group, "hide");
+ gtk_action_set_visible (action, can_show && shown);
- if (!WEBKIT_DOM_IS_HTML_IMAGE_ELEMENT (button)) {
- WebKitDOMElement *element;
+ /* Show this action if there are multiple viewable
+ * attachments, and at least one of them is shown. */
+ visible = (n_shown + n_hidden > 1) && (n_shown > 0);
+ action = gtk_action_group_get_action (action_group, "hide-all");
+ gtk_action_set_visible (action, visible);
- element = webkit_dom_element_query_selector (parent, "#__evo-moreaddr-img", NULL);
- if (!element)
- goto clean;
+ action = gtk_action_group_get_action (action_group, "zoom-to-100");
+ gtk_action_set_visible (action, can_show && shown && is_image && !zoomed_to_100);
- webkit_dom_html_image_element_set_src (WEBKIT_DOM_HTML_IMAGE_ELEMENT (element), path);
-
- g_object_unref (element);
- } else
- webkit_dom_html_image_element_set_src (WEBKIT_DOM_HTML_IMAGE_ELEMENT (button), path);
- clean:
- g_clear_object (&css_full);
- g_clear_object (&css_ellipsis);
- g_clear_object (&full_addr);
- g_clear_object (&ellipsis);
- g_clear_object (&parent);
+ action = gtk_action_group_get_action (action_group, "zoom-to-window");
+ gtk_action_set_visible (action, can_show && shown && is_image && zoomed_to_100);
}
static void
-add_color_css_rule_for_web_view (EWebView *view,
- const gchar *color_name,
- const gchar *color_value)
+mail_display_attachment_menu_deactivate_cb (GtkMenuShell *menu,
+ gpointer user_data)
{
- gchar *selector;
- gchar *style;
+ EMailDisplay *display = user_data;
- selector = g_strconcat (".-e-mail-formatter-", color_name, NULL);
+ g_return_if_fail (E_IS_MAIL_DISPLAY (display));
- if (g_strstr_len (color_name, -1, "header")) {
- style = g_strconcat (
- "color: ", color_value, " !important;", NULL);
- } else if (g_strstr_len (color_name, -1, "frame")) {
- style = g_strconcat (
- "border-color: ", color_value, NULL);
- } else {
- style = g_strconcat (
- "background-color: ", color_value, " !important;", NULL);
- }
+ gtk_action_group_set_visible (display->priv->attachment_inline_group, FALSE);
- e_web_view_add_css_rule_into_style_sheet (
- view,
- "-e-mail-formatter-style-sheet",
- selector,
- style);
-
- g_free (style);
- g_free (selector);
+ g_signal_handlers_disconnect_by_func (menu,
+ G_CALLBACK (mail_display_attachment_menu_deactivate_cb), display);
}
static void
-initialize_web_view_colors (EMailDisplay *display)
+mail_display_attachment_menu_position_cb (GtkMenu *menu,
+ gint *x,
+ gint *y,
+ gboolean *push_in,
+ gpointer user_data)
{
- EMailFormatter *formatter;
+ GtkRequisition menu_requisition;
GtkTextDirection direction;
- const gchar *style;
- gint ii;
+ GtkAllocation allocation;
+ GdkRectangle monitor;
+ GdkScreen *screen;
+ GdkWindow *window;
+ GtkWidget *widget;
+ EMailDisplay *display = user_data;
+ gint monitor_num;
- const gchar *color_names[] = {
- "body-color",
- "citation-color",
- "frame-color",
- "header-color",
- NULL
- };
+ g_return_if_fail (E_IS_MAIL_DISPLAY (display));
- formatter = e_mail_display_get_formatter (display);
+ widget = GTK_WIDGET (display);
+ gtk_widget_get_preferred_size (GTK_WIDGET (menu), &menu_requisition, NULL);
- for (ii = 0; color_names[ii]; ii++) {
- GdkRGBA *color = NULL;
- gchar *color_value;
+ window = gtk_widget_get_parent_window (widget);
+ screen = gtk_widget_get_screen (GTK_WIDGET (menu));
+ monitor_num = gdk_screen_get_monitor_at_window (screen, window);
+ if (monitor_num < 0)
+ monitor_num = 0;
+ gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
- g_object_get (formatter, color_names[ii], &color, NULL);
- color_value = g_strdup_printf ("#%06x", e_rgba_to_value (color));
+ allocation = display->priv->attachment_popup_position;
- add_color_css_rule_for_web_view (
- E_WEB_VIEW (display),
- color_names[ii],
- color_value);
+ gdk_window_get_origin (window, x, y);
+ *x += allocation.x;
+ *y += allocation.y + allocation.height;
- gdk_rgba_free (color);
- g_free (color_value);
- }
+ direction = gtk_widget_get_direction (widget);
+ if (direction == GTK_TEXT_DIR_LTR)
+ *x += MAX (allocation.width - menu_requisition.width, 0);
+ else if (menu_requisition.width > allocation.width)
+ *x -= menu_requisition.width - allocation.width;
- e_web_view_add_css_rule_into_style_sheet (
- E_WEB_VIEW (display),
- "-e-mail-formatter-style-sheet",
- ".-e-mail-formatter-frame-security-none",
- "border-width: 1px; border-style: solid");
+ *push_in = FALSE;
+}
- /* the rgba values below were copied from e-formatter-secure-button */
- direction = gtk_widget_get_default_direction ();
+static void
+mail_display_attachment_select_path (EAttachmentView *view,
+ EAttachment *attachment)
+{
+ GtkTreePath *path;
+ GtkTreeIter iter;
+ EAttachmentStore *store;
- if (direction == GTK_TEXT_DIR_RTL)
- style = "border-width: 1px 1px 1px 4px; border-style: solid; border-color: rgba(53%, 73%,
53%, 1.0)";
- else
- style = "border-width: 1px 4px 1px 1px; border-style: solid; border-color: rgba(53%, 73%,
53%, 1.0)";
- e_web_view_add_css_rule_into_style_sheet (
- E_WEB_VIEW (display),
- "-e-mail-formatter-style-sheet",
- ".-e-mail-formatter-frame-security-good",
- style);
+ g_return_if_fail (E_IS_ATTACHMENT_VIEW (view));
+ g_return_if_fail (E_IS_ATTACHMENT (attachment));
- if (direction == GTK_TEXT_DIR_RTL)
- style = "border-width: 1px 1px 1px 4px; border-style: solid; border-color: rgba(73%, 53%,
53%, 1.0)";
- else
- style = "border-width: 1px 4px 1px 1px; border-style: solid; border-color: rgba(73%, 53%,
53%, 1.0)";
- e_web_view_add_css_rule_into_style_sheet (
- E_WEB_VIEW (display),
- "-e-mail-formatter-style-sheet",
- ".-e-mail-formatter-frame-security-bad",
- style);
+ store = e_attachment_view_get_store (view);
+ g_return_if_fail (e_attachment_store_find_attachment_iter (store, attachment, &iter));
- if (direction == GTK_TEXT_DIR_RTL)
- style = "border-width: 1px 1px 1px 4px; border-style: solid; border-color: rgba(91%, 82%,
13%, 1.0)";
- else
- style = "border-width: 1px 4px 1px 1px; border-style: solid; border-color: rgba(91%, 82%,
13%, 1.0)";
- e_web_view_add_css_rule_into_style_sheet (
- E_WEB_VIEW (display),
- "-e-mail-formatter-style-sheet",
- ".-e-mail-formatter-frame-security-unknown",
- style);
+ path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &iter);
- if (direction == GTK_TEXT_DIR_RTL)
- style = "border-width: 1px 1px 1px 4px; border-style: solid; border-color: rgba(91%, 82%,
13%, 1.0)";
- else
- style = "border-width: 1px 4px 1px 1px; border-style: solid; border-color: rgba(91%, 82%,
13%, 1.0)";
- e_web_view_add_css_rule_into_style_sheet (
- E_WEB_VIEW (display),
- "-e-mail-formatter-style-sheet",
- ".-e-mail-formatter-frame-security-need-key",
- style);
+ e_attachment_view_unselect_all (view);
+ e_attachment_view_select_path (view, path);
+
+ gtk_tree_path_free (path);
}
static void
-setup_image_click_event_listeners_on_document (WebKitDOMDocument *document,
- WebKitWebView *web_view)
+mail_display_attachment_menu_clicked_cb (EWebView *web_view,
+ const gchar *element_class,
+ const gchar *element_value,
+ const GtkAllocation *element_position,
+ gpointer user_data)
{
- gint length, ii = 0;
- WebKitDOMElement *button;
- WebKitDOMNodeList *list;
+ EMailDisplay *display;
+ EAttachmentView *view;
+ EAttachment *attachment;
+
+ g_return_if_fail (E_IS_MAIL_DISPLAY (web_view));
+ g_return_if_fail (element_class != NULL);
+ g_return_if_fail (element_value != NULL);
+ g_return_if_fail (element_position != NULL);
- /* Install event listeners on document */
- button = webkit_dom_document_get_element_by_id (
- document, "__evo-collapse-headers-img");
- if (button != NULL)
- webkit_dom_event_target_add_event_listener (
- WEBKIT_DOM_EVENT_TARGET (button), "click",
- G_CALLBACK (toggle_headers_visibility),
- FALSE, web_view);
+ display = E_MAIL_DISPLAY (web_view);
+ view = e_mail_display_get_attachment_view (display);
+ attachment = mail_display_ref_attachment_from_element (display, element_value);
- list = webkit_dom_document_query_selector_all (document, "*[id^=__evo-moreaddr-]", NULL);
+ if (view && attachment) {
+ GtkWidget *popup_menu;
- length = webkit_dom_node_list_get_length (list);
+ popup_menu = e_attachment_view_get_popup_menu (view);
- for (ii = 0; ii < length; ii++) {
- button = WEBKIT_DOM_ELEMENT (webkit_dom_node_list_item (list, ii));
+ g_signal_connect (
+ popup_menu, "deactivate",
+ G_CALLBACK (mail_display_attachment_menu_deactivate_cb), display);
- webkit_dom_event_target_add_event_listener (
- WEBKIT_DOM_EVENT_TARGET (button), "click",
- G_CALLBACK (toggle_address_visibility), FALSE,
- NULL);
+ mail_display_attachment_select_path (view, attachment);
+ display->priv->attachment_popup_position = *element_position;
+
+ mail_display_attachment_inline_update_actions (display);
+ gtk_action_group_set_visible (display->priv->attachment_inline_group, TRUE);
+
+ e_attachment_view_show_popup_menu (view, NULL,
+ mail_display_attachment_menu_position_cb, display);
}
- g_object_unref (list);
+
+ g_clear_object (&attachment);
}
static void
-setup_dom_bindings (WebKitWebView *web_view,
- WebKitWebFrame *frame,
- gpointer user_data)
+mail_display_attachment_added_cb (EAttachmentStore *store,
+ EAttachment *attachment,
+ gpointer user_data)
{
- WebKitDOMDocument *document;
+ EMailDisplay *display = user_data;
+ guint flags;
+
+ g_return_if_fail (E_IS_ATTACHMENT_STORE (store));
+ g_return_if_fail (E_IS_ATTACHMENT (attachment));
+ g_return_if_fail (E_IS_MAIL_DISPLAY (display));
- document = webkit_web_frame_get_dom_document (frame);
+ flags = e_attachment_get_initially_shown (attachment) ? E_ATTACHMENT_FLAG_VISIBLE : 0;
- setup_image_click_event_listeners_on_document (document, web_view);
+ g_hash_table_insert (display->priv->attachment_flags, attachment, GUINT_TO_POINTER (flags));
}
static void
-mail_parts_bind_dom (GObject *object,
- GParamSpec *pspec,
- gpointer user_data)
-{
- WebKitWebFrame *frame;
- WebKitLoadStatus load_status;
- WebKitWebView *web_view;
- WebKitDOMDocument *document;
- EMailDisplay *display;
- GQueue queue = G_QUEUE_INIT;
- GList *head, *link;
- const gchar *frame_name;
+mail_display_attachment_removed_cb (EAttachmentStore *store,
+ EAttachment *attachment,
+ gpointer user_data)
+{
+ EMailDisplay *display = user_data;
- frame = WEBKIT_WEB_FRAME (object);
- load_status = webkit_web_frame_get_load_status (frame);
+ g_return_if_fail (E_IS_ATTACHMENT_STORE (store));
+ g_return_if_fail (E_IS_ATTACHMENT (attachment));
+ g_return_if_fail (E_IS_MAIL_DISPLAY (display));
- web_view = webkit_web_frame_get_web_view (frame);
- display = E_MAIL_DISPLAY (web_view);
+ g_hash_table_remove (display->priv->attachment_flags, attachment);
+}
- if (load_status == WEBKIT_LOAD_PROVISIONAL) {
- if (webkit_web_view_get_main_frame (web_view) == frame)
- e_mail_display_cleanup_skipped_uris (display);
- return;
+static void
+mail_element_exists_cb (GDBusProxy *web_extension,
+ GAsyncResult *result,
+ EMailPart *part)
+{
+ gboolean element_exists = FALSE;
+ GVariant *result_variant;
+ guint64 page_id;
+
+ result_variant = g_dbus_proxy_call_finish (web_extension, result, NULL);
+ if (result_variant) {
+ g_variant_get (result_variant, "(bt)", &element_exists, &page_id);
+ g_variant_unref (result_variant);
}
- if (load_status != WEBKIT_LOAD_FINISHED)
- return;
+ if (element_exists)
+ e_mail_part_bind_dom_element (
+ part,
+ web_extension,
+ page_id,
+ e_mail_part_get_id (part));
+
+ g_object_unref (part);
+}
+
+static void
+mail_parts_bind_dom (EMailDisplay *display)
+{
+ EWebView *web_view;
+ GQueue queue = G_QUEUE_INIT;
+ GList *head, *link;
+ GDBusProxy *web_extension;
+ gboolean has_attachment = FALSE;
+
+ g_return_if_fail (E_IS_MAIL_DISPLAY (display));
if (display->priv->part_list == NULL)
return;
initialize_web_view_colors (display);
- frame_name = webkit_web_frame_get_name (frame);
- if (frame_name == NULL || *frame_name == '\0')
- frame_name = ".message.headers";
- document = webkit_web_view_get_dom_document (web_view);
+ web_view = E_WEB_VIEW (display);
- e_mail_part_list_queue_parts (
- display->priv->part_list, frame_name, &queue);
+ web_extension = e_web_view_get_web_extension_proxy (web_view);
+ if (!web_extension)
+ return;
+
+ e_mail_part_list_queue_parts (display->priv->part_list, NULL, &queue);
head = g_queue_peek_head_link (&queue);
for (link = head; link != NULL; link = g_list_next (link)) {
EMailPart *part = E_MAIL_PART (link->data);
- WebKitDOMElement *element;
const gchar *part_id;
- /* Iterate only the parts rendered in
- * the frame and all it's subparts. */
- if (!e_mail_part_id_has_prefix (part, frame_name))
- break;
-
part_id = e_mail_part_get_id (part);
- element = find_element_by_id (document, part_id);
- if (element != NULL)
- e_mail_part_bind_dom_element (part, element);
+ has_attachment = has_attachment || E_IS_MAIL_PART_ATTACHMENT (part);
+
+ e_mail_part_web_view_loaded (part, web_view);
+
+ g_dbus_proxy_call (
+ web_extension,
+ "ElementExists",
+ g_variant_new (
+ "(ts)",
+ webkit_web_view_get_page_id (
+ WEBKIT_WEB_VIEW (display)),
+ part_id),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ (GAsyncReadyCallback)mail_element_exists_cb,
+ g_object_ref (part));
}
while (!g_queue_is_empty (&queue))
g_object_unref (g_queue_pop_head (&queue));
+
+ if (has_attachment) {
+ e_web_view_register_element_clicked (web_view, "attachment-expander",
+ mail_display_attachment_expander_clicked_cb, NULL);
+ e_web_view_register_element_clicked (web_view, "attachment-menu",
+ mail_display_attachment_menu_clicked_cb, NULL);
+ }
}
static void
-mail_display_frame_created (WebKitWebView *web_view,
- WebKitWebFrame *frame,
- gpointer user_data)
+mail_display_load_changed_cb (WebKitWebView *wk_web_view,
+ WebKitLoadEvent load_event,
+ gpointer user_data)
{
- d (printf ("Frame %s created!\n", webkit_web_frame_get_name (frame)));
+ EMailDisplay *display;
- /* Call bind_func of all parts written in this frame */
- g_signal_connect (
- frame, "notify::load-status",
- G_CALLBACK (mail_parts_bind_dom), NULL);
-}
+ g_return_if_fail (E_IS_MAIL_DISPLAY (wk_web_view));
-static void
-mail_display_uri_changed (EMailDisplay *display,
- GParamSpec *pspec,
- gpointer dummy)
-{
- d (printf ("EMailDisplay URI changed, recreating widgets hashtable\n"));
+ display = E_MAIL_DISPLAY (wk_web_view);
- if (display->priv->widgets != NULL) {
- g_hash_table_foreach (
- display->priv->widgets,
- mail_display_plugin_widget_disconnect, display);
- g_hash_table_destroy (display->priv->widgets);
+ if (load_event == WEBKIT_LOAD_STARTED) {
+ e_mail_display_cleanup_skipped_uris (display);
+ e_attachment_store_remove_all (display->priv->attachment_store);
+ return;
}
- display->priv->widgets = g_hash_table_new_full (
- (GHashFunc) g_str_hash,
- (GEqualFunc) g_str_equal,
- (GDestroyNotify) g_free,
- (GDestroyNotify) e_weak_ref_free);
+ if (load_event == WEBKIT_LOAD_FINISHED) {
+ setup_dom_bindings (display);
+ mail_parts_bind_dom (display);
+ }
}
static void
@@ -1387,6 +1249,20 @@ mail_display_get_property (GObject *object,
GParamSpec *pspec)
{
switch (property_id) {
+ case PROP_ATTACHMENT_STORE:
+ g_value_set_object (
+ value,
+ e_mail_display_get_attachment_store (
+ E_MAIL_DISPLAY (object)));
+ return;
+
+ case PROP_ATTACHMENT_VIEW:
+ g_value_set_object (
+ value,
+ e_mail_display_get_attachment_view (
+ E_MAIL_DISPLAY (object)));
+ return;
+
case PROP_FORMATTER:
g_value_set_object (
value,
@@ -1445,22 +1321,36 @@ mail_display_dispose (GObject *object)
priv->scheduled_reload = 0;
}
- if (priv->widgets != NULL) {
- g_hash_table_foreach (
- priv->widgets,
- mail_display_plugin_widget_disconnect, object);
- g_hash_table_destroy (priv->widgets);
- priv->widgets = NULL;
- }
-
if (priv->settings != NULL)
g_signal_handlers_disconnect_matched (
priv->settings, G_SIGNAL_MATCH_DATA,
0, 0, NULL, NULL, object);
+ if (priv->web_extension_headers_collapsed_signal_id > 0) {
+ g_dbus_connection_signal_unsubscribe (
+ g_dbus_proxy_get_connection (
+ e_web_view_get_web_extension_proxy (E_WEB_VIEW (object))),
+ priv->web_extension_headers_collapsed_signal_id);
+ priv->web_extension_headers_collapsed_signal_id = 0;
+ }
+
+ if (priv->attachment_store) {
+ /* To have called the mail_display_attachment_removed_cb() before it's disconnected */
+ e_attachment_store_remove_all (priv->attachment_store);
+
+ g_signal_handlers_disconnect_by_func (priv->attachment_store,
+ G_CALLBACK (mail_display_attachment_added_cb), object);
+
+ g_signal_handlers_disconnect_by_func (priv->attachment_store,
+ G_CALLBACK (mail_display_attachment_removed_cb), object);
+ }
+
g_clear_object (&priv->part_list);
g_clear_object (&priv->formatter);
g_clear_object (&priv->settings);
+ g_clear_object (&priv->attachment_store);
+ g_clear_object (&priv->attachment_view);
+ g_clear_object (&priv->attachment_inline_group);
/* Chain up to parent's dispose() method. */
G_OBJECT_CLASS (e_mail_display_parent_class)->dispose (object);
@@ -1484,6 +1374,7 @@ mail_display_finalize (GObject *object)
priv->skipped_remote_content_sites = NULL;
}
+ g_hash_table_destroy (priv->attachment_flags);
g_clear_object (&priv->remote_content);
g_mutex_unlock (&priv->remote_content_lock);
g_mutex_clear (&priv->remote_content_lock);
@@ -1493,12 +1384,107 @@ mail_display_finalize (GObject *object)
}
static void
+mail_display_get_font_settings (GSettings *settings,
+ PangoFontDescription **monospace,
+ PangoFontDescription **variable)
+{
+ gboolean use_custom_font;
+ gchar *monospace_font;
+ gchar *variable_font;
+
+ use_custom_font = g_settings_get_boolean (settings, "use-custom-font");
+
+ if (!use_custom_font) {
+ if (monospace)
+ *monospace = NULL;
+ if (variable)
+ *variable = NULL;
+ return;
+ }
+
+ monospace_font = g_settings_get_string (settings, "monospace-font");
+ variable_font = g_settings_get_string (settings, "variable-width-font");
+
+ if (monospace)
+ *monospace = (monospace_font != NULL) ? pango_font_description_from_string (monospace_font) :
NULL;
+ if (variable)
+ *variable = (variable_font != NULL) ? pango_font_description_from_string (variable_font) :
NULL;
+
+ g_free (monospace_font);
+ g_free (variable_font);
+}
+
+static void
+mail_display_set_fonts (EWebView *web_view,
+ PangoFontDescription **monospace,
+ PangoFontDescription **variable)
+{
+ EMailDisplay *display = E_MAIL_DISPLAY (web_view);
+
+ mail_display_get_font_settings (display->priv->settings, monospace, variable);
+}
+
+static void
+mail_display_web_view_initialize (WebKitWebView *web_view)
+{
+ WebKitSettings *webkit_settings;
+
+ webkit_settings = webkit_web_view_get_settings (web_view);
+
+ g_object_set (webkit_settings,
+ "enable-frame-flattening", TRUE,
+ NULL);
+}
+
+static void
mail_display_constructed (GObject *object)
{
+ EContentRequest *content_request;
+ EWebView *web_view;
+ EMailDisplay *display;
+ GtkUIManager *ui_manager;
+
e_extensible_load_extensions (E_EXTENSIBLE (object));
/* Chain up to parent's constructed() method. */
G_OBJECT_CLASS (e_mail_display_parent_class)->constructed (object);
+
+ mail_display_web_view_initialize (WEBKIT_WEB_VIEW (object));
+
+ display = E_MAIL_DISPLAY (object);
+ web_view = E_WEB_VIEW (object);
+
+ e_web_view_update_fonts (web_view);
+
+ content_request = e_http_request_new ();
+ e_web_view_register_content_request_for_scheme (web_view, "evo-http", content_request);
+ e_web_view_register_content_request_for_scheme (web_view, "evo-https", content_request);
+ g_object_unref (content_request);
+
+ content_request = e_mail_request_new ();
+ e_web_view_register_content_request_for_scheme (web_view, "mail", content_request);
+ g_object_unref (content_request);
+
+ content_request = e_cid_request_new ();
+ e_web_view_register_content_request_for_scheme (web_view, "cid", content_request);
+ g_object_unref (content_request);
+
+ display->priv->attachment_view = g_object_ref_sink (e_attachment_bar_new
(display->priv->attachment_store));
+
+ ui_manager = e_attachment_view_get_ui_manager (display->priv->attachment_view);
+ if (ui_manager) {
+ GError *error = NULL;
+
+ gtk_ui_manager_insert_action_group (ui_manager, display->priv->attachment_inline_group, -1);
+
+ display->priv->attachment_inline_ui_id = gtk_ui_manager_add_ui_from_string (ui_manager,
+ attachment_popup_ui, -1, &error);
+
+ if (error) {
+ g_warning ("%s: Failed to read attachment_popup_ui: %s", G_STRFUNC, error->message);
+ g_clear_error (&error);
+ }
+ }
}
static void
@@ -1526,98 +1512,80 @@ static gboolean
mail_display_button_press_event (GtkWidget *widget,
GdkEventButton *event)
{
- EWebView *web_view = E_WEB_VIEW (widget);
- WebKitHitTestResult *hit_test;
- GList *list, *link;
+ if (event->button == 3) {
+ EWebView *web_view = E_WEB_VIEW (widget);
+ gchar *popup_document_uri;
+ GList *list, *link;
- if (event->button != 3)
- goto chainup;
+ popup_document_uri = e_web_view_get_document_uri_from_point (web_view, event->x, event->y);
- hit_test = webkit_web_view_get_hit_test_result (
- WEBKIT_WEB_VIEW (web_view), event);
+ list = e_extensible_list_extensions (
+ E_EXTENSIBLE (web_view), E_TYPE_EXTENSION);
+ for (link = list; link != NULL; link = g_list_next (link)) {
+ EExtension *extension = link->data;
- list = e_extensible_list_extensions (
- E_EXTENSIBLE (web_view), E_TYPE_EXTENSION);
- for (link = list; link != NULL; link = g_list_next (link)) {
- EExtension *extension = link->data;
+ if (!E_IS_MAIL_DISPLAY_POPUP_EXTENSION (extension))
+ continue;
- if (!E_IS_MAIL_DISPLAY_POPUP_EXTENSION (extension))
- continue;
+ e_mail_display_popup_extension_update_actions (
+ E_MAIL_DISPLAY_POPUP_EXTENSION (extension), popup_document_uri);
+ }
- e_mail_display_popup_extension_update_actions (
- E_MAIL_DISPLAY_POPUP_EXTENSION (extension), hit_test);
+ g_list_free (list);
+ g_free (popup_document_uri);
}
- g_list_free (list);
-
- g_object_unref (hit_test);
-chainup:
/* Chain up to parent's button_press_event() method. */
return GTK_WIDGET_CLASS (e_mail_display_parent_class)->
button_press_event (widget, event);
}
-static gchar *
-mail_display_redirect_uri (EWebView *web_view,
- const gchar *uri)
-{
- EMailDisplay *display;
- EMailPartList *part_list;
- gboolean uri_is_http;
- display = E_MAIL_DISPLAY (web_view);
- part_list = e_mail_display_get_part_list (display);
+static gboolean
+mail_display_image_exists_in_cache (const gchar *image_uri)
+{
+ gchar *filename;
+ gchar *hash;
+ gboolean exists = FALSE;
- if (part_list == NULL)
- goto chainup;
+ if (!emd_global_http_cache)
+ return FALSE;
- /* Redirect cid:part_id to mail://mail_id/cid:part_id */
- if (g_str_has_prefix (uri, "cid:")) {
- CamelFolder *folder;
- const gchar *message_uid;
+ hash = g_compute_checksum_for_string (G_CHECKSUM_MD5, image_uri, -1);
+ filename = camel_data_cache_get_filename (
+ emd_global_http_cache, "http", hash);
- folder = e_mail_part_list_get_folder (part_list);
- message_uid = e_mail_part_list_get_message_uid (part_list);
+ if (filename != NULL) {
+ struct stat st;
- /* Always write raw content of CID object. */
- return e_mail_part_build_uri (
- folder, message_uid,
- "part_id", G_TYPE_STRING, uri,
- "mode", G_TYPE_INT, E_MAIL_FORMATTER_MODE_CID, NULL);
+ exists = g_file_test (filename, G_FILE_TEST_EXISTS);
+ if (exists && g_stat (filename, &st) == 0) {
+ exists = st.st_size != 0;
+ } else {
+ exists = FALSE;
+ }
+ g_free (filename);
}
- /* WebKit won't allow to load a local file when displaying
- * "remote" mail:// protocol, so we need to handle this manually. */
- if (g_str_has_prefix (uri, "file:")) {
- gchar *content = NULL;
- gchar *content_type;
- gchar *filename;
- gchar *encoded;
- gchar *new_uri;
- gsize length = 0;
-
- filename = g_filename_from_uri (uri, NULL, NULL);
- if (filename == NULL)
- goto chainup;
-
- if (!g_file_get_contents (filename, &content, &length, NULL)) {
- g_free (filename);
- goto chainup;
- }
+ g_free (hash);
- encoded = g_base64_encode ((guchar *) content, length);
- content_type = g_content_type_guess (filename, NULL, 0, NULL);
+ return exists;
+}
- new_uri = g_strdup_printf (
- "data:%s;base64,%s", content_type, encoded);
+static void
+mail_display_uri_requested_cb (EWebView *web_view,
+ const gchar *uri,
+ gchar **redirect_to_uri)
+{
+ EMailDisplay *display;
+ EMailPartList *part_list;
+ gboolean uri_is_http;
- g_free (content_type);
- g_free (content);
- g_free (filename);
- g_free (encoded);
+ display = E_MAIL_DISPLAY (web_view);
+ part_list = e_mail_display_get_part_list (display);
- return new_uri;
- }
+ if (part_list == NULL)
+ return;
uri_is_http =
g_str_has_prefix (uri, "http:") ||
@@ -1639,7 +1607,8 @@ mail_display_redirect_uri (EWebView *web_view,
can_download_uri = e_mail_display_can_download_uri (display, uri);
if (!can_download_uri) {
/* Check Evolution's cache */
- can_download_uri = mail_display_image_exists_in_cache (uri);
+ can_download_uri = mail_display_image_exists_in_cache (
+ uri + (g_str_has_prefix (uri, "evo-") ? 4 : 0));
}
/* If the URI is not cached and we are not allowed to load it
@@ -1650,17 +1619,26 @@ mail_display_redirect_uri (EWebView *web_view,
if (!can_download_uri && !display->priv->force_image_load &&
(image_policy == E_IMAGE_LOADING_POLICY_NEVER)) {
e_mail_display_claim_skipped_uri (display, uri);
- return g_strdup ("about:blank");
+ g_free (*redirect_to_uri);
+ *redirect_to_uri = g_strdup ("");
+ return;
}
folder = e_mail_part_list_get_folder (part_list);
message_uid = e_mail_part_list_get_message_uid (part_list);
- new_uri = g_strconcat ("evo-", uri, NULL);
+ if (g_str_has_prefix (uri, "evo-")) {
+ soup_uri = soup_uri_new (uri);
+ } else {
+ new_uri = g_strconcat ("evo-", uri, NULL);
+ soup_uri = soup_uri_new (new_uri);
+
+ g_free (new_uri);
+ }
+
mail_uri = e_mail_part_build_uri (
folder, message_uid, NULL, NULL);
- soup_uri = soup_uri_new (new_uri);
if (soup_uri->query)
query = soup_form_decode (soup_uri->query);
else
@@ -1682,22 +1660,18 @@ mail_display_redirect_uri (EWebView *web_view,
g_free (mail_uri);
soup_uri_set_query_from_form (soup_uri, query);
- g_free (new_uri);
new_uri = soup_uri_to_string (soup_uri, FALSE);
soup_uri_free (soup_uri);
g_hash_table_unref (query);
- return new_uri;
+ g_free (*redirect_to_uri);
+ *redirect_to_uri = new_uri;
}
-
-chainup:
- /* Chain up to parent's redirect_uri() method. */
- return E_WEB_VIEW_CLASS (e_mail_display_parent_class)->
- redirect_uri (web_view, uri);
}
+#if 0 /* FIXME WK2 */
static CamelMimePart *
camel_mime_part_from_cid (EMailDisplay *display,
const gchar *uri)
@@ -1745,60 +1719,6 @@ mail_display_suggest_filename (EWebView *web_view,
}
static void
-mail_display_set_fonts (EWebView *web_view,
- PangoFontDescription **monospace,
- PangoFontDescription **variable)
-{
- EMailDisplay *display = E_MAIL_DISPLAY (web_view);
- gboolean use_custom_font;
- gchar *monospace_font;
- gchar *variable_font;
-
- use_custom_font = g_settings_get_boolean (
- display->priv->settings, "use-custom-font");
- if (!use_custom_font) {
- *monospace = NULL;
- *variable = NULL;
- return;
- }
-
- monospace_font = g_settings_get_string (
- display->priv->settings, "monospace-font");
- variable_font = g_settings_get_string (
- display->priv->settings, "variable-width-font");
-
- *monospace = (monospace_font != NULL) ?
- pango_font_description_from_string (monospace_font) : NULL;
- *variable = (variable_font != NULL) ?
- pango_font_description_from_string (variable_font) : NULL;
-
- g_free (monospace_font);
- g_free (variable_font);
-}
-
-static void
-e_mail_display_test_change_and_update_fonts_cb (EMailDisplay *mail_display,
- const gchar *key,
- GSettings *settings)
-{
- GVariant *new_value, *old_value;
-
- new_value = g_settings_get_value (settings, key);
- old_value = g_hash_table_lookup (mail_display->priv->old_settings, key);
-
- if (!new_value || !old_value || !g_variant_equal (new_value, old_value)) {
- if (new_value)
- g_hash_table_insert (mail_display->priv->old_settings, g_strdup (key), new_value);
- else
- g_hash_table_remove (mail_display->priv->old_settings, key);
-
- e_web_view_update_fonts (E_WEB_VIEW (mail_display));
- } else if (new_value) {
- g_variant_unref (new_value);
- }
-}
-
-static void
mail_display_drag_data_get (GtkWidget *widget,
GdkDragContext *context,
GtkSelectionData *data,
@@ -1859,6 +1779,29 @@ mail_display_drag_data_get (GtkWidget *widget,
out:
g_free (uri);
}
+#endif
+
+static void
+e_mail_display_test_change_and_update_fonts_cb (EMailDisplay *mail_display,
+ const gchar *key,
+ GSettings *settings)
+{
+ GVariant *new_value, *old_value;
+
+ new_value = g_settings_get_value (settings, key);
+ old_value = g_hash_table_lookup (mail_display->priv->old_settings, key);
+
+ if (!new_value || !old_value || !g_variant_equal (new_value, old_value)) {
+ if (new_value)
+ g_hash_table_insert (mail_display->priv->old_settings, g_strdup (key), new_value);
+ else
+ g_hash_table_remove (mail_display->priv->old_settings, key);
+
+ e_web_view_update_fonts (E_WEB_VIEW (mail_display));
+ } else if (new_value) {
+ g_variant_unref (new_value);
+ }
+}
static void
e_mail_display_class_init (EMailDisplayClass *class)
@@ -1882,12 +1825,35 @@ e_mail_display_class_init (EMailDisplayClass *class)
widget_class->button_press_event = mail_display_button_press_event;
web_view_class = E_WEB_VIEW_CLASS (class);
- web_view_class->redirect_uri = mail_display_redirect_uri;
+#if 0 /* FIXME WK2 */
web_view_class->suggest_filename = mail_display_suggest_filename;
+#endif
web_view_class->set_fonts = mail_display_set_fonts;
g_object_class_install_property (
object_class,
+ PROP_ATTACHMENT_STORE,
+ g_param_spec_object (
+ "attachment-store",
+ "Attachment Store",
+ NULL,
+ E_TYPE_ATTACHMENT_STORE,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_ATTACHMENT_VIEW,
+ g_param_spec_object (
+ "attachment-view",
+ "Attachment View",
+ NULL,
+ E_TYPE_ATTACHMENT_VIEW,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (
+ object_class,
PROP_FORMATTER,
g_param_spec_pointer (
"formatter",
@@ -1956,13 +1922,24 @@ static void
e_mail_display_init (EMailDisplay *display)
{
GtkUIManager *ui_manager;
- const gchar *user_cache_dir;
- WebKitWebSettings *settings;
- WebKitWebFrame *main_frame;
GtkActionGroup *actions;
display->priv = E_MAIL_DISPLAY_GET_PRIVATE (display);
+ display->priv->attachment_store = E_ATTACHMENT_STORE (e_attachment_store_new ());
+ display->priv->attachment_flags = g_hash_table_new (g_direct_hash, g_direct_equal);
+ display->priv->attachment_inline_group = gtk_action_group_new ("e-mail-display-attachment-inline");
+
+ gtk_action_group_add_actions (
+ display->priv->attachment_inline_group, attachment_inline_entries,
+ G_N_ELEMENTS (attachment_inline_entries), display);
+ gtk_action_group_set_visible (display->priv->attachment_inline_group, FALSE);
+
+ g_signal_connect (display->priv->attachment_store, "attachment-added",
+ G_CALLBACK (mail_display_attachment_added_cb), display);
+ g_signal_connect (display->priv->attachment_store, "attachment-removed",
+ G_CALLBACK (mail_display_attachment_removed_cb), display);
+
display->priv->old_settings = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
(GDestroyNotify) g_variant_unref);
/* Set invalid mode so that MODE property initialization is run
@@ -1972,39 +1949,18 @@ e_mail_display_init (EMailDisplay *display)
display->priv->force_image_load = FALSE;
display->priv->scheduled_reload = 0;
- webkit_web_view_set_full_content_zoom (WEBKIT_WEB_VIEW (display), TRUE);
-
- settings = webkit_web_view_get_settings (WEBKIT_WEB_VIEW (display));
- g_object_set (settings, "enable-frame-flattening", TRUE, NULL);
-
g_signal_connect (
- display, "navigation-policy-decision-requested",
- G_CALLBACK (mail_display_link_clicked), NULL);
- g_signal_connect (
- display, "resource-request-starting",
- G_CALLBACK (mail_display_resource_requested), NULL);
+ display, "decide-policy",
+ G_CALLBACK (decide_policy_cb), NULL);
+
g_signal_connect (
display, "process-mailto",
G_CALLBACK (mail_display_process_mailto), NULL);
- g_signal_connect (
- display, "create-plugin-widget",
- G_CALLBACK (mail_display_plugin_widget_requested), NULL);
- g_signal_connect (
- display, "frame-created",
- G_CALLBACK (mail_display_frame_created), NULL);
- e_signal_connect_notify (
- display, "notify::uri",
- G_CALLBACK (mail_display_uri_changed), NULL);
- g_signal_connect (
- display, "document-load-finished",
- G_CALLBACK (setup_dom_bindings), NULL);
- g_signal_connect (
- display, "document-load-finished",
- G_CALLBACK (initialize_web_view_colors), NULL);
+#if 0 /* FIXME WK2 */
g_signal_connect_after (
display, "drag-data-get",
G_CALLBACK (mail_display_drag_data_get), display);
-
+#endif
display->priv->settings = e_util_ref_settings ("org.gnome.evolution.mail");
g_signal_connect_swapped (
display->priv->settings , "changed::monospace-font",
@@ -2016,12 +1972,9 @@ e_mail_display_init (EMailDisplay *display)
display->priv->settings , "changed::use-custom-font",
G_CALLBACK (e_mail_display_test_change_and_update_fonts_cb), display);
- e_web_view_update_fonts (E_WEB_VIEW (display));
-
- main_frame = webkit_web_view_get_main_frame (WEBKIT_WEB_VIEW (display));
- e_signal_connect_notify (
- main_frame, "notify::load-status",
- G_CALLBACK (mail_parts_bind_dom), NULL);
+ g_signal_connect (
+ display, "load-changed",
+ G_CALLBACK (mail_display_load_changed_cb), NULL);
actions = e_web_view_get_action_group (E_WEB_VIEW (display), "mailto");
gtk_action_group_add_actions (
@@ -2030,16 +1983,14 @@ e_mail_display_init (EMailDisplay *display)
ui_manager = e_web_view_get_ui_manager (E_WEB_VIEW (display));
gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, NULL);
- e_web_view_install_request_handler (
- E_WEB_VIEW (display), E_TYPE_MAIL_REQUEST);
- e_web_view_install_request_handler (
- E_WEB_VIEW (display), E_TYPE_HTTP_REQUEST);
- e_web_view_install_request_handler (
- E_WEB_VIEW (display), E_TYPE_FILE_REQUEST);
- e_web_view_install_request_handler (
- E_WEB_VIEW (display), E_TYPE_STOCK_REQUEST);
+ g_mutex_init (&display->priv->remote_content_lock);
+ display->priv->remote_content = NULL;
+ display->priv->skipped_remote_content_sites = g_hash_table_new_full (camel_strcase_hash,
camel_strcase_equal, g_free, NULL);
+
+ g_signal_connect (display, "uri-requested", G_CALLBACK (mail_display_uri_requested_cb), NULL);
if (emd_global_http_cache == NULL) {
+ const gchar *user_cache_dir;
GError *error = NULL;
user_cache_dir = e_get_user_cache_dir ();
@@ -2058,10 +2009,6 @@ e_mail_display_init (EMailDisplay *display)
g_clear_error (&error);
}
}
-
- g_mutex_init (&display->priv->remote_content_lock);
- display->priv->remote_content = NULL;
- display->priv->skipped_remote_content_sites = g_hash_table_new_full (camel_strcase_hash,
camel_strcase_equal, g_free, NULL);
}
static void
@@ -2088,6 +2035,46 @@ e_mail_display_update_colors (EMailDisplay *display,
g_free (color_value);
}
+static void
+e_mail_display_claim_attachment (EMailFormatter *formatter,
+ EAttachment *attachment,
+ gpointer user_data)
+{
+ EMailDisplay *display = user_data;
+ GList *attachments;
+
+ g_return_if_fail (E_IS_MAIL_FORMATTER (formatter));
+ g_return_if_fail (E_IS_ATTACHMENT (attachment));
+ g_return_if_fail (E_IS_MAIL_DISPLAY (display));
+
+ attachments = e_attachment_store_get_attachments (display->priv->attachment_store);
+
+ if (!g_list_find (attachments, attachment)) {
+ e_attachment_store_add_attachment (display->priv->attachment_store, attachment);
+
+ if (e_attachment_is_mail_note (attachment)) {
+ CamelFolder *folder;
+ const gchar *message_uid;
+
+ folder = e_mail_part_list_get_folder (display->priv->part_list);
+ message_uid = e_mail_part_list_get_message_uid (display->priv->part_list);
+
+ if (folder && message_uid) {
+ CamelMessageInfo *info;
+
+ info = camel_folder_get_message_info (folder, message_uid);
+ if (info) {
+ if (!camel_message_info_get_user_flag (info, E_MAIL_NOTES_USER_FLAG))
+ camel_message_info_set_user_flag (info,
E_MAIL_NOTES_USER_FLAG, TRUE);
+ camel_message_info_unref (info);
+ }
+ }
+ }
+ }
+
+ g_list_free_full (attachments, g_object_unref);
+}
+
GtkWidget *
e_mail_display_new (EMailRemoteContent *remote_content)
{
@@ -2096,6 +2083,22 @@ e_mail_display_new (EMailRemoteContent *remote_content)
NULL);
}
+EAttachmentStore *
+e_mail_display_get_attachment_store (EMailDisplay *display)
+{
+ g_return_val_if_fail (E_IS_MAIL_DISPLAY (display), NULL);
+
+ return display->priv->attachment_store;
+}
+
+EAttachmentView *
+e_mail_display_get_attachment_view (EMailDisplay *display)
+{
+ g_return_val_if_fail (E_IS_MAIL_DISPLAY (display), NULL);
+
+ return display->priv->attachment_view;
+}
+
EMailFormatterMode
e_mail_display_get_mode (EMailDisplay *display)
{
@@ -2178,6 +2181,8 @@ e_mail_display_set_mode (EMailDisplay *display,
G_CALLBACK (e_mail_display_reload), display,
NULL);
+ g_signal_connect (formatter, "claim-attachment", G_CALLBACK (e_mail_display_claim_attachment),
display);
+
e_mail_display_reload (display);
g_object_notify (G_OBJECT (display), "mode");
@@ -2281,7 +2286,7 @@ e_mail_display_load (EMailDisplay *display,
g_return_if_fail (E_IS_MAIL_DISPLAY (display));
- display->priv->force_image_load = FALSE;
+ e_mail_display_set_force_load_images (display, FALSE);
part_list = display->priv->part_list;
if (part_list == NULL) {
@@ -2442,85 +2447,42 @@ e_mail_display_set_status (EMailDisplay *display,
g_free (str);
}
-static gchar *
-mail_display_get_frame_selection_text (WebKitDOMElement *iframe)
-{
- WebKitDOMDocument *document;
- WebKitDOMDOMWindow *window;
- WebKitDOMDOMSelection *selection;
- WebKitDOMNodeList *frames;
- gulong ii, length;
-
- document = webkit_dom_html_iframe_element_get_content_document (
- WEBKIT_DOM_HTML_IFRAME_ELEMENT (iframe));
- window = webkit_dom_document_get_default_view (document);
- selection = webkit_dom_dom_window_get_selection (window);
- if (selection && (webkit_dom_dom_selection_get_range_count (selection) > 0)) {
- WebKitDOMRange *range;
-
- range = webkit_dom_dom_selection_get_range_at (selection, 0, NULL);
- if (range != NULL)
- return webkit_dom_range_to_string (range, NULL);
- }
-
- frames = webkit_dom_document_get_elements_by_tag_name (
- document, "IFRAME");
- length = webkit_dom_node_list_get_length (frames);
- for (ii = 0; ii < length; ii++) {
- WebKitDOMNode *node;
- gchar *text;
-
- node = webkit_dom_node_list_item (frames, ii);
-
- text = mail_display_get_frame_selection_text (
- WEBKIT_DOM_ELEMENT (node));
-
- g_object_unref (node);
- if (text != NULL) {
- g_object_unref (frames);
- return text;
- }
- }
-
- g_object_unref (frames);
-
- return NULL;
-}
-
-gchar *
-e_mail_display_get_selection_plain_text (EMailDisplay *display)
+const gchar *
+e_mail_display_get_selection_plain_text_sync (EMailDisplay *display,
+ GCancellable *cancellable,
+ GError **error)
{
- WebKitDOMDocument *document;
- WebKitDOMNodeList *frames;
- gulong ii, length;
+ GDBusProxy *web_extension;
g_return_val_if_fail (E_IS_MAIL_DISPLAY (display), NULL);
-
+/* FIXME WK2
if (!webkit_web_view_has_selection (WEBKIT_WEB_VIEW (display)))
return NULL;
-
- document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (display));
- frames = webkit_dom_document_get_elements_by_tag_name (document, "IFRAME");
- length = webkit_dom_node_list_get_length (frames);
-
- for (ii = 0; ii < length; ii++) {
- gchar *text;
- WebKitDOMNode *node;
-
- node = webkit_dom_node_list_item (frames, ii);
-
- text = mail_display_get_frame_selection_text (
- WEBKIT_DOM_ELEMENT (node));
-
- g_object_unref (node);
- if (text != NULL) {
- g_object_unref (frames);
- return text;
+*/
+ web_extension = e_web_view_get_web_extension_proxy (E_WEB_VIEW (display));
+ if (web_extension) {
+ GVariant *result;
+ const gchar *text_content = NULL;
+
+ result = g_dbus_proxy_call_sync (
+ web_extension,
+ "GetDocumentContentText",
+ g_variant_new (
+ "(t)",
+ webkit_web_view_get_page_id (
+ WEBKIT_WEB_VIEW (display))),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ cancellable,
+ error);
+
+ if (result) {
+ g_variant_get (result, "(&s)", &text_content);
+ g_variant_unref (result);
+ return text_content;
}
}
- g_object_unref (frames);
-
return NULL;
}
@@ -2529,7 +2491,7 @@ e_mail_display_load_images (EMailDisplay *display)
{
g_return_if_fail (E_IS_MAIL_DISPLAY (display));
- display->priv->force_image_load = TRUE;
+ e_mail_display_set_force_load_images (display, TRUE);
e_web_view_reload (E_WEB_VIEW (display));
}
@@ -2539,6 +2501,9 @@ e_mail_display_set_force_load_images (EMailDisplay *display,
{
g_return_if_fail (E_IS_MAIL_DISPLAY (display));
+ if ((display->priv->force_image_load ? 1 : 0) == (force_load_images ? 1 : 0))
+ return;
+
display->priv->force_image_load = force_load_images;
}
@@ -2617,37 +2582,3 @@ e_mail_display_set_remote_content (EMailDisplay *display,
g_mutex_unlock (&display->priv->remote_content_lock);
}
-
-gboolean
-e_mail_display_needs_key (EMailDisplay *mail_display,
- gboolean with_input)
-{
- gboolean needs_key = FALSE;
-
- g_return_val_if_fail (E_IS_MAIL_DISPLAY (mail_display), FALSE);
-
- if (gtk_widget_has_focus (GTK_WIDGET (mail_display))) {
- WebKitWebFrame *frame;
- WebKitDOMDocument *dom;
- WebKitDOMElement *element;
- gchar *name = NULL;
-
- frame = webkit_web_view_get_focused_frame (WEBKIT_WEB_VIEW (mail_display));
- if (!frame)
- return FALSE;
- dom = webkit_web_frame_get_dom_document (frame);
- element = webkit_dom_html_document_get_active_element (WEBKIT_DOM_HTML_DOCUMENT (dom));
-
- if (element)
- name = webkit_dom_node_get_node_name (WEBKIT_DOM_NODE (element));
-
- /* if INPUT or TEXTAREA has focus, then any key press should go there */
- if (name && ((with_input && g_ascii_strcasecmp (name, "INPUT") == 0) || g_ascii_strcasecmp
(name, "TEXTAREA") == 0)) {
- needs_key = TRUE;
- }
-
- g_free (name);
- }
-
- return needs_key;
-}
diff --git a/mail/e-mail-display.h b/mail/e-mail-display.h
index 893f172..3670f91 100644
--- a/mail/e-mail-display.h
+++ b/mail/e-mail-display.h
@@ -62,6 +62,12 @@ struct _EMailDisplayClass {
GType e_mail_display_get_type (void) G_GNUC_CONST;
GtkWidget * e_mail_display_new (EMailRemoteContent *remote_content);
+EAttachmentStore *
+ e_mail_display_get_attachment_store
+ (EMailDisplay *display);
+EAttachmentView *
+ e_mail_display_get_attachment_view
+ (EMailDisplay *display);
EMailFormatterMode
e_mail_display_get_mode (EMailDisplay *display);
void e_mail_display_set_mode (EMailDisplay *display,
@@ -88,8 +94,10 @@ GtkAction * e_mail_display_get_action (EMailDisplay *display,
const gchar *action_name);
void e_mail_display_set_status (EMailDisplay *display,
const gchar *status);
-gchar * e_mail_display_get_selection_plain_text
- (EMailDisplay *display);
+const gchar * e_mail_display_get_selection_plain_text_sync
+ (EMailDisplay *display,
+ GCancellable *cancellable,
+ GError **error);
void e_mail_display_load_images (EMailDisplay *display);
void e_mail_display_set_force_load_images
(EMailDisplay *display,
@@ -104,8 +112,6 @@ EMailRemoteContent *
void e_mail_display_set_remote_content
(EMailDisplay *display,
EMailRemoteContent *remote_content);
-gboolean e_mail_display_needs_key (EMailDisplay *mail_display,
- gboolean with_input);
G_END_DECLS
diff --git a/mail/e-mail-notes.c b/mail/e-mail-notes.c
index 7d69cb9..94a8396 100644
--- a/mail/e-mail-notes.c
+++ b/mail/e-mail-notes.c
@@ -94,12 +94,12 @@ e_mail_notes_extract_text_content (CamelMimePart *part)
}
static void
-e_mail_notes_extract_text_from_multipart_alternative (EHTMLEditorView *view,
+e_mail_notes_extract_text_from_multipart_alternative (EContentEditor *cnt_editor,
CamelMultipart *in_multipart)
{
guint ii, nparts;
- g_return_if_fail (E_IS_HTML_EDITOR_VIEW (view));
+ g_return_if_fail (E_IS_CONTENT_EDITOR (cnt_editor));
g_return_if_fail (CAMEL_IS_MULTIPART (in_multipart));
nparts = camel_multipart_get_number (in_multipart);
@@ -122,8 +122,12 @@ e_mail_notes_extract_text_from_multipart_alternative (EHTMLEditorView *view,
text = e_mail_notes_extract_text_content (part);
if (text) {
- e_html_editor_view_set_html_mode (view, TRUE);
- e_html_editor_view_set_text_html (view, text);
+ e_content_editor_set_html_mode (cnt_editor, TRUE);
+ e_content_editor_insert_content (
+ cnt_editor,
+ text,
+ E_CONTENT_EDITOR_INSERT_TEXT_HTML |
+ E_CONTENT_EDITOR_INSERT_REPLACE_ALL);
g_free (text);
break;
}
@@ -132,7 +136,11 @@ e_mail_notes_extract_text_from_multipart_alternative (EHTMLEditorView *view,
text = e_mail_notes_extract_text_content (part);
if (text) {
- e_html_editor_view_set_text_plain (view, text);
+ e_content_editor_insert_content (
+ cnt_editor,
+ text,
+ E_CONTENT_EDITOR_INSERT_TEXT_PLAIN |
+ E_CONTENT_EDITOR_INSERT_REPLACE_ALL);
g_free (text);
}
break;
@@ -144,13 +152,13 @@ static void
e_mail_notes_editor_extract_text_from_multipart_related (EMailNotesEditor *notes_editor,
CamelMultipart *multipart)
{
- EHTMLEditorView *view;
+ EContentEditor *cnt_editor;
guint ii, nparts;
g_return_if_fail (E_IS_MAIL_NOTES_EDITOR (notes_editor));
g_return_if_fail (CAMEL_IS_MULTIPART (multipart));
- view = e_html_editor_get_view (notes_editor->editor);
+ cnt_editor = e_html_editor_get_content_editor (notes_editor->editor);
nparts = camel_multipart_get_number (multipart);
for (ii = 0; ii < nparts; ii++) {
@@ -167,12 +175,11 @@ e_mail_notes_editor_extract_text_from_multipart_related (EMailNotesEditor *notes
continue;
if (camel_content_type_is (ct, "image", "*")) {
- e_html_editor_view_add_inline_image_from_mime_part (view, part);
+ e_content_editor_insert_image_from_mime_part (cnt_editor, part);
} else if (camel_content_type_is (ct, "multipart", "alternative")) {
content = camel_medium_get_content (CAMEL_MEDIUM (part));
- if (CAMEL_IS_MULTIPART (content)) {
- e_mail_notes_extract_text_from_multipart_alternative (view, CAMEL_MULTIPART
(content));
- }
+ if (CAMEL_IS_MULTIPART (content))
+ e_mail_notes_extract_text_from_multipart_alternative (cnt_editor,
CAMEL_MULTIPART (content));
}
}
}
@@ -183,7 +190,7 @@ e_mail_notes_editor_extract_text_from_part (EMailNotesEditor *notes_editor,
{
CamelContentType *ct;
CamelDataWrapper *content;
- EHTMLEditorView *view;
+ EContentEditor *cnt_editor;
g_return_if_fail (E_IS_MAIL_NOTES_EDITOR (notes_editor));
g_return_if_fail (CAMEL_IS_MIME_PART (part));
@@ -194,7 +201,7 @@ e_mail_notes_editor_extract_text_from_part (EMailNotesEditor *notes_editor,
g_return_if_fail (content != NULL);
g_return_if_fail (ct != NULL);
- view = e_html_editor_get_view (notes_editor->editor);
+ cnt_editor = e_html_editor_get_content_editor (notes_editor->editor);
if (camel_content_type_is (ct, "multipart", "related")) {
g_return_if_fail (CAMEL_IS_MULTIPART (content));
@@ -202,14 +209,18 @@ e_mail_notes_editor_extract_text_from_part (EMailNotesEditor *notes_editor,
e_mail_notes_editor_extract_text_from_multipart_related (notes_editor, CAMEL_MULTIPART
(content));
} else if (camel_content_type_is (ct, "multipart", "alternative")) {
if (CAMEL_IS_MULTIPART (content)) {
- e_mail_notes_extract_text_from_multipart_alternative (view, CAMEL_MULTIPART
(content));
+ e_mail_notes_extract_text_from_multipart_alternative (cnt_editor, CAMEL_MULTIPART
(content));
}
} else if (camel_content_type_is (ct, "text", "plain")) {
gchar *text;
text = e_mail_notes_extract_text_content (part);
if (text) {
- e_html_editor_view_set_text_plain (view, text);
+ e_content_editor_insert_content (
+ cnt_editor,
+ text,
+ E_CONTENT_EDITOR_INSERT_TEXT_PLAIN |
+ E_CONTENT_EDITOR_INSERT_REPLACE_ALL);
g_free (text);
}
}
@@ -221,7 +232,7 @@ e_mail_notes_editor_extract_text_from_message (EMailNotesEditor *notes_editor,
{
CamelContentType *ct;
CamelDataWrapper *content;
- EHTMLEditorView *view;
+ EContentEditor *cnt_editor;
g_return_if_fail (E_IS_MAIL_NOTES_EDITOR (notes_editor));
g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message));
@@ -232,7 +243,7 @@ e_mail_notes_editor_extract_text_from_message (EMailNotesEditor *notes_editor,
g_return_if_fail (content != NULL);
g_return_if_fail (ct != NULL);
- view = e_html_editor_get_view (notes_editor->editor);
+ cnt_editor = e_html_editor_get_content_editor (notes_editor->editor);
if (camel_content_type_is (ct, "multipart", "mixed")) {
EAttachmentStore *attachment_store;
@@ -276,13 +287,13 @@ e_mail_notes_editor_extract_text_from_message (EMailNotesEditor *notes_editor,
e_mail_notes_editor_extract_text_from_part (notes_editor, CAMEL_MIME_PART (message));
}
- e_html_editor_view_set_changed (view, FALSE);
+ e_content_editor_set_changed (cnt_editor, FALSE);
}
static CamelMimeMessage *
e_mail_notes_editor_encode_text_to_message (EMailNotesEditor *notes_editor)
{
- EHTMLEditorView *view;
+ EContentEditor *cnt_editor;
EAttachmentStore *attachment_store;
CamelMimeMessage *message = NULL;
gchar *message_uid;
@@ -293,8 +304,8 @@ e_mail_notes_editor_encode_text_to_message (EMailNotesEditor *notes_editor)
g_return_val_if_fail (E_IS_MAIL_NOTES_EDITOR (notes_editor), NULL);
g_return_val_if_fail (notes_editor->editor, NULL);
- view = e_html_editor_get_view (notes_editor->editor);
- g_return_val_if_fail (E_IS_HTML_EDITOR_VIEW (view), NULL);
+ cnt_editor = e_html_editor_get_content_editor (notes_editor->editor);
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (cnt_editor), NULL);
message = camel_mime_message_new ();
username = g_get_user_name ();
@@ -316,18 +327,23 @@ e_mail_notes_editor_encode_text_to_message (EMailNotesEditor *notes_editor)
attachment_store = e_attachment_view_get_store (E_ATTACHMENT_VIEW (notes_editor->attachment_paned));
has_attachments = e_attachment_store_get_num_attachments (attachment_store) > 0;
- if (e_html_editor_view_get_html_mode (view)) {
+ if (e_content_editor_get_html_mode (cnt_editor)) {
CamelMultipart *multipart_alternative;
CamelMultipart *multipart_body;
CamelMimePart *part;
- GList *inline_images = NULL;
+ GSList *inline_images_parts = NULL;
gchar *text;
multipart_alternative = camel_multipart_new ();
camel_data_wrapper_set_mime_type (CAMEL_DATA_WRAPPER (multipart_alternative),
"multipart/alternative");
camel_multipart_set_boundary (multipart_alternative, NULL);
- text = e_html_editor_view_get_text_plain (view);
+ text = e_content_editor_get_content (
+ cnt_editor,
+ E_CONTENT_EDITOR_GET_TEXT_PLAIN |
+ E_CONTENT_EDITOR_GET_PROCESSED,
+ NULL, NULL);
+
if (text && *text) {
part = camel_mime_part_new ();
camel_mime_part_set_content (part, text, strlen (text), "text/plain");
@@ -340,7 +356,14 @@ e_mail_notes_editor_encode_text_to_message (EMailNotesEditor *notes_editor)
g_free (text);
- text = e_html_editor_view_get_text_html (view, g_get_host_name (), &inline_images);
+ text = e_content_editor_get_content (
+ cnt_editor,
+ E_CONTENT_EDITOR_GET_PROCESSED |
+ E_CONTENT_EDITOR_GET_TEXT_HTML |
+ E_CONTENT_EDITOR_GET_INLINE_IMAGES,
+ g_get_host_name (),
+ &inline_images_parts);
+
if (has_attachments && !has_text && (!text || !*text)) {
/* Text is required, thus if there are attachments,
but no text, then store at least a space. */
@@ -357,14 +380,14 @@ e_mail_notes_editor_encode_text_to_message (EMailNotesEditor *notes_editor)
has_text = TRUE;
} else {
- g_list_free_full (inline_images, g_object_unref);
- inline_images = NULL;
+ g_slist_free_full (inline_images_parts, g_object_unref);
+ inline_images_parts = NULL;
}
g_free (text);
- if (inline_images) {
- GList *link;
+ if (inline_images_parts) {
+ GSList *link;
multipart_body = camel_multipart_new ();
camel_data_wrapper_set_mime_type (CAMEL_DATA_WRAPPER (multipart_body),
"multipart/related");
@@ -375,7 +398,7 @@ e_mail_notes_editor_encode_text_to_message (EMailNotesEditor *notes_editor)
camel_multipart_add_part (multipart_body, part);
g_object_unref (part);
- for (link = inline_images; link; link = g_list_next (link)) {
+ for (link = inline_images_parts; link; link = g_slist_next (link)) {
CamelMimePart *part = link->data;
if (!part)
@@ -408,13 +431,17 @@ e_mail_notes_editor_encode_text_to_message (EMailNotesEditor *notes_editor)
camel_medium_set_content (CAMEL_MEDIUM (message), CAMEL_DATA_WRAPPER (multipart_body));
- g_list_free_full (inline_images, g_object_unref);
+ g_slist_free_full (inline_images_parts, g_object_unref);
g_clear_object (&multipart_alternative);
g_clear_object (&multipart_body);
} else {
gchar *text;
- text = e_html_editor_view_get_text_plain (view);
+ text = e_content_editor_get_content (
+ cnt_editor,
+ E_CONTENT_EDITOR_GET_TEXT_PLAIN |
+ E_CONTENT_EDITOR_GET_PROCESSED,
+ NULL, NULL);
if (has_attachments && !has_text && (!text || !*text)) {
/* Text is required, thus if there are attachments,
@@ -560,17 +587,17 @@ notes_editor_activity_notify_cb (EActivityBar *activity_bar,
GParamSpec *param,
EMailNotesEditor *notes_editor)
{
- EHTMLEditorView *view;
+ EContentEditor *cnt_editor;
GtkAction *action;
gboolean can_edit;
g_return_if_fail (E_IS_ACTIVITY_BAR (activity_bar));
g_return_if_fail (E_IS_MAIL_NOTES_EDITOR (notes_editor));
- view = e_html_editor_get_view (notes_editor->editor);
+ cnt_editor = e_html_editor_get_content_editor (notes_editor->editor);
can_edit = notes_editor->had_message && !e_activity_bar_get_activity (activity_bar);
- webkit_web_view_set_editable (WEBKIT_WEB_VIEW (view), can_edit);
+ g_object_set (cnt_editor, "editable", can_edit, NULL);
action = gtk_action_group_get_action (notes_editor->action_group, "save-and-close");
gtk_action_set_sensitive (action, can_edit);
@@ -711,12 +738,12 @@ static void
action_close_cb (GtkAction *action,
EMailNotesEditor *notes_editor)
{
- EHTMLEditorView *view;
+ EContentEditor *cnt_editor;
gboolean something_changed = FALSE;
- view = e_html_editor_get_view (notes_editor->editor);
+ cnt_editor = e_html_editor_get_content_editor (notes_editor->editor);
- something_changed = webkit_web_view_can_undo (WEBKIT_WEB_VIEW (view));
+ something_changed = e_content_editor_get_changed (cnt_editor);
if (something_changed) {
gint response;
@@ -874,9 +901,10 @@ e_mail_notes_editor_init (EMailNotesEditor *notes_editor)
}
static EMailNotesEditor *
-e_mail_notes_editor_new (GtkWindow *parent,
- CamelFolder *folder,
- const gchar *uid)
+e_mail_notes_editor_new_with_editor (EHTMLEditor *html_editor,
+ GtkWindow *parent,
+ CamelFolder *folder,
+ const gchar *uid)
{
const gchar *ui =
"<ui>\n"
@@ -921,7 +949,7 @@ e_mail_notes_editor_new (GtkWindow *parent,
};
EMailNotesEditor *notes_editor;
- EHTMLEditorView *view;
+ EContentEditor *cnt_editor;
EFocusTracker *focus_tracker;
EActivityBar *activity_bar;
GtkUIManager *ui_manager;
@@ -948,10 +976,10 @@ e_mail_notes_editor_new (GtkWindow *parent,
content = widget;
- widget = e_html_editor_new ();
+ widget = GTK_WIDGET (html_editor);
- notes_editor->editor = E_HTML_EDITOR (widget);
- view = e_html_editor_get_view (notes_editor->editor);
+ notes_editor->editor = html_editor;
+ cnt_editor = e_html_editor_get_content_editor (notes_editor->editor);
ui_manager = e_html_editor_get_ui_manager (notes_editor->editor);
/* Because we are loading from a hard-coded string, there is
@@ -987,6 +1015,12 @@ e_mail_notes_editor_new (GtkWindow *parent,
gtk_widget_show (widget);
widget = GTK_WIDGET (notes_editor->editor);
+ g_object_set (G_OBJECT (widget),
+ "halign", GTK_ALIGN_FILL,
+ "hexpand", TRUE,
+ "valign", GTK_ALIGN_FILL,
+ "vexpand", TRUE,
+ NULL);
gtk_box_pack_start (GTK_BOX (content), widget, TRUE, TRUE, 0);
gtk_widget_show (widget);
@@ -996,7 +1030,7 @@ e_mail_notes_editor_new (GtkWindow *parent,
gtk_widget_show (widget);
e_binding_bind_property (
- view, "editable",
+ cnt_editor, "editable",
widget, "sensitive",
G_BINDING_SYNC_CREATE);
@@ -1017,10 +1051,11 @@ e_mail_notes_editor_new (GtkWindow *parent,
notes_editor->focus_tracker = focus_tracker;
- gtk_widget_grab_focus (GTK_WIDGET (view));
+ gtk_widget_grab_focus (GTK_WIDGET (cnt_editor));
settings = e_util_ref_settings ("org.gnome.evolution.mail");
- e_html_editor_view_set_html_mode (view, g_settings_get_boolean (settings, "composer-send-html"));
+ e_content_editor_set_html_mode (
+ cnt_editor, g_settings_get_boolean (settings, "composer-send-html"));
g_object_unref (settings);
g_signal_connect (
@@ -1039,29 +1074,79 @@ e_mail_notes_editor_new (GtkWindow *parent,
return notes_editor;
}
+typedef struct _AsyncData {
+ GtkWindow *parent;
+ CamelFolder *folder;
+ gchar *uid;
+} AsyncData;
+
+static void
+async_data_free (gpointer ptr)
+{
+ AsyncData *ad = ptr;
+
+ if (ad) {
+ g_clear_object (&ad->parent);
+ g_clear_object (&ad->folder);
+ g_free (ad->uid);
+ g_free (ad);
+ }
+}
+
+static void
+e_mail_notes_editor_ready_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ AsyncData *ad = user_data;
+ GtkWidget *html_editor;
+ GError *error = NULL;
+
+ g_return_if_fail (result != NULL);
+ g_return_if_fail (ad != NULL);
+
+ html_editor = e_html_editor_new_finish (result, &error);
+ if (error) {
+ g_warning ("%s: Failed to create HTML editor: %s", G_STRFUNC, error->message);
+ g_clear_error (&error);
+ } else {
+ EMailNotesEditor *notes_editor;
+ EActivityBar *activity_bar;
+ EActivity *activity;
+
+ notes_editor = e_mail_notes_editor_new_with_editor (E_HTML_EDITOR (html_editor),
+ ad->parent, ad->folder, ad->uid);
+
+ activity_bar = e_html_editor_get_activity_bar (notes_editor->editor);
+ activity = e_alert_sink_submit_thread_job (E_ALERT_SINK (notes_editor->editor),
+ _("Retrieving message..."), "mail:no-retrieve-message", NULL,
+ e_mail_notes_retrieve_message_thread,
+ g_object_ref (notes_editor), e_mail_notes_retrieve_message_done);
+ e_activity_bar_set_activity (activity_bar, activity);
+ g_clear_object (&activity);
+
+ gtk_widget_show (GTK_WIDGET (notes_editor));
+ }
+
+ async_data_free (ad);
+}
+
void
e_mail_notes_edit (GtkWindow *parent,
CamelFolder *folder,
const gchar *uid)
{
- EMailNotesEditor *notes_editor;
- EActivityBar *activity_bar;
- EActivity *activity;
+ AsyncData *ad;
g_return_if_fail (CAMEL_IS_FOLDER (folder));
g_return_if_fail (uid != NULL);
- notes_editor = e_mail_notes_editor_new (parent, folder, uid);
-
- activity_bar = e_html_editor_get_activity_bar (notes_editor->editor);
- activity = e_alert_sink_submit_thread_job (E_ALERT_SINK (notes_editor->editor),
- _("Retrieving message..."), "mail:no-retrieve-message", NULL,
- e_mail_notes_retrieve_message_thread,
- g_object_ref (notes_editor), e_mail_notes_retrieve_message_done);
- e_activity_bar_set_activity (activity_bar, activity);
- g_clear_object (&activity);
+ ad = g_new0 (AsyncData, 1);
+ ad->parent = parent ? g_object_ref (parent) : NULL;
+ ad->folder = g_object_ref (folder);
+ ad->uid = g_strdup (uid);
- gtk_widget_show (GTK_WIDGET (notes_editor));
+ e_html_editor_new (e_mail_notes_editor_ready_cb, ad);
}
gboolean
diff --git a/mail/e-mail-paned-view.c b/mail/e-mail-paned-view.c
index 47bc059..cf5635e 100644
--- a/mail/e-mail-paned-view.c
+++ b/mail/e-mail-paned-view.c
@@ -675,7 +675,7 @@ mail_paned_view_constructed (GObject *object)
EMailView *view;
GtkWidget *message_list;
GtkWidget *container;
- GtkWidget *widget;
+ GtkWidget *widget, *vbox;
priv = E_MAIL_PANED_VIEW_GET_PRIVATE (object);
@@ -737,8 +737,13 @@ mail_paned_view_constructed (GObject *object)
container = priv->paned;
+ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
widget = e_preview_pane_new (E_WEB_VIEW (priv->display));
- gtk_paned_pack2 (GTK_PANED (container), widget, FALSE, FALSE);
+
+ gtk_box_pack_start (GTK_BOX (vbox), widget, TRUE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (vbox), GTK_WIDGET (e_mail_display_get_attachment_view (priv->display)),
FALSE, FALSE, 0);
+
+ gtk_paned_pack2 (GTK_PANED (container), vbox, FALSE, FALSE);
priv->preview_pane = g_object_ref (widget);
gtk_widget_show (GTK_WIDGET (priv->display));
gtk_widget_show (widget);
@@ -748,6 +753,11 @@ mail_paned_view_constructed (GObject *object)
widget, "visible",
G_BINDING_SYNC_CREATE);
+ e_binding_bind_property (
+ object, "preview-visible",
+ vbox, "visible",
+ G_BINDING_SYNC_CREATE);
+
/* Load the view instance. */
e_mail_view_update_view_instance (E_MAIL_VIEW (object));
diff --git a/mail/e-mail-printer.c b/mail/e-mail-printer.c
index 2208ad6..15ab8b8 100644
--- a/mail/e-mail-printer.c
+++ b/mail/e-mail-printer.c
@@ -23,7 +23,7 @@
#include <glib/gi18n.h>
#include <gtk/gtk.h>
-#include <webkit/webkitdom.h>
+#include <camel/camel.h>
#include "e-util/e-util.h"
@@ -49,9 +49,6 @@ struct _EMailPrinterPrivate {
gchar *export_filename;
- WebKitWebView *web_view; /* WebView to print from */
-
- GtkPrintOperation *operation;
GtkPrintOperationAction print_action;
};
@@ -101,8 +98,9 @@ async_context_free (AsyncContext *async_context)
g_slice_free (AsyncContext, async_context);
}
+#if 0 /* FIXME WK2 */
static GtkWidget *
-mail_printer_create_custom_widget_cb (GtkPrintOperation *operation,
+mail_printer_create_custom_widget_cb (WebKitPrintOperation *operation,
AsyncContext *async_context)
{
EMailDisplay *display;
@@ -110,7 +108,7 @@ mail_printer_create_custom_widget_cb (GtkPrintOperation *operation,
EMailPart *part;
GtkWidget *widget;
- gtk_print_operation_set_custom_tab_label (operation, _("Headers"));
+ webkit_print_operation_set_custom_tab_label (operation, _("Headers"));
display = E_MAIL_DISPLAY (async_context->web_view);
part_list = e_mail_display_get_part_list (display);
@@ -128,7 +126,7 @@ mail_printer_create_custom_widget_cb (GtkPrintOperation *operation,
}
static void
-mail_printer_custom_widget_apply_cb (GtkPrintOperation *operation,
+mail_printer_custom_widget_apply_cb (WebKitPrintOperation *operation,
GtkWidget *widget,
AsyncContext *async_context)
{
@@ -171,6 +169,33 @@ mail_printer_draw_footer_cb (GtkPrintOperation *operation,
g_object_unref (layout);
g_free (text);
}
+#endif
+static void
+mail_printer_print_finished_cb (WebKitPrintOperation *print_operation,
+ GSimpleAsyncResult *simple)
+{
+ if (camel_debug ("wex"))
+ printf ("%s\n", G_STRFUNC);
+}
+
+static void
+mail_printer_print_failed_cb (WebKitPrintOperation *print_operation,
+ GError *error,
+ GSimpleAsyncResult *simple)
+{
+ AsyncContext *async_context;
+
+ if (camel_debug ("wex"))
+ printf ("%s\n", G_STRFUNC);
+ async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+ if (error != NULL)
+ g_simple_async_result_take_error (simple, error);
+ else
+ g_warning ("WebKit print operation returned ERROR result without setting a GError");
+
+ async_context->print_result = GTK_PRINT_OPERATION_RESULT_ERROR;
+}
static gboolean
mail_printer_print_timeout_cb (gpointer user_data)
@@ -178,34 +203,32 @@ mail_printer_print_timeout_cb (gpointer user_data)
GSimpleAsyncResult *simple;
AsyncContext *async_context;
GCancellable *cancellable;
- GtkPrintOperation *print_operation;
+ WebKitPrintOperation *print_operation;
+/* FIXME WK2 EMailPrinter *printer;
GtkPrintOperationAction print_action;
- EMailPrinter *printer;
- WebKitWebFrame *web_frame;
- gulong create_custom_widget_handler_id;
- gulong custom_widget_apply_handler_id;
gulong draw_page_handler_id;
+ gulong create_custom_widget_handler_id;
+ gulong custom_widget_apply_handler_id;*/
GError *error = NULL;
simple = G_SIMPLE_ASYNC_RESULT (user_data);
async_context = g_simple_async_result_get_op_res_gpointer (simple);
cancellable = async_context->cancellable;
+ /*
print_action = async_context->print_action;
-
+*/
/* Check for cancellation one last time before printing. */
if (g_cancellable_set_error_if_cancelled (cancellable, &error))
goto exit;
/* This returns a new reference. */
+/*
printer = (EMailPrinter *) g_async_result_get_source_object (
G_ASYNC_RESULT (simple));
-
- print_operation = e_print_operation_new ();
-
- gtk_print_operation_set_show_progress (print_operation, TRUE);
- gtk_print_operation_set_unit (print_operation, GTK_UNIT_PIXEL);
-
+*/
+ print_operation = webkit_print_operation_new (async_context->web_view);
+/*
if (async_context->print_action == GTK_PRINT_OPERATION_ACTION_EXPORT) {
const gchar *export_filename;
@@ -214,7 +237,8 @@ mail_printer_print_timeout_cb (gpointer user_data)
gtk_print_operation_set_export_filename (
print_operation, export_filename);
}
-
+*/
+/*
create_custom_widget_handler_id = g_signal_connect (
print_operation, "create-custom-widget",
G_CALLBACK (mail_printer_create_custom_widget_cb),
@@ -224,42 +248,29 @@ mail_printer_print_timeout_cb (gpointer user_data)
print_operation, "custom-widget-apply",
G_CALLBACK (mail_printer_custom_widget_apply_cb),
async_context);
+*/
+ g_signal_connect (
+ print_operation, "failed",
+ G_CALLBACK (mail_printer_print_failed_cb),
+ async_context);
+
+ g_signal_connect (
+ print_operation, "finished",
+ G_CALLBACK (mail_printer_print_finished_cb),
+ async_context);
+/* FIXME WK2 - this will be hard to add back to WK2 API.. There is a CSS draft
+ * that can be used to add a page numbers, but it is not in WebKit yet.
+ * http://www.w3.org/TR/css3-page/
draw_page_handler_id = g_signal_connect (
print_operation, "draw-page",
G_CALLBACK (mail_printer_draw_footer_cb),
async_context->cancellable);
-
- web_frame = webkit_web_view_get_main_frame (async_context->web_view);
-
- async_context->print_result = webkit_web_frame_print_full (
- web_frame, print_operation, print_action, &error);
-
- /* Sanity check. */
- switch (async_context->print_result) {
- case GTK_PRINT_OPERATION_RESULT_ERROR:
- if (error == NULL)
- g_warning (
- "WebKit print operation returned "
- "ERROR result without setting a "
- "GError");
- break;
- case GTK_PRINT_OPERATION_RESULT_APPLY:
- if (error != NULL)
- g_warning (
- "WebKit print operation returned "
- "APPLY result but also set a GError");
- break;
- case GTK_PRINT_OPERATION_RESULT_CANCEL:
- if (error != NULL)
- g_warning (
- "WebKit print operation returned "
- "CANCEL result but also set a GError");
- break;
- default:
- g_warn_if_reached ();
- }
-
+*/
+ webkit_print_operation_run_dialog (
+ print_operation,
+ GTK_WINDOW (gtk_widget_get_toplevel (gtk_widget_get_toplevel (GTK_WIDGET
(async_context->web_view)))));
+/* FIXME WK2
g_signal_handler_disconnect (
print_operation, create_custom_widget_handler_id);
@@ -268,10 +279,11 @@ mail_printer_print_timeout_cb (gpointer user_data)
g_signal_handler_disconnect (
print_operation, draw_page_handler_id);
-
+*/
g_object_unref (print_operation);
- g_object_unref (printer);
+/*
+ g_object_unref (printer);*/
exit:
if (error != NULL)
@@ -283,18 +295,16 @@ exit:
}
static void
-mail_printer_load_status_cb (WebKitWebView *web_view,
- GParamSpec *pspec,
- GSimpleAsyncResult *simple)
+mail_printer_load_changed_cb (WebKitWebView *web_view,
+ WebKitLoadEvent load_event,
+ GSimpleAsyncResult *simple)
{
AsyncContext *async_context;
- WebKitLoadStatus load_status;
GCancellable *cancellable;
GError *error = NULL;
/* Note: we disregard WEBKIT_LOAD_FAILED and print what we can. */
- load_status = webkit_web_view_get_load_status (web_view);
- if (load_status != WEBKIT_LOAD_FINISHED)
+ if (load_event != WEBKIT_LOAD_FINISHED)
return;
/* Signal handlers are holding the only GSimpleAsyncResult
@@ -341,7 +351,7 @@ mail_printer_new_web_view (const gchar *charset,
const gchar *default_charset)
{
WebKitWebView *web_view;
- WebKitWebSettings *web_settings;
+ WebKitSettings *web_settings;
EMailFormatter *formatter;
web_view = g_object_new (
@@ -446,8 +456,6 @@ mail_printer_dispose (GObject *object)
g_clear_object (&priv->formatter);
g_clear_object (&priv->part_list);
g_clear_object (&priv->remote_content);
- g_clear_object (&priv->web_view);
- g_clear_object (&priv->operation);
/* Chain up to parent's dispose() method. */
G_OBJECT_CLASS (e_mail_printer_parent_class)->dispose (object);
@@ -587,8 +595,8 @@ e_mail_printer_print (EMailPrinter *printer,
async_context->web_view = g_object_ref_sink (web_view);
handler_id = g_signal_connect_data (
- web_view, "notify::load-status",
- G_CALLBACK (mail_printer_load_status_cb),
+ web_view, "load-changed",
+ G_CALLBACK (mail_printer_load_changed_cb),
g_object_ref (simple),
(GClosureNotify) g_object_unref, 0);
async_context->load_status_handler_id = handler_id;
diff --git a/mail/e-mail-reader-utils.c b/mail/e-mail-reader-utils.c
index fed2e85..c850bba 100644
--- a/mail/e-mail-reader-utils.c
+++ b/mail/e-mail-reader-utils.c
@@ -1729,6 +1729,76 @@ e_mail_reader_remove_duplicates (EMailReader *reader)
g_ptr_array_unref (uids);
}
+typedef struct _CreateComposerData {
+ EMailReader *reader;
+ CamelFolder *folder;
+ CamelMimeMessage *message;
+ gchar *message_uid;
+ gboolean keep_signature;
+
+ EMailPartList *part_list;
+ EMailReplyType reply_type;
+ EMailReplyStyle reply_style;
+ CamelInternetAddress *address;
+ EMailPartValidityFlags validity_pgp_sum;
+ EMailPartValidityFlags validity_smime_sum;
+
+ EMailForwardStyle forward_style;
+
+ CamelMimePart *attached_part;
+ gchar *attached_subject;
+ GPtrArray *attached_uids;
+} CreateComposerData;
+
+static void
+create_composer_data_free (CreateComposerData *ccd)
+{
+ if (ccd) {
+ if (ccd->attached_uids)
+ g_ptr_array_unref (ccd->attached_uids);
+
+ g_clear_object (&ccd->reader);
+ g_clear_object (&ccd->folder);
+ g_clear_object (&ccd->message);
+ g_clear_object (&ccd->part_list);
+ g_clear_object (&ccd->address);
+ g_clear_object (&ccd->attached_part);
+ g_free (ccd->message_uid);
+ g_free (ccd->attached_subject);
+ g_free (ccd);
+ }
+}
+
+static void
+mail_reader_edit_messages_composer_created_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ CreateComposerData *ccd = user_data;
+ EMsgComposer *composer;
+ GError *error = NULL;
+
+ g_return_if_fail (ccd != NULL);
+
+ composer = e_msg_composer_new_finish (result, &error);
+ if (error) {
+ g_warning ("%s: Failed to create msg composer: %s", G_STRFUNC, error->message);
+ g_clear_error (&error);
+ } else {
+ camel_medium_remove_header (
+ CAMEL_MEDIUM (ccd->message), "X-Mailer");
+
+ em_utils_edit_message (
+ composer, ccd->folder, ccd->message, ccd->message_uid,
+ ccd->keep_signature);
+
+ e_mail_reader_composer_created (
+ ccd->reader, composer, ccd->message);
+ }
+
+ create_composer_data_free (ccd);
+}
+
static void
mail_reader_edit_messages_cb (GObject *source_object,
GAsyncResult *result,
@@ -1780,24 +1850,17 @@ mail_reader_edit_messages_cb (GObject *source_object,
g_hash_table_iter_init (&iter, hash_table);
while (g_hash_table_iter_next (&iter, &key, &value)) {
- EMsgComposer *composer;
- CamelMimeMessage *message;
- const gchar *message_uid = NULL;
-
- if (async_context->replace)
- message_uid = (const gchar *) key;
-
- message = CAMEL_MIME_MESSAGE (value);
+ CreateComposerData *ccd;
- camel_medium_remove_header (
- CAMEL_MEDIUM (message), "X-Mailer");
+ ccd = g_new0 (CreateComposerData, 1);
+ ccd->reader = g_object_ref (async_context->reader);
+ ccd->folder = g_object_ref (folder);
+ ccd->message = g_object_ref (CAMEL_MIME_MESSAGE (value));
- composer = em_utils_edit_message (
- shell, folder, message, message_uid,
- async_context->keep_signature);
+ if (async_context->replace)
+ ccd->message_uid = g_strdup ((const gchar *) key);
- e_mail_reader_composer_created (
- async_context->reader, composer, message);
+ e_msg_composer_new (shell, mail_reader_edit_messages_composer_created_cb, ccd);
}
g_hash_table_unref (hash_table);
@@ -1843,6 +1906,44 @@ e_mail_reader_edit_messages (EMailReader *reader,
}
static void
+mail_reader_forward_attached_composer_created_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ CreateComposerData *ccd = user_data;
+ EMsgComposer *composer;
+ GError *error = NULL;
+
+ composer = e_msg_composer_new_finish (result, &error);
+ if (error) {
+ g_warning ("%s: Failed to create msg composer: %s", G_STRFUNC, error->message);
+ g_clear_error (&error);
+ } else {
+ CamelDataWrapper *content;
+
+ em_utils_forward_attachment (composer, ccd->attached_part, ccd->attached_subject,
ccd->folder, ccd->attached_uids);
+
+ content = camel_medium_get_content (CAMEL_MEDIUM (ccd->attached_part));
+ if (CAMEL_IS_MIME_MESSAGE (content)) {
+ e_mail_reader_composer_created (ccd->reader, composer, CAMEL_MIME_MESSAGE (content));
+ } else {
+ /* XXX What to do for the multipart/digest case?
+ * Extract the first message from the digest, or
+ * change the argument type to CamelMimePart and
+ * just pass the whole digest through?
+ *
+ * This signal is primarily serving EMailBrowser,
+ * which can only forward one message at a time.
+ * So for the moment it doesn't matter, but still
+ * something to consider. */
+ e_mail_reader_composer_created (ccd->reader, composer, NULL);
+ }
+ }
+
+ create_composer_data_free (ccd);
+}
+
+static void
mail_reader_forward_attachment_cb (GObject *source_object,
GAsyncResult *result,
gpointer user_data)
@@ -1851,9 +1952,9 @@ mail_reader_forward_attachment_cb (GObject *source_object,
EMailBackend *backend;
EActivity *activity;
EAlertSink *alert_sink;
+ EShell *shell;
CamelMimePart *part;
- CamelDataWrapper *content;
- EMsgComposer *composer;
+ CreateComposerData *ccd;
gchar *subject = NULL;
AsyncContext *async_context;
GError *local_error = NULL;
@@ -1887,40 +1988,53 @@ mail_reader_forward_attachment_cb (GObject *source_object,
goto exit;
}
+ ccd = g_new0 (CreateComposerData, 1);
+ ccd->reader = g_object_ref (async_context->reader);
+ ccd->folder = g_object_ref (folder);
+ ccd->attached_part = part;
+ ccd->attached_subject = subject;
+ ccd->attached_uids = async_context->uids ? g_ptr_array_ref (async_context->uids) : NULL;
+
backend = e_mail_reader_get_backend (async_context->reader);
+ shell = e_shell_backend_get_shell (E_SHELL_BACKEND (backend));
- composer = em_utils_forward_attachment (
- backend, part, subject, folder, async_context->uids);
-
- content = camel_medium_get_content (CAMEL_MEDIUM (part));
- if (CAMEL_IS_MIME_MESSAGE (content)) {
- e_mail_reader_composer_created (
- async_context->reader, composer,
- CAMEL_MIME_MESSAGE (content));
- } else {
- /* XXX What to do for the multipart/digest case?
- * Extract the first message from the digest, or
- * change the argument type to CamelMimePart and
- * just pass the whole digest through?
- *
- * This signal is primarily serving EMailBrowser,
- * which can only forward one message at a time.
- * So for the moment it doesn't matter, but still
- * something to consider. */
- e_mail_reader_composer_created (
- async_context->reader, composer, NULL);
- }
+ e_msg_composer_new (shell, mail_reader_forward_attached_composer_created_cb, ccd);
e_activity_set_state (activity, E_ACTIVITY_COMPLETED);
- g_object_unref (part);
- g_free (subject);
-
exit:
async_context_free (async_context);
}
static void
+mail_reader_forward_message_composer_created_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ CreateComposerData *ccd = user_data;
+ EMsgComposer *composer;
+ GError *error = NULL;
+
+ g_return_if_fail (ccd != NULL);
+
+ composer = e_msg_composer_new_finish (result, &error);
+ if (error) {
+ g_warning ("%s: Failed to create msg composer: %s", G_STRFUNC, error->message);
+ g_clear_error (&error);
+ } else {
+ em_utils_forward_message (
+ composer, ccd->message,
+ ccd->forward_style,
+ ccd->folder, ccd->message_uid);
+
+ e_mail_reader_composer_created (
+ ccd->reader, composer, ccd->message);
+ }
+
+ create_composer_data_free (ccd);
+}
+
+static void
mail_reader_forward_messages_cb (GObject *source_object,
GAsyncResult *result,
gpointer user_data)
@@ -1929,6 +2043,7 @@ mail_reader_forward_messages_cb (GObject *source_object,
EMailBackend *backend;
EActivity *activity;
EAlertSink *alert_sink;
+ EShell *shell;
GHashTable *hash_table;
GHashTableIter iter;
gpointer key, value;
@@ -1942,6 +2057,7 @@ mail_reader_forward_messages_cb (GObject *source_object,
alert_sink = e_activity_get_alert_sink (activity);
backend = e_mail_reader_get_backend (async_context->reader);
+ shell = e_shell_backend_get_shell (E_SHELL_BACKEND (backend));
hash_table = e_mail_folder_get_multiple_messages_finish (
folder, result, &local_error);
@@ -1969,20 +2085,21 @@ mail_reader_forward_messages_cb (GObject *source_object,
g_hash_table_iter_init (&iter, hash_table);
while (g_hash_table_iter_next (&iter, &key, &value)) {
- EMsgComposer *composer;
+ CreateComposerData *ccd;
CamelMimeMessage *message;
const gchar *message_uid;
message_uid = (const gchar *) key;
message = CAMEL_MIME_MESSAGE (value);
- composer = em_utils_forward_message (
- backend, message,
- async_context->forward_style,
- folder, message_uid);
+ ccd = g_new0 (CreateComposerData, 1);
+ ccd->reader = g_object_ref (async_context->reader);
+ ccd->folder = g_object_ref (folder);
+ ccd->message = g_object_ref (message);
+ ccd->message_uid = g_strdup (message_uid);
+ ccd->forward_style = async_context->forward_style;
- e_mail_reader_composer_created (
- async_context->reader, composer, message);
+ e_msg_composer_new (shell, mail_reader_forward_message_composer_created_cb, ccd);
}
g_hash_table_unref (hash_table);
@@ -2087,6 +2204,41 @@ html_contains_nonwhitespace (const gchar *html,
}
static void
+mail_reader_reply_composer_created_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ AsyncContext *async_context = user_data;
+ EMsgComposer *composer;
+ GError *error = NULL;
+
+ g_return_if_fail (async_context != NULL);
+
+ composer = e_msg_composer_new_finish (result, &error);
+ if (error) {
+ g_warning ("%s: Failed to create msg composer: %s", G_STRFUNC, error->message);
+ g_clear_error (&error);
+ } else {
+ CamelMimeMessage *message;
+
+ message = e_mail_part_list_get_message (async_context->part_list);
+
+ em_utils_reply_to_message (
+ composer, message,
+ async_context->folder,
+ async_context->message_uid,
+ async_context->reply_type,
+ async_context->reply_style,
+ async_context->part_list,
+ async_context->address);
+
+ e_mail_reader_composer_created (async_context->reader, composer, message);
+ }
+
+ async_context_free (async_context);
+}
+
+static void
mail_reader_reply_message_parsed (GObject *object,
GAsyncResult *result,
gpointer user_data)
@@ -2094,15 +2246,12 @@ mail_reader_reply_message_parsed (GObject *object,
EShell *shell;
EMailBackend *backend;
EMailReader *reader = E_MAIL_READER (object);
- EMailPartList *part_list;
- EMsgComposer *composer;
- CamelMimeMessage *message;
AsyncContext *async_context;
GError *local_error = NULL;
async_context = (AsyncContext *) user_data;
- part_list = e_mail_reader_parse_message_finish (reader, result, &local_error);
+ async_context->part_list = e_mail_reader_parse_message_finish (reader, result, &local_error);
if (local_error) {
g_warn_if_fail (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_CANCELLED));
@@ -2113,25 +2262,10 @@ mail_reader_reply_message_parsed (GObject *object,
return;
}
- message = e_mail_part_list_get_message (part_list);
-
backend = e_mail_reader_get_backend (async_context->reader);
shell = e_shell_backend_get_shell (E_SHELL_BACKEND (backend));
- composer = em_utils_reply_to_message (
- shell, message,
- async_context->folder,
- async_context->message_uid,
- async_context->reply_type,
- async_context->reply_style,
- part_list,
- async_context->address);
-
- e_mail_reader_composer_created (reader, composer, message);
-
- g_object_unref (part_list);
-
- async_context_free (async_context);
+ e_msg_composer_new (shell, mail_reader_reply_composer_created_cb, async_context);
}
static void
@@ -2186,6 +2320,60 @@ mail_reader_get_message_ready_cb (GObject *source_object,
g_object_unref (message);
}
+static void
+mail_reader_reply_to_message_composer_created_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ CreateComposerData *ccd = user_data;
+ EMsgComposer *composer;
+ GError *error = NULL;
+
+ g_return_if_fail (ccd != NULL);
+
+ composer = e_msg_composer_new_finish (result, &error);
+ if (error) {
+ g_warning ("%s: failed to create msg composer: %s", G_STRFUNC, error->message);
+ g_clear_error (&error);
+ } else {
+ em_utils_reply_to_message (
+ composer, ccd->message, ccd->folder, ccd->message_uid,
+ ccd->reply_type, ccd->reply_style, ccd->part_list, ccd->address);
+
+ if (ccd->validity_pgp_sum != 0 || ccd->validity_smime_sum != 0) {
+ GtkToggleAction *action;
+
+ if ((ccd->validity_pgp_sum & E_MAIL_PART_VALIDITY_PGP) != 0) {
+ if ((ccd->validity_pgp_sum & E_MAIL_PART_VALIDITY_SIGNED) != 0) {
+ action = GTK_TOGGLE_ACTION (E_COMPOSER_ACTION_PGP_SIGN (composer));
+ gtk_toggle_action_set_active (action, TRUE);
+ }
+
+ if ((ccd->validity_pgp_sum & E_MAIL_PART_VALIDITY_ENCRYPTED) != 0) {
+ action = GTK_TOGGLE_ACTION (E_COMPOSER_ACTION_PGP_ENCRYPT (composer));
+ gtk_toggle_action_set_active (action, TRUE);
+ }
+ }
+
+ if ((ccd->validity_smime_sum & E_MAIL_PART_VALIDITY_SMIME) != 0) {
+ if ((ccd->validity_smime_sum & E_MAIL_PART_VALIDITY_SIGNED) != 0) {
+ action = GTK_TOGGLE_ACTION (E_COMPOSER_ACTION_SMIME_SIGN (composer));
+ gtk_toggle_action_set_active (action, TRUE);
+ }
+
+ if ((ccd->validity_smime_sum & E_MAIL_PART_VALIDITY_ENCRYPTED) != 0) {
+ action = GTK_TOGGLE_ACTION (E_COMPOSER_ACTION_SMIME_ENCRYPT
(composer));
+ gtk_toggle_action_set_active (action, TRUE);
+ }
+ }
+ }
+
+ e_mail_reader_composer_created (ccd->reader, composer, ccd->message);
+ }
+
+ create_composer_data_free (ccd);
+}
+
void
e_mail_reader_reply_to_message (EMailReader *reader,
CamelMimeMessage *src_message,
@@ -2208,7 +2396,7 @@ e_mail_reader_reply_to_message (EMailReader *reader,
gint length;
gchar *mail_uri;
CamelObjectBag *registry;
- EMsgComposer *composer;
+ CreateComposerData *ccd;
EMailPartValidityFlags validity_pgp_sum = 0;
EMailPartValidityFlags validity_smime_sum = 0;
@@ -2305,7 +2493,7 @@ e_mail_reader_reply_to_message (EMailReader *reader,
if (!e_web_view_is_selection_active (web_view))
goto whole_message;
- selection = e_web_view_get_selection_html (web_view);
+ selection = e_web_view_get_selection_content_html_sync (web_view, NULL, NULL);
if (selection == NULL || *selection == '\0')
goto whole_message;
@@ -2338,42 +2526,16 @@ e_mail_reader_reply_to_message (EMailReader *reader,
CAMEL_MIME_PART (new_message),
selection, length, "text/html; charset=utf-8");
- composer = em_utils_reply_to_message (
- shell, new_message, folder, uid,
- reply_type, reply_style, NULL, address);
- if (validity_pgp_sum != 0 || validity_smime_sum != 0) {
- GtkToggleAction *action;
-
- if ((validity_pgp_sum & E_MAIL_PART_VALIDITY_PGP) != 0) {
- if ((validity_pgp_sum & E_MAIL_PART_VALIDITY_SIGNED) != 0) {
- action = GTK_TOGGLE_ACTION (E_COMPOSER_ACTION_PGP_SIGN (composer));
- gtk_toggle_action_set_active (action, TRUE);
- }
-
- if ((validity_pgp_sum & E_MAIL_PART_VALIDITY_ENCRYPTED) != 0) {
- action = GTK_TOGGLE_ACTION (E_COMPOSER_ACTION_PGP_ENCRYPT (composer));
- gtk_toggle_action_set_active (action, TRUE);
- }
- }
-
- if ((validity_smime_sum & E_MAIL_PART_VALIDITY_SMIME) != 0) {
- if ((validity_smime_sum & E_MAIL_PART_VALIDITY_SIGNED) != 0) {
- action = GTK_TOGGLE_ACTION (E_COMPOSER_ACTION_SMIME_SIGN (composer));
- gtk_toggle_action_set_active (action, TRUE);
- }
-
- if ((validity_smime_sum & E_MAIL_PART_VALIDITY_ENCRYPTED) != 0) {
- action = GTK_TOGGLE_ACTION (E_COMPOSER_ACTION_SMIME_ENCRYPT (composer));
- gtk_toggle_action_set_active (action, TRUE);
- }
- }
- }
-
- e_mail_reader_composer_created (reader, composer, new_message);
+ ccd = g_new0 (CreateComposerData, 1);
+ ccd->reader = g_object_ref (reader);
+ ccd->folder = g_object_ref (folder);
+ ccd->message_uid = g_strdup (uid);
+ ccd->message = new_message;
+ ccd->reply_type = reply_type;
+ ccd->reply_style = reply_style;
+ ccd->address = address ? g_object_ref (address) : NULL;
- g_object_unref (new_message);
-
- g_free (selection);
+ e_msg_composer_new (shell, mail_reader_reply_to_message_composer_created_cb, ccd);
goto exit;
@@ -2408,14 +2570,21 @@ whole_message:
g_object_unref (activity);
} else {
- composer = em_utils_reply_to_message (
- shell, src_message, folder, uid,
- reply_type, reply_style, part_list, address);
-
- e_mail_reader_composer_created (reader, composer, src_message);
+ ccd = g_new0 (CreateComposerData, 1);
+ ccd->reader = g_object_ref (reader);
+ ccd->folder = g_object_ref (folder);
+ ccd->message_uid = g_strdup (uid);
+ ccd->message = g_object_ref (src_message);
+ ccd->reply_type = reply_type;
+ ccd->reply_style = reply_style;
+ ccd->part_list = part_list ? g_object_ref (part_list) : NULL;
+ ccd->address = address ? g_object_ref (address) : NULL;
+
+ e_msg_composer_new (shell, mail_reader_reply_to_message_composer_created_cb, ccd);
}
exit:
+ g_free (selection);
g_clear_object (&address);
g_clear_object (&folder);
}
diff --git a/mail/e-mail-reader.c b/mail/e-mail-reader.c
index b215f79..8fe32f4 100644
--- a/mail/e-mail-reader.c
+++ b/mail/e-mail-reader.c
@@ -915,6 +915,43 @@ action_mail_message_edit_cb (GtkAction *action,
g_ptr_array_unref (uids);
}
+typedef struct _CreateComposerData {
+ EMailReader *reader;
+ CamelMimeMessage *message;
+ CamelFolder *folder;
+ gboolean is_redirect;
+} CreateComposerData;
+
+static void
+mail_reader_new_composer_created_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ CreateComposerData *ccd = user_data;
+ EMsgComposer *composer;
+ GError *error = NULL;
+
+ g_return_if_fail (ccd != NULL);
+
+ composer = e_msg_composer_new_finish (result, &error);
+ if (error) {
+ g_warning ("%s: Failed to create msg composer: %s", G_STRFUNC, error->message);
+ g_clear_error (&error);
+ } else {
+ if (ccd->is_redirect)
+ em_utils_redirect_message (composer, ccd->message);
+ else
+ em_utils_compose_new_message (composer, ccd->folder);
+
+ e_mail_reader_composer_created (ccd->reader, composer, ccd->message);
+ }
+
+ g_clear_object (&ccd->reader);
+ g_clear_object (&ccd->message);
+ g_clear_object (&ccd->folder);
+ g_free (ccd);
+}
+
static void
action_mail_message_new_cb (GtkAction *action,
EMailReader *reader)
@@ -923,7 +960,7 @@ action_mail_message_new_cb (GtkAction *action,
EMailBackend *backend;
EShellBackend *shell_backend;
CamelFolder *folder;
- EMsgComposer *composer;
+ CreateComposerData *ccd;
folder = e_mail_reader_ref_folder (reader);
backend = e_mail_reader_get_backend (reader);
@@ -931,11 +968,12 @@ action_mail_message_new_cb (GtkAction *action,
shell_backend = E_SHELL_BACKEND (backend);
shell = e_shell_backend_get_shell (shell_backend);
- composer = em_utils_compose_new_message (shell, folder);
-
- e_mail_reader_composer_created (reader, composer, NULL);
+ ccd = g_new0 (CreateComposerData, 1);
+ ccd->reader = g_object_ref (reader);
+ ccd->folder = folder;
+ ccd->is_redirect = FALSE;
- g_clear_object (&folder);
+ e_msg_composer_new (shell, mail_reader_new_composer_created_cb, ccd);
}
static void
@@ -1140,7 +1178,7 @@ mail_reader_redirect_cb (CamelFolder *folder,
EMailBackend *backend;
EAlertSink *alert_sink;
CamelMimeMessage *message;
- EMsgComposer *composer;
+ CreateComposerData *ccd;
GError *error = NULL;
alert_sink = e_activity_get_alert_sink (closure->activity);
@@ -1168,11 +1206,12 @@ mail_reader_redirect_cb (CamelFolder *folder,
backend = e_mail_reader_get_backend (closure->reader);
shell = e_shell_backend_get_shell (E_SHELL_BACKEND (backend));
- composer = em_utils_redirect_message (shell, message);
+ ccd = g_new0 (CreateComposerData, 1);
+ ccd->reader = g_object_ref (closure->reader);
+ ccd->message = message;
+ ccd->is_redirect = TRUE;
- e_mail_reader_composer_created (closure->reader, composer, message);
-
- g_object_unref (message);
+ e_msg_composer_new (shell, mail_reader_new_composer_created_cb, ccd);
mail_reader_closure_free (closure);
}
@@ -2640,33 +2679,22 @@ mail_reader_key_press_event_cb (EMailReader *reader,
const gchar *action_name;
if (!gtk_widget_has_focus (GTK_WIDGET (reader))) {
- WebKitWebFrame *frame;
- WebKitDOMDocument *dom;
- WebKitDOMElement *element;
EMailDisplay *display;
- gchar *name = NULL;
+ GDBusProxy *web_extension;
display = e_mail_reader_get_mail_display (reader);
- frame = webkit_web_view_get_focused_frame (WEBKIT_WEB_VIEW (display));
-
- if (frame != NULL) {
- dom = webkit_web_frame_get_dom_document (frame);
- element = webkit_dom_html_document_get_active_element (WEBKIT_DOM_HTML_DOCUMENT
(dom));
+ web_extension = e_web_view_get_web_extension_proxy (E_WEB_VIEW (display));
+ if (web_extension) {
+ GVariant *result;
- if (element != NULL) {
- name = webkit_dom_node_get_node_name (WEBKIT_DOM_NODE (element));
- g_object_unref (element);
- }
+ result = g_dbus_proxy_get_cached_property (web_extension, "NeedInput");
+ if (result) {
+ gboolean need_input = g_variant_get_boolean (result);
+ g_variant_unref (result);
- /* If INPUT or TEXTAREA has focus,
- * then any key press should go there. */
- if (name != NULL &&
- (g_ascii_strcasecmp (name, "INPUT") == 0 ||
- g_ascii_strcasecmp (name, "TEXTAREA") == 0)) {
- g_free (name);
- return FALSE;
+ if (need_input)
+ return FALSE;
}
- g_free (name);
}
}
@@ -2849,13 +2877,13 @@ schedule_timeout_mark_seen (EMailReader *reader)
}
static void
-mail_reader_load_status_changed_cb (EMailReader *reader,
- GParamSpec *pspec,
- EMailDisplay *display)
+mail_reader_load_changed_cb (EMailReader *reader,
+ WebKitLoadEvent event,
+ EMailDisplay *display)
{
EMailReaderPrivate *priv;
- if (webkit_web_view_get_load_status (WEBKIT_WEB_VIEW (display)) != WEBKIT_LOAD_FINISHED)
+ if (event != WEBKIT_LOAD_FINISHED)
return;
priv = E_MAIL_READER_GET_PRIVATE (reader);
@@ -4405,9 +4433,9 @@ connect_signals:
display, "key-press-event",
G_CALLBACK (mail_reader_key_press_event_cb), reader);
- e_signal_connect_notify_swapped (
- display, "notify::load-status",
- G_CALLBACK (mail_reader_load_status_changed_cb), reader);
+ g_signal_connect_swapped (
+ display, "load-changed",
+ G_CALLBACK (mail_reader_load_changed_cb), reader);
g_signal_connect_swapped (
message_list, "message-selected",
@@ -5500,37 +5528,27 @@ e_mail_reader_create_remote_content_alert_button (EMailReader *reader)
}
static void
-e_mail_reader_load_status_notify_cb (WebKitWebFrame *frame,
- GParamSpec *param,
+mail_reader_display_load_changed_cb (EMailDisplay *mail_display,
+ WebKitLoadEvent load_event,
EMailReader *reader)
{
- WebKitLoadStatus load_status;
- EMailDisplay *mail_display;
EMailReaderPrivate *priv;
- g_return_if_fail (WEBKIT_IS_WEB_FRAME (frame));
+ g_return_if_fail (E_IS_MAIL_DISPLAY (mail_display));
g_return_if_fail (E_IS_MAIL_READER (reader));
priv = E_MAIL_READER_GET_PRIVATE (reader);
g_return_if_fail (priv != NULL);
- load_status = webkit_web_frame_get_load_status (frame);
- if (load_status == WEBKIT_LOAD_PROVISIONAL) {
- WebKitWebView *web_view;
-
- web_view = webkit_web_frame_get_web_view (frame);
-
- if (priv->remote_content_alert && webkit_web_view_get_main_frame (web_view) == frame)
+ if (load_event == WEBKIT_LOAD_STARTED) {
+ if (priv->remote_content_alert)
e_alert_response (priv->remote_content_alert, GTK_RESPONSE_CLOSE);
return;
}
- if (load_status != WEBKIT_LOAD_FINISHED)
+ if (load_event != WEBKIT_LOAD_FINISHED)
return;
- mail_display = e_mail_reader_get_mail_display (reader);
- g_return_if_fail (E_IS_MAIL_DISPLAY (mail_display));
-
if (!e_mail_display_has_skipped_remote_content_sites (mail_display))
return;
@@ -5552,18 +5570,6 @@ e_mail_reader_load_status_notify_cb (WebKitWebFrame *frame,
}
}
-static void
-mail_reader_display_frame_created_cb (WebKitWebView *web_view,
- WebKitWebFrame *frame,
- EMailReader *reader)
-{
- g_return_if_fail (E_IS_MAIL_DISPLAY (web_view));
- g_return_if_fail (E_IS_MAIL_READER (reader));
-
- e_signal_connect_notify (frame, "notify::load-status",
- G_CALLBACK (e_mail_reader_load_status_notify_cb), reader);
-}
-
/**
* e_mail_reader_connect_remote_content:
* @reader: an #EMailReader
@@ -5575,18 +5581,12 @@ void
e_mail_reader_connect_remote_content (EMailReader *reader)
{
EMailDisplay *mail_display;
- WebKitWebFrame *frame;
g_return_if_fail (E_IS_MAIL_READER (reader));
mail_display = e_mail_reader_get_mail_display (reader);
g_return_if_fail (E_IS_MAIL_DISPLAY (mail_display));
- frame = webkit_web_view_get_main_frame (WEBKIT_WEB_VIEW (mail_display));
-
- e_signal_connect_notify (frame, "notify::load-status",
- G_CALLBACK (e_mail_reader_load_status_notify_cb), reader);
-
- g_signal_connect (mail_display, "frame-created",
- G_CALLBACK (mail_reader_display_frame_created_cb), reader);
+ g_signal_connect (mail_display, "load-changed",
+ G_CALLBACK (mail_reader_display_load_changed_cb), reader);
}
diff --git a/mail/e-mail-request.c b/mail/e-mail-request.c
index ce673e9..a5ef505 100644
--- a/mail/e-mail-request.c
+++ b/mail/e-mail-request.c
@@ -15,19 +15,15 @@
*
*/
-#define LIBSOUP_USE_UNSTABLE_REQUEST_API
-
-#include "e-mail-request.h"
-#include "em-utils.h"
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
#include <libsoup/soup.h>
-#include <libsoup/soup-requester.h>
-#include <libsoup/soup-request-http.h>
-
-#include <webkit/webkit.h>
#include <glib/gi18n.h>
#include <camel/camel.h>
+#include <libedataserver/libedataserver.h>
#include "shell/e-shell.h"
@@ -35,85 +31,127 @@
#include "em-format/e-mail-formatter-utils.h"
#include "em-format/e-mail-formatter-print.h"
+#include "em-utils.h"
+#include "e-mail-display.h"
#include "e-mail-ui-session.h"
+#include "e-mail-request.h"
#define d(x)
-#define dd(x)
-
-#define E_MAIL_REQUEST_GET_PRIVATE(obj) \
- (G_TYPE_INSTANCE_GET_PRIVATE \
- ((obj), E_TYPE_MAIL_REQUEST, EMailRequestPrivate))
struct _EMailRequestPrivate {
- GBytes *bytes;
- gchar *mime_type;
+ gint dummy;
+};
- GHashTable *uri_query;
- gchar *uri_base;
- gchar *full_uri;
+static void e_mail_request_content_request_init (EContentRequestInterface *iface);
- gboolean part_converted_to_utf8;
- gchar *ret_mime_type;
-};
+G_DEFINE_TYPE_WITH_CODE (EMailRequest, e_mail_request, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (E_TYPE_CONTENT_REQUEST, e_mail_request_content_request_init))
-static const gchar *data_schemes[] = { "mail", NULL };
+static gboolean
+e_mail_request_can_process_uri (EContentRequest *request,
+ const gchar *uri)
+{
+ g_return_val_if_fail (E_IS_MAIL_REQUEST (request), FALSE);
+ g_return_val_if_fail (uri != NULL, FALSE);
-G_DEFINE_TYPE (EMailRequest, e_mail_request, SOUP_TYPE_REQUEST)
+ return g_ascii_strncasecmp (uri, "mail:", 5) == 0;
+}
static void
-handle_mail_request (GSimpleAsyncResult *simple,
- GObject *object,
- GCancellable *cancellable)
+save_gicon_to_stream (GIcon *icon,
+ gint size,
+ GOutputStream *output_stream,
+ gchar **out_mime_type)
+{
+ GtkIconInfo *icon_info;
+ GdkPixbuf *pixbuf;
+
+ if (size < 16)
+ size = 16;
+
+ icon_info = gtk_icon_theme_lookup_by_gicon (gtk_icon_theme_get_default (), icon, size,
GTK_ICON_LOOKUP_FORCE_SIZE);
+ if (!icon_info)
+ return;
+
+ pixbuf = gtk_icon_info_load_icon (icon_info, NULL);
+ if (pixbuf) {
+ if (gdk_pixbuf_save_to_stream (
+ pixbuf, output_stream,
+ "png", NULL, NULL, NULL)) {
+ *out_mime_type = g_strdup ("image/png");
+ }
+ g_object_unref (pixbuf);
+ }
+
+ g_object_unref (icon);
+}
+
+static gboolean
+mail_request_process_mail_sync (EContentRequest *request,
+ SoupURI *suri,
+ GHashTable *uri_query,
+ GObject *requester,
+ GInputStream **out_stream,
+ gint64 *out_stream_length,
+ gchar **out_mime_type,
+ GCancellable *cancellable,
+ GError **error)
{
- EMailRequest *request = E_MAIL_REQUEST (object);
EMailFormatter *formatter;
EMailPartList *part_list;
CamelObjectBag *registry;
- GInputStream *input_stream;
GOutputStream *output_stream;
+ GBytes *bytes;
+ gchar *tmp, *use_mime_type = NULL;
const gchar *val;
const gchar *default_charset, *charset;
+ gboolean part_converted_to_utf8 = FALSE;
EMailFormatterContext context = { 0 };
- if (g_cancellable_is_cancelled (cancellable))
- return;
+ if (g_cancellable_set_error_if_cancelled (cancellable, error))
+ return FALSE;
+
+ tmp = g_strdup_printf ("%s://%s%s", suri->scheme, suri->host, suri->path);
registry = e_mail_part_list_get_registry ();
- part_list = camel_object_bag_get (registry, request->priv->uri_base);
+ part_list = camel_object_bag_get (registry, tmp);
+
+ g_free (tmp);
+
+ context.uri = soup_uri_to_string (suri, FALSE);
if (camel_debug_start ("emformat:requests")) {
- printf ("%s: found part-list %p for full_uri '%s'\n", G_STRFUNC, part_list,
request->priv->full_uri);
+ printf ("%s: found part-list %p for full_uri '%s'\n", G_STRFUNC, part_list, context.uri);
camel_debug_end ();
}
- if (!part_list)
- return;
+ if (!part_list) {
+ g_free (context.uri);
+ return FALSE;
+ }
- val = g_hash_table_lookup (
- request->priv->uri_query, "headers_collapsed");
+ val = g_hash_table_lookup (uri_query, "headers_collapsed");
if (val != NULL && atoi (val) == 1)
context.flags |= E_MAIL_FORMATTER_HEADER_FLAG_COLLAPSED;
- val = g_hash_table_lookup (
- request->priv->uri_query, "headers_collapsable");
+ val = g_hash_table_lookup (uri_query, "headers_collapsable");
if (val != NULL && atoi (val) == 1)
context.flags |= E_MAIL_FORMATTER_HEADER_FLAG_COLLAPSABLE;
- val = g_hash_table_lookup (request->priv->uri_query, "mode");
+ val = g_hash_table_lookup (uri_query, "mode");
if (val != NULL)
context.mode = atoi (val);
- default_charset = g_hash_table_lookup (
- request->priv->uri_query, "formatter_default_charset");
- charset = g_hash_table_lookup (
- request->priv->uri_query, "formatter_charset");
+ default_charset = g_hash_table_lookup (uri_query, "formatter_default_charset");
+ charset = g_hash_table_lookup (uri_query, "formatter_charset");
context.part_list = g_object_ref (part_list);
- context.uri = request->priv->full_uri;
if (context.mode == E_MAIL_FORMATTER_MODE_PRINTING)
formatter = e_mail_formatter_print_new ();
+ else if (E_IS_MAIL_DISPLAY (requester))
+ formatter = g_object_ref (e_mail_display_get_formatter (E_MAIL_DISPLAY (requester)));
else
formatter = e_mail_formatter_new ();
@@ -124,7 +162,58 @@ handle_mail_request (GSimpleAsyncResult *simple,
output_stream = g_memory_output_stream_new_resizable ();
- val = g_hash_table_lookup (request->priv->uri_query, "part_id");
+ val = g_hash_table_lookup (uri_query, "attachment_icon");
+ if (val) {
+ gchar *attachment_id;
+
+ attachment_id = soup_uri_decode (val);
+ if (E_IS_MAIL_DISPLAY (requester)) {
+ EMailDisplay *mail_display = E_MAIL_DISPLAY (requester);
+ EAttachmentStore *attachment_store;
+ GList *attachments, *link;
+
+ attachment_store = e_mail_display_get_attachment_store (mail_display);
+ attachments = e_attachment_store_get_attachments (attachment_store);
+ for (link = attachments; link; link = g_list_next (link)) {
+ EAttachment *attachment = link->data;
+ gboolean can_use;
+
+ tmp = g_strdup_printf ("%p", attachment);
+ can_use = g_strcmp0 (tmp, attachment_id) == 0;
+ g_free (tmp);
+
+ if (can_use) {
+ GtkTreeIter iter;
+
+ if (e_attachment_store_find_attachment_iter (attachment_store,
attachment, &iter)) {
+ GIcon *icon = NULL;
+
+ gtk_tree_model_get (GTK_TREE_MODEL (attachment_store), &iter,
+ E_ATTACHMENT_STORE_COLUMN_ICON, &icon,
+ -1);
+
+ if (icon) {
+ const gchar *size = g_hash_table_lookup (uri_query,
"size");
+ if (!size)
+ size = "16";
+
+ save_gicon_to_stream (icon, atoi (size),
output_stream, &use_mime_type);
+ }
+ }
+
+ break;
+ }
+ }
+
+ g_list_free_full (attachments, g_object_unref);
+ }
+
+ g_free (attachment_id);
+
+ goto no_part;
+ }
+
+ val = g_hash_table_lookup (uri_query, "part_id");
if (val != NULL) {
EMailPart *part;
const gchar *mime_type;
@@ -143,40 +232,20 @@ handle_mail_request (GSimpleAsyncResult *simple,
}
g_free (part_id);
- mime_type = g_hash_table_lookup (
- request->priv->uri_query, "mime_type");
+ mime_type = g_hash_table_lookup (uri_query, "mime_type");
if (context.mode == E_MAIL_FORMATTER_MODE_SOURCE)
mime_type = "application/vnd.evolution.source";
- if (context.mode == E_MAIL_FORMATTER_MODE_CID) {
- CamelDataWrapper *dw;
- CamelMimePart *mime_part;
-
- mime_part = e_mail_part_ref_mime_part (part);
- dw = camel_medium_get_content (CAMEL_MEDIUM (mime_part));
- g_return_if_fail (dw);
-
- if (!mime_type) {
- g_free (request->priv->mime_type);
- request->priv->mime_type = camel_data_wrapper_get_mime_type (dw);
- }
-
- camel_data_wrapper_decode_to_output_stream_sync (
- dw, output_stream, cancellable, NULL);
-
- g_object_unref (mime_part);
- } else {
- if (mime_type == NULL)
- mime_type = e_mail_part_get_mime_type (part);
+ if (mime_type == NULL)
+ mime_type = e_mail_part_get_mime_type (part);
- e_mail_formatter_format_as (
- formatter, &context, part,
- output_stream, mime_type,
- cancellable);
+ e_mail_formatter_format_as (
+ formatter, &context, part,
+ output_stream, mime_type,
+ cancellable);
- request->priv->part_converted_to_utf8 = e_mail_part_get_converted_to_utf8 (part);
- }
+ part_converted_to_utf8 = e_mail_part_get_converted_to_utf8 (part);
g_object_unref (part);
@@ -191,61 +260,54 @@ handle_mail_request (GSimpleAsyncResult *simple,
g_output_stream_close (output_stream, NULL, NULL);
- if (request->priv->bytes != NULL)
- g_bytes_unref (request->priv->bytes);
-
- request->priv->bytes = g_memory_output_stream_steal_as_bytes (
- G_MEMORY_OUTPUT_STREAM (output_stream));
+ bytes = g_memory_output_stream_steal_as_bytes (G_MEMORY_OUTPUT_STREAM (output_stream));
- if (g_bytes_get_size (request->priv->bytes) == 0) {
+ if (g_bytes_get_size (bytes) == 0) {
gchar *data;
- g_bytes_unref (request->priv->bytes);
+ g_bytes_unref (bytes);
data = g_strdup_printf (
"<p align='center'>%s</p>",
_("The message has no text content."));
/* Takes ownership of the string. */
- request->priv->bytes = g_bytes_new_take (
- data, strlen (data) + 1);
+ bytes = g_bytes_new_take (data, strlen (data) + 1);
}
- input_stream =
- g_memory_input_stream_new_from_bytes (request->priv->bytes);
+ if (!use_mime_type)
+ use_mime_type = g_strdup ("text/html");
- g_simple_async_result_set_op_res_gpointer (
- simple, g_object_ref (input_stream),
- (GDestroyNotify) g_object_unref);
+ if (part_converted_to_utf8 && g_strcmp0 (use_mime_type, "text/html") == 0) {
+ tmp = g_strconcat (use_mime_type, "; charset=\"UTF-8\"", NULL);
+ g_free (use_mime_type);
+ use_mime_type = tmp;
+ }
- g_object_unref (input_stream);
- g_object_unref (output_stream);
+ *out_stream = g_memory_input_stream_new_from_bytes (bytes);
+ *out_stream_length = g_bytes_get_size (bytes);
+ *out_mime_type = use_mime_type;
+ g_object_unref (output_stream);
g_object_unref (part_list);
g_object_unref (formatter);
-}
-
-static GInputStream *
-get_empty_image_stream (void)
-{
- GdkPixbuf *pixbuf;
- gchar *buffer;
- gsize length;
-
- pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, 1, 1);
- gdk_pixbuf_fill (pixbuf, 0x00000000); /* transparent black */
- gdk_pixbuf_save_to_buffer (pixbuf, &buffer, &length, "png", NULL, NULL);
- g_object_unref (pixbuf);
+ g_bytes_unref (bytes);
+ g_free (context.uri);
- return g_memory_input_stream_new_from_data (buffer, length, g_free);
+ return TRUE;
}
-static void
-handle_contact_photo_request (GSimpleAsyncResult *simple,
- GObject *object,
- GCancellable *cancellable)
+static gboolean
+mail_request_process_contact_photo_sync (EContentRequest *request,
+ SoupURI *suri,
+ GHashTable *uri_query,
+ GObject *requester,
+ GInputStream **out_stream,
+ gint64 *out_stream_length,
+ gchar **out_mime_type,
+ GCancellable *cancellable,
+ GError **error)
{
- EMailRequest *request = E_MAIL_REQUEST (object);
EShell *shell;
EShellBackend *shell_backend;
EMailBackend *mail_backend;
@@ -256,227 +318,188 @@ handle_contact_photo_request (GSimpleAsyncResult *simple,
const gchar *email_address;
const gchar *escaped_string;
gchar *unescaped_string;
- GError *error = NULL;
+ gboolean success = FALSE;
- /* XXX Is this really the only way to obtain
- * the mail session instance from here? */
shell = e_shell_get_default ();
shell_backend = e_shell_get_backend_by_name (shell, "mail");
mail_backend = E_MAIL_BACKEND (shell_backend);
mail_session = e_mail_backend_get_session (mail_backend);
- photo_cache = e_mail_ui_session_get_photo_cache (
- E_MAIL_UI_SESSION (mail_session));
+ photo_cache = e_mail_ui_session_get_photo_cache (E_MAIL_UI_SESSION (mail_session));
- request->priv->mime_type = g_strdup ("image/*");
+ escaped_string = g_hash_table_lookup (uri_query, "mailaddr");
+ if (escaped_string && *escaped_string) {
+ cia = camel_internet_address_new ();
- escaped_string = g_hash_table_lookup (
- request->priv->uri_query, "mailaddr");
- if (escaped_string == NULL || *escaped_string == '\0')
- goto exit;
+ unescaped_string = g_uri_unescape_string (escaped_string, NULL);
+ camel_address_decode (CAMEL_ADDRESS (cia), unescaped_string);
+ g_free (unescaped_string);
- cia = camel_internet_address_new ();
+ if (camel_internet_address_get (cia, 0, NULL, &email_address))
+ success = e_photo_cache_get_photo_sync (
+ photo_cache, email_address,
+ cancellable, &stream, error);
- unescaped_string = g_uri_unescape_string (escaped_string, NULL);
- camel_address_decode (CAMEL_ADDRESS (cia), unescaped_string);
- g_free (unescaped_string);
+ g_object_unref (cia);
- if (camel_internet_address_get (cia, 0, NULL, &email_address))
- e_photo_cache_get_photo_sync (
- photo_cache, email_address,
- cancellable, &stream, &error);
+ if (success) {
+ *out_stream = stream;
+ *out_stream_length = -1;
+ *out_mime_type = g_strdup ("image/*");
+ }
+ }
- g_object_unref (cia);
+ if (!success) {
+ GdkPixbuf *pixbuf;
+ gchar *buffer;
+ gsize length;
- /* Ignore cancellations. */
- if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
- g_clear_error (&error);
- } else if (error != NULL) {
- g_warning ("%s: %s", G_STRFUNC, error->message);
- g_clear_error (&error);
- }
+ g_clear_error (error);
-exit:
- if (stream == NULL)
- stream = get_empty_image_stream ();
+ /* Construct empty image stream, to not show "broken image" icon when no contact photo is
found */
+ pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, 1, 1);
+ gdk_pixbuf_fill (pixbuf, 0x00000000); /* transparent black */
+ gdk_pixbuf_save_to_buffer (pixbuf, &buffer, &length, "png", NULL, NULL);
+ g_object_unref (pixbuf);
- g_simple_async_result_set_op_res_gpointer (
- simple, g_object_ref (stream),
- (GDestroyNotify) g_object_unref);
+ *out_stream = g_memory_input_stream_new_from_data (buffer, length, g_free);
+ *out_stream_length = length;
+ *out_mime_type = g_strdup ("image/png");
+ }
- g_object_unref (stream);
+ return TRUE;
}
-static void
-mail_request_finalize (GObject *object)
+typedef struct _MailIdleData
{
- EMailRequestPrivate *priv;
+ EContentRequest *request;
+ SoupURI *suri;
+ GHashTable *uri_query;
+ GObject *requester;
+ GInputStream **out_stream;
+ gint64 *out_stream_length;
+ gchar **out_mime_type;
+ GCancellable *cancellable;
+ GError **error;
- priv = E_MAIL_REQUEST_GET_PRIVATE (object);
+ gboolean success;
+ EFlag *flag;
+} MailIdleData;
- if (priv->bytes != NULL)
- g_bytes_unref (priv->bytes);
+static gboolean
+process_mail_request_idle_cb (gpointer user_data)
+{
+ MailIdleData *mid = user_data;
- if (priv->uri_query != NULL)
- g_hash_table_destroy (priv->uri_query);
+ g_return_val_if_fail (mid != NULL, FALSE);
+ g_return_val_if_fail (E_IS_MAIL_REQUEST (mid->request), FALSE);
+ g_return_val_if_fail (mid->suri != NULL, FALSE);
+ g_return_val_if_fail (mid->flag != NULL, FALSE);
- g_free (priv->mime_type);
- g_free (priv->uri_base);
- g_free (priv->full_uri);
- g_free (priv->ret_mime_type);
+ mid->success = mail_request_process_mail_sync (mid->request,
+ mid->suri, mid->uri_query, mid->requester, mid->out_stream,
+ mid->out_stream_length, mid->out_mime_type,
+ mid->cancellable, mid->error);
- /* Chain up to parent's finalize() method. */
- G_OBJECT_CLASS (e_mail_request_parent_class)->finalize (object);
-}
+ e_flag_set (mid->flag);
-static gboolean
-mail_request_check_uri (SoupRequest *request,
- SoupURI *uri,
- GError **error)
-{
- return (strcmp (uri->scheme, "mail") == 0);
+ return FALSE;
}
-static void
-mail_request_send_async (SoupRequest *request,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
+static gboolean
+e_mail_request_process_sync (EContentRequest *request,
+ const gchar *uri,
+ GObject *requester,
+ GInputStream **out_stream,
+ gint64 *out_stream_length,
+ gchar **out_mime_type,
+ GCancellable *cancellable,
+ GError **error)
{
- EMailRequestPrivate *priv;
- GSimpleAsyncResult *simple;
- SoupURI *uri;
+ SoupURI *suri;
+ GHashTable *uri_query;
+ gboolean success = FALSE;
- priv = E_MAIL_REQUEST_GET_PRIVATE (request);
+ g_return_val_if_fail (E_IS_MAIL_REQUEST (request), FALSE);
+ g_return_val_if_fail (uri != NULL, FALSE);
- uri = soup_request_get_uri (request);
+ if (g_cancellable_set_error_if_cancelled (cancellable, error))
+ return FALSE;
- d (printf ("received request for %s\n", soup_uri_to_string (uri, FALSE)));
+ suri = soup_uri_new (uri);
+ g_return_val_if_fail (suri != NULL, FALSE);
- if (uri->query) {
- priv->uri_query = soup_form_decode (uri->query);
+ if (suri->query) {
+ uri_query = soup_form_decode (suri->query);
} else {
- priv->uri_query = NULL;
+ uri_query = NULL;
}
- priv->full_uri = soup_uri_to_string (uri, FALSE);
- priv->uri_base = g_strdup_printf (
- "%s://%s%s", uri->scheme, uri->host, uri->path);
-
- simple = g_simple_async_result_new (
- G_OBJECT (request), callback,
- user_data, mail_request_send_async);
-
- g_simple_async_result_set_check_cancellable (simple, cancellable);
-
- if (g_strcmp0 (uri->host, "contact-photo") == 0) {
- e_util_run_simple_async_result_in_thread (
- simple, handle_contact_photo_request,
- cancellable);
+ if (g_strcmp0 (suri->host, "contact-photo") == 0) {
+ success = mail_request_process_contact_photo_sync (request, suri, uri_query, requester,
+ out_stream, out_stream_length, out_mime_type, cancellable, error);
} else {
- /* Process e-mail mail requests in this thread, which should be
- * the main/UI thread, because any EMailFormatter can create
- * GtkWidget-s, or manipulate with them, which should be always
- * done in the main/UI thread. */
- handle_mail_request (simple, G_OBJECT (request), cancellable);
- g_simple_async_result_complete_in_idle (simple);
- }
-
- g_object_unref (simple);
-}
-
-static GInputStream *
-mail_request_send_finish (SoupRequest *request,
- GAsyncResult *result,
- GError **error)
-{
- GSimpleAsyncResult *simple;
- GInputStream *stream;
-
- simple = G_SIMPLE_ASYNC_RESULT (result);
- stream = g_simple_async_result_get_op_res_gpointer (simple);
+ MailIdleData mid;
+
+ mid.request = request;
+ mid.suri = suri;
+ mid.uri_query = uri_query;
+ mid.requester = requester;
+ mid.out_stream = out_stream;
+ mid.out_stream_length = out_stream_length;
+ mid.out_mime_type = out_mime_type;
+ mid.cancellable = cancellable;
+ mid.error = error;
+ mid.flag = e_flag_new ();
+ mid.success = FALSE;
+
+ if (e_util_is_main_thread (NULL)) {
+ process_mail_request_idle_cb (&mid);
+ } else {
+ /* Process e-mail mail requests in the main/UI thread, because
+ * any EMailFormatter can create GtkWidget-s, or manipulate with
+ * them, which should be always done in the main/UI thread. */
+ g_idle_add_full (
+ G_PRIORITY_HIGH_IDLE,
+ process_mail_request_idle_cb,
+ &mid, NULL);
+
+ e_flag_wait (mid.flag);
+ }
- /* Reset the stream before passing it back to webkit */
- if (G_IS_SEEKABLE (stream))
- g_seekable_seek (
- G_SEEKABLE (stream), 0, G_SEEK_SET, NULL, NULL);
+ e_flag_free (mid.flag);
- if (stream == NULL) {
- /* We must always return something */
- stream = g_memory_input_stream_new ();
- } else {
- g_object_ref (stream);
+ success = mid.success;
}
- return stream;
-}
-
-static goffset
-mail_request_get_content_length (SoupRequest *request)
-{
- EMailRequestPrivate *priv;
- goffset content_length = -1; /* -1 means unknown */
+ if (uri_query)
+ g_hash_table_destroy (uri_query);
+ soup_uri_free (suri);
- priv = E_MAIL_REQUEST_GET_PRIVATE (request);
-
- if (priv->bytes != NULL)
- content_length = g_bytes_get_size (priv->bytes);
-
- return content_length;
+ return success;
}
-static const gchar *
-mail_request_get_content_type (SoupRequest *request)
+static void
+e_mail_request_content_request_init (EContentRequestInterface *iface)
{
- EMailRequestPrivate *priv;
- gchar *mime_type;
-
- priv = E_MAIL_REQUEST_GET_PRIVATE (request);
-
- if (priv->mime_type != NULL) {
- mime_type = g_strdup (priv->mime_type);
- } else {
- mime_type = g_strdup ("text/html");
- }
-
- if (g_strcmp0 (mime_type, "text/html") == 0 &&
- priv->part_converted_to_utf8) {
- priv->ret_mime_type = g_strconcat (
- mime_type, "; charset=\"UTF-8\"", NULL);
- g_free (mime_type);
- } else {
- priv->ret_mime_type = mime_type;
- }
-
- d (printf ("Content-Type: %s\n", priv->ret_mime_type));
-
- return priv->ret_mime_type;
+ iface->can_process_uri = e_mail_request_can_process_uri;
+ iface->process_sync = e_mail_request_process_sync;
}
static void
e_mail_request_class_init (EMailRequestClass *class)
{
- GObjectClass *object_class;
- SoupRequestClass *request_class;
-
g_type_class_add_private (class, sizeof (EMailRequestPrivate));
-
- object_class = G_OBJECT_CLASS (class);
- object_class->finalize = mail_request_finalize;
-
- request_class = SOUP_REQUEST_CLASS (class);
- request_class->schemes = data_schemes;
- request_class->send_async = mail_request_send_async;
- request_class->send_finish = mail_request_send_finish;
- request_class->get_content_type = mail_request_get_content_type;
- request_class->get_content_length = mail_request_get_content_length;
- request_class->check_uri = mail_request_check_uri;
}
static void
e_mail_request_init (EMailRequest *request)
{
- request->priv = E_MAIL_REQUEST_GET_PRIVATE (request);
- request->priv->part_converted_to_utf8 = FALSE;
+ request->priv = G_TYPE_INSTANCE_GET_PRIVATE (request, E_TYPE_MAIL_REQUEST, EMailRequestPrivate);
}
+EContentRequest *
+e_mail_request_new (void)
+{
+ return g_object_new (E_TYPE_MAIL_REQUEST, NULL);
+}
diff --git a/mail/e-mail-request.h b/mail/e-mail-request.h
index c85266e..cd35992 100644
--- a/mail/e-mail-request.h
+++ b/mail/e-mail-request.h
@@ -18,10 +18,7 @@
#ifndef E_MAIL_REQUEST_H
#define E_MAIL_REQUEST_H
-#define LIBSOUP_USE_UNSTABLE_REQUEST_API
-
-#include <libsoup/soup.h>
-#include <libsoup/soup-request.h>
+#include <e-util/e-util.h>
/* Standard GObject macros */
#define E_TYPE_MAIL_REQUEST \
@@ -49,15 +46,17 @@ typedef struct _EMailRequestClass EMailRequestClass;
typedef struct _EMailRequestPrivate EMailRequestPrivate;
struct _EMailRequest {
- SoupRequest parent;
+ GObject parent;
EMailRequestPrivate *priv;
};
struct _EMailRequestClass {
- SoupRequestClass parent;
+ GObjectClass parent;
};
GType e_mail_request_get_type (void) G_GNUC_CONST;
+EContentRequest *
+ e_mail_request_new (void);
G_END_DECLS
diff --git a/mail/em-composer-utils.c b/mail/em-composer-utils.c
index a983db5..2a68541 100644
--- a/mail/em-composer-utils.c
+++ b/mail/em-composer-utils.c
@@ -534,7 +534,7 @@ composer_presend_check_unwanted_html (EMsgComposer *composer,
{
EDestination **recipients;
EHTMLEditor *editor;
- EHTMLEditorView *view;
+ EContentEditor *cnt_editor;
EComposerHeaderTable *table;
GSettings *settings;
gboolean check_passed = TRUE;
@@ -546,8 +546,8 @@ composer_presend_check_unwanted_html (EMsgComposer *composer,
settings = e_util_ref_settings ("org.gnome.evolution.mail");
editor = e_msg_composer_get_editor (composer);
- view = e_html_editor_get_view (editor);
- html_mode = e_html_editor_view_get_html_mode (view);
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ html_mode = e_content_editor_get_html_mode (cnt_editor);
table = e_msg_composer_get_header_table (composer);
recipients = e_composer_header_table_get_destinations (table);
@@ -681,11 +681,12 @@ exit:
if (set_changed) {
EHTMLEditor *editor;
- EHTMLEditorView *view;
+ EContentEditor *cnt_editor;
editor = e_msg_composer_get_editor (async_context->composer);
- view = e_html_editor_get_view (editor);
- e_html_editor_view_set_changed (view, TRUE);
+ cnt_editor = e_html_editor_get_content_editor (editor);
+
+ e_content_editor_set_changed (cnt_editor, TRUE);
gtk_window_present (GTK_WINDOW (async_context->composer));
}
@@ -800,14 +801,14 @@ static void
composer_set_no_change (EMsgComposer *composer)
{
EHTMLEditor *editor;
- EHTMLEditorView *view;
+ EContentEditor *cnt_editor;
g_return_if_fail (composer != NULL);
editor = e_msg_composer_get_editor (composer);
- view = e_html_editor_get_view (editor);
+ cnt_editor = e_html_editor_get_content_editor (editor);
- e_html_editor_view_set_changed (view, FALSE);
+ e_content_editor_set_changed (cnt_editor, FALSE);
}
/* delete original messages from Outbox folder */
@@ -853,13 +854,13 @@ composer_save_to_drafts_complete (GObject *source_object,
EActivity *activity;
AsyncContext *async_context;
EHTMLEditor *editor;
- EHTMLEditorView *view;
+ EContentEditor *cnt_editor;
GError *local_error = NULL;
async_context = (AsyncContext *) user_data;
editor = e_msg_composer_get_editor (async_context->composer);
- view = e_html_editor_get_view (editor);
+ cnt_editor = e_html_editor_get_content_editor (editor);
/* We don't really care if this failed. If something other than
* cancellation happened, emit a runtime warning so the error is
@@ -870,14 +871,13 @@ composer_save_to_drafts_complete (GObject *source_object,
activity = async_context->activity;
if (e_activity_handle_cancellation (activity, local_error)) {
- e_html_editor_view_set_changed (view, TRUE);
+ e_content_editor_set_changed (cnt_editor, TRUE);
g_error_free (local_error);
} else if (local_error != NULL) {
- e_html_editor_view_set_changed (view, TRUE);
+ e_content_editor_set_changed (cnt_editor, TRUE);
g_warning ("%s", local_error->message);
g_error_free (local_error);
-
} else
e_activity_set_state (activity, E_ACTIVITY_COMPLETED);
@@ -907,14 +907,14 @@ composer_save_to_drafts_cleanup (GObject *source_object,
EAlertSink *alert_sink;
GCancellable *cancellable;
EHTMLEditor *editor;
- EHTMLEditorView *view;
+ EContentEditor *cnt_editor;
AsyncContext *async_context;
GError *local_error = NULL;
async_context = (AsyncContext *) user_data;
editor = e_msg_composer_get_editor (async_context->composer);
- view = e_html_editor_get_view (editor);
+ cnt_editor = e_html_editor_get_content_editor (editor);
activity = async_context->activity;
alert_sink = e_activity_get_alert_sink (activity);
@@ -926,7 +926,7 @@ composer_save_to_drafts_cleanup (GObject *source_object,
if (e_activity_handle_cancellation (activity, local_error)) {
g_warn_if_fail (async_context->message_uid == NULL);
- e_html_editor_view_set_changed (view, TRUE);
+ e_content_editor_set_changed (cnt_editor, TRUE);
async_context_free (async_context);
g_error_free (local_error);
return;
@@ -944,7 +944,7 @@ composer_save_to_drafts_cleanup (GObject *source_object,
GTK_WINDOW (async_context->composer),
"mail:ask-default-drafts", local_error->message, NULL);
if (response != GTK_RESPONSE_YES) {
- e_html_editor_view_set_changed (view, TRUE);
+ e_content_editor_set_changed (cnt_editor, TRUE);
async_context_free (async_context);
} else {
composer_save_to_drafts_append_mail (async_context, NULL);
@@ -958,7 +958,7 @@ composer_save_to_drafts_cleanup (GObject *source_object,
alert_sink,
"mail-composer:save-to-drafts-error",
local_error->message, NULL);
- e_html_editor_view_set_changed (view, TRUE);
+ e_content_editor_set_changed (cnt_editor, TRUE);
async_context_free (async_context);
g_error_free (local_error);
return;
@@ -1023,7 +1023,7 @@ composer_save_to_drafts_got_folder (GObject *source_object,
EActivity *activity;
CamelFolder *drafts_folder;
EHTMLEditor *editor;
- EHTMLEditorView *view;
+ EContentEditor *cnt_editor;
AsyncContext *async_context;
GError *local_error = NULL;
@@ -1032,7 +1032,7 @@ composer_save_to_drafts_got_folder (GObject *source_object,
activity = async_context->activity;
editor = e_msg_composer_get_editor (async_context->composer);
- view = e_html_editor_get_view (editor);
+ cnt_editor = e_html_editor_get_content_editor (editor);
drafts_folder = e_mail_session_uri_to_folder_finish (
E_MAIL_SESSION (source_object), result, &local_error);
@@ -1043,7 +1043,7 @@ composer_save_to_drafts_got_folder (GObject *source_object,
((drafts_folder == NULL) && (local_error != NULL)));
if (e_activity_handle_cancellation (activity, local_error)) {
- e_html_editor_view_set_changed (view, TRUE);
+ e_content_editor_set_changed (cnt_editor, TRUE);
async_context_free (async_context);
g_error_free (local_error);
return;
@@ -1061,7 +1061,7 @@ composer_save_to_drafts_got_folder (GObject *source_object,
g_error_free (local_error);
if (response != GTK_RESPONSE_YES) {
- e_html_editor_view_set_changed (view, TRUE);
+ e_content_editor_set_changed (cnt_editor, TRUE);
async_context_free (async_context);
return;
}
@@ -1316,20 +1316,17 @@ em_utils_composer_print_cb (EMsgComposer *composer,
/* Composing messages... */
-static EMsgComposer *
-create_new_composer (EShell *shell,
- const gchar *subject,
- CamelFolder *folder)
+static void
+set_up_new_composer (EMsgComposer *composer,
+ const gchar *subject,
+ CamelFolder *folder)
{
- EMsgComposer *composer;
EClientCache *client_cache;
ESourceRegistry *registry;
EComposerHeaderTable *table;
ESource *source = NULL;
gchar *identity = NULL;
- composer = e_msg_composer_new (shell);
-
table = e_msg_composer_get_header_table (composer);
client_cache = e_composer_header_table_ref_client_cache (table);
@@ -1360,50 +1357,36 @@ create_new_composer (EShell *shell,
e_composer_header_table_set_subject (table, subject);
e_composer_header_table_set_identity_uid (table, identity);
- em_utils_apply_send_account_override_to_composer (composer, shell, folder);
+ em_utils_apply_send_account_override_to_composer (composer, folder);
g_free (identity);
g_object_unref (client_cache);
g_object_unref (registry);
-
- return composer;
}
/**
* em_utils_compose_new_message:
- * @shell: an #EShell
- * @folder: a #CamelFolder, or %NULL
+ * @composer: an #EMsgComposer
+ * @folder: (nullable): a #CamelFolder, or %NULL
*
- * Opens a new composer window as a child window of @parent's toplevel
- * window.
+ * Sets up a new @composer window.
*
- * Returns: the resulting #EMsgComposer
+ * Since: 3.22
**/
-EMsgComposer *
-em_utils_compose_new_message (EShell *shell,
+void
+em_utils_compose_new_message (EMsgComposer *composer,
CamelFolder *folder)
{
- EMsgComposer *composer;
- EHTMLEditor *editor;
- EHTMLEditorView *view;
-
- g_return_val_if_fail (E_IS_SHELL (shell), NULL);
+ g_return_if_fail (E_IS_MSG_COMPOSER (composer));
if (folder != NULL)
- g_return_val_if_fail (CAMEL_IS_FOLDER (folder), NULL);
+ g_return_if_fail (CAMEL_IS_FOLDER (folder));
- composer = create_new_composer (shell, "", folder);
+ set_up_new_composer (composer, "", folder);
composer_set_no_change (composer);
- editor = e_msg_composer_get_editor (composer);
- view = e_html_editor_get_view (editor);
-
- e_html_editor_view_set_content_is_new_message (view, TRUE);
-
gtk_widget_show (GTK_WIDGET (composer));
-
- return composer;
}
static CamelMimeMessage *
@@ -1483,37 +1466,50 @@ em_utils_get_composer_recipients_as_message (EMsgComposer *composer)
return message;
}
-/**
- * em_utils_compose_new_message_with_mailto:
- * @shell: an #EShell
- * @mailto: a mailto URL
- * @folder: a #CamelFolder, or %NULL
- *
- * Opens a new composer window as a child window of @parent's toplevel
- * window. If @mailto is non-NULL, the composer fields will be filled in
- * according to the values in the mailto URL.
- **/
-EMsgComposer *
-em_utils_compose_new_message_with_mailto (EShell *shell,
- const gchar *mailto,
- CamelFolder *folder)
+typedef struct _CreateComposerData {
+ gchar *mailto;
+ CamelFolder *folder;
+} CreateComposerData;
+
+static void
+create_composer_data_free (gpointer ptr)
+{
+ CreateComposerData *ccd = ptr;
+
+ if (ccd) {
+ g_clear_object (&ccd->folder);
+ g_free (ccd->mailto);
+ g_free (ccd);
+ }
+}
+
+static void
+msg_composer_created_with_mailto_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
{
+ CreateComposerData *ccd = user_data;
EMsgComposer *composer;
EComposerHeaderTable *table;
EClientCache *client_cache;
ESourceRegistry *registry;
+ GError *error = NULL;
- g_return_val_if_fail (E_IS_SHELL (shell), NULL);
+ g_return_if_fail (ccd != NULL);
- if (folder != NULL)
- g_return_val_if_fail (CAMEL_IS_FOLDER (folder), NULL);
+ composer = e_msg_composer_new_finish (result, &error);
+ if (error) {
+ g_warning ("%s: Failed to create msg composer: %s", G_STRFUNC, error->message);
+ g_clear_error (&error);
+ create_composer_data_free (ccd);
- if (mailto != NULL)
- composer = e_msg_composer_new_from_url (shell, mailto);
- else
- composer = e_msg_composer_new (shell);
+ return;
+ }
+
+ if (ccd->mailto)
+ e_msg_composer_setup_from_url (composer, ccd->mailto);
- em_utils_apply_send_account_override_to_composer (composer, shell, folder);
+ em_utils_apply_send_account_override_to_composer (composer, ccd->folder);
table = e_msg_composer_get_header_table (composer);
@@ -1525,11 +1521,11 @@ em_utils_compose_new_message_with_mailto (EShell *shell,
/* If a CamelFolder was given, we need to backtrack and find
* the corresponding ESource with a Mail Identity extension. */
- if (folder != NULL) {
+ if (ccd->folder) {
ESource *source;
CamelStore *store;
- store = camel_folder_get_parent_store (folder);
+ store = camel_folder_get_parent_store (ccd->folder);
source = em_utils_ref_mail_identity_for_store (registry, store);
if (source != NULL) {
@@ -1544,7 +1540,36 @@ em_utils_compose_new_message_with_mailto (EShell *shell,
gtk_window_present (GTK_WINDOW (composer));
- return composer;
+ create_composer_data_free (ccd);
+}
+
+/**
+ * em_utils_compose_new_message_with_mailto:
+ * @shell: an #EShell
+ * @mailto: a mailto URL
+ * @folder: a #CamelFolder, or %NULL
+ *
+ * Opens a new composer window as a child window of @parent's toplevel
+ * window. If @mailto is non-NULL, the composer fields will be filled in
+ * according to the values in the mailto URL.
+ **/
+void
+em_utils_compose_new_message_with_mailto (EShell *shell,
+ const gchar *mailto,
+ CamelFolder *folder)
+{
+ CreateComposerData *ccd;
+
+ g_return_if_fail (E_IS_SHELL (shell));
+
+ if (folder != NULL)
+ g_return_if_fail (CAMEL_IS_FOLDER (folder));
+
+ ccd = g_new0 (CreateComposerData, 1);
+ ccd->folder = folder ? g_object_ref (folder) : NULL;
+ ccd->mailto = g_strdup (mailto);
+
+ e_msg_composer_new (shell, msg_composer_created_with_mailto_cb, ccd);
}
static gboolean
@@ -1749,22 +1774,22 @@ quoting_text (QuotingTextEnum type)
/**
* em_utils_edit_message:
- * @shell: an #EShell
+ * @composer: an #EMsgComposer
* @folder: a #CamelFolder
* @message: a #CamelMimeMessage
* @message_uid: UID of @message, or %NULL
*
- * Opens a composer filled in with the headers/mime-parts/etc of
- * @message.
+ * Sets up the @composer with the headers/mime-parts/etc of the @message.
+ *
+ * Since: 3.22
**/
-EMsgComposer *
-em_utils_edit_message (EShell *shell,
+void
+em_utils_edit_message (EMsgComposer *composer,
CamelFolder *folder,
CamelMimeMessage *message,
const gchar *message_uid,
gboolean keep_signature)
{
- EMsgComposer *composer;
ESourceRegistry *registry;
ESource *source;
gboolean folder_is_sent;
@@ -1773,12 +1798,12 @@ em_utils_edit_message (EShell *shell,
gboolean folder_is_templates;
gchar *override_identity_uid = NULL;
- g_return_val_if_fail (E_IS_SHELL (shell), NULL);
- g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), NULL);
+ g_return_if_fail (E_IS_MSG_COMPOSER (composer));
+ g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message));
if (folder)
- g_return_val_if_fail (CAMEL_IS_FOLDER (folder), NULL);
+ g_return_if_fail (CAMEL_IS_FOLDER (folder));
- registry = e_shell_get_registry (shell);
+ registry = e_shell_get_registry (e_msg_composer_get_shell (composer));
if (folder) {
folder_is_sent = em_utils_folder_is_sent (registry, folder);
@@ -1830,7 +1855,7 @@ em_utils_edit_message (EShell *shell,
}
}
- source = em_utils_check_send_account_override (shell, message, folder);
+ source = em_utils_check_send_account_override (e_msg_composer_get_shell (composer), message,
folder);
if (source) {
g_free (override_identity_uid);
override_identity_uid = e_source_dup_uid (source);
@@ -1838,7 +1863,7 @@ em_utils_edit_message (EShell *shell,
}
}
- composer = e_msg_composer_new_with_message (shell, message, keep_signature, override_identity_uid,
NULL);
+ e_msg_composer_setup_with_message (composer, message, keep_signature, override_identity_uid, NULL);
g_free (override_identity_uid);
@@ -1881,8 +1906,6 @@ em_utils_edit_message (EShell *shell,
composer_set_no_change (composer);
gtk_widget_show (GTK_WIDGET (composer));
-
- return composer;
}
static void
@@ -2098,39 +2121,36 @@ setup_forward_attached_callbacks (EMsgComposer *composer,
(GDestroyNotify) forward_data_free);
}
-static EMsgComposer *
-forward_non_attached (EMailBackend *backend,
+static void
+forward_non_attached (EMsgComposer *composer,
CamelFolder *folder,
const gchar *uid,
CamelMimeMessage *message,
EMailForwardStyle style)
{
- EMsgComposer *composer = NULL;
- EMailSession *session;
- EShell *shell;
+ CamelSession *session;
gchar *text, *forward;
guint32 validity_found = 0;
guint32 flags;
+ g_return_if_fail (E_IS_MSG_COMPOSER (composer));
+
+ session = e_msg_composer_ref_session (composer);
+
flags = E_MAIL_FORMATTER_QUOTE_FLAG_HEADERS |
E_MAIL_FORMATTER_QUOTE_FLAG_KEEP_SIG;
if (style == E_MAIL_FORWARD_STYLE_QUOTED)
flags |= E_MAIL_FORMATTER_QUOTE_FLAG_CITE;
- session = e_mail_backend_get_session (backend);
- shell = e_shell_backend_get_shell (E_SHELL_BACKEND (backend));
-
forward = quoting_text (QUOTING_FORWARD);
- text = em_utils_message_to_html (
- CAMEL_SESSION (session), message,
- forward, flags, NULL, NULL, NULL, &validity_found);
+ text = em_utils_message_to_html (session, message, forward, flags, NULL, NULL, NULL, &validity_found);
if (text != NULL) {
CamelDataWrapper *content;
gchar *subject;
subject = mail_tool_generate_forward_subject (message);
- composer = create_new_composer (shell, subject, folder);
+ set_up_new_composer (composer, subject, folder);
g_free (subject);
content = camel_medium_get_content (CAMEL_MEDIUM (message));
@@ -2157,26 +2177,24 @@ forward_non_attached (EMailBackend *backend,
g_free (tmp_message_uid);
}
- emu_update_composers_security (
- composer, validity_found);
+ emu_update_composers_security (composer, validity_found);
composer_set_no_change (composer);
gtk_widget_show (GTK_WIDGET (composer));
g_free (text);
}
+ g_clear_object (&session);
g_free (forward);
-
- return composer;
}
/**
* em_utils_forward_message:
- * @backend: an #EMailBackend
+ * @composer: an #EMsgComposer
* @message: a #CamelMimeMessage to forward
* @style: the forward style to use
- * @folder: a #CamelFolder, or %NULL
- * @uid: the UID of %message, or %NULL
+ * @folder: (nullable): a #CamelFolder, or %NULL
+ * @uid: (nullable): the UID of %message, or %NULL
*
* Forwards @message in the given @style.
*
@@ -2194,8 +2212,8 @@ forward_non_attached (EMailBackend *backend,
* in its own composer window in 'quoted' form (each line starting with
* a "> ").
**/
-EMsgComposer *
-em_utils_forward_message (EMailBackend *backend,
+void
+em_utils_forward_message (EMsgComposer *composer,
CamelMimeMessage *message,
EMailForwardStyle style,
CamelFolder *folder,
@@ -2203,10 +2221,9 @@ em_utils_forward_message (EMailBackend *backend,
{
CamelMimePart *part;
gchar *subject;
- EMsgComposer *composer = NULL;
- g_return_val_if_fail (E_IS_MAIL_BACKEND (backend), NULL);
- g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), NULL);
+ g_return_if_fail (E_IS_MSG_COMPOSER (composer));
+ g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message));
switch (style) {
case E_MAIL_FORWARD_STYLE_ATTACHED:
@@ -2214,8 +2231,7 @@ em_utils_forward_message (EMailBackend *backend,
part = mail_tool_make_message_attachment (message);
subject = mail_tool_generate_forward_subject (message);
- composer = em_utils_forward_attachment (
- backend, part, subject, NULL, NULL);
+ em_utils_forward_attachment (composer, part, subject, NULL, NULL);
g_object_unref (part);
g_free (subject);
@@ -2223,34 +2239,27 @@ em_utils_forward_message (EMailBackend *backend,
case E_MAIL_FORWARD_STYLE_INLINE:
case E_MAIL_FORWARD_STYLE_QUOTED:
- composer = forward_non_attached (
- backend, folder, uid, message, style);
+ forward_non_attached (composer, folder, uid, message, style);
break;
}
-
- return composer;
}
-EMsgComposer *
-em_utils_forward_attachment (EMailBackend *backend,
+void
+em_utils_forward_attachment (EMsgComposer *composer,
CamelMimePart *part,
const gchar *subject,
CamelFolder *folder,
GPtrArray *uids)
{
- EShell *shell;
CamelDataWrapper *content;
- EMsgComposer *composer;
- g_return_val_if_fail (E_IS_MAIL_BACKEND (backend), NULL);
- g_return_val_if_fail (CAMEL_IS_MIME_PART (part), NULL);
+ g_return_if_fail (E_IS_MSG_COMPOSER (composer));
+ g_return_if_fail (CAMEL_IS_MIME_PART (part));
if (folder != NULL)
- g_return_val_if_fail (CAMEL_IS_FOLDER (folder), NULL);
-
- shell = e_shell_backend_get_shell (E_SHELL_BACKEND (backend));
+ g_return_if_fail (CAMEL_IS_FOLDER (folder));
- composer = create_new_composer (shell, subject, folder);
+ set_up_new_composer (composer, subject, folder);
e_msg_composer_attach (composer, part);
@@ -2291,8 +2300,6 @@ em_utils_forward_attachment (EMailBackend *backend,
composer_set_no_change (composer);
gtk_widget_show (GTK_WIDGET (composer));
-
- return composer;
}
static gint
@@ -2368,18 +2375,30 @@ sort_sources_by_ui (GList **psources,
g_hash_table_destroy (uids_order);
}
-/* Redirecting messages... */
-
-static EMsgComposer *
-redirect_get_composer (EShell *shell,
- CamelMimeMessage *message)
+/**
+ * em_utils_redirect_message:
+ * @composer: an #EMsgComposer
+ * @message: message to redirect
+ *
+ * Sets up the @composer to redirect @message (Note: only headers will be
+ * editable). Adds Resent-From/Resent-To/etc headers.
+ *
+ * Since: 3.22
+ **/
+void
+em_utils_redirect_message (EMsgComposer *composer,
+ CamelMimeMessage *message)
{
- EMsgComposer *composer;
ESourceRegistry *registry;
- CamelMedium *medium;
ESource *source;
+ EShell *shell;
+ CamelMedium *medium;
gchar *identity_uid = NULL;
+ g_return_if_fail (E_IS_MSG_COMPOSER (composer));
+ g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message));
+
+ shell = e_msg_composer_get_shell (composer);
medium = CAMEL_MEDIUM (message);
/* QMail will refuse to send a message if it finds one of
@@ -2407,40 +2426,13 @@ redirect_get_composer (EShell *shell,
g_object_unref (source);
}
- composer = e_msg_composer_new_redirect (
- shell, message, identity_uid, NULL);
+ e_msg_composer_setup_redirect (composer, message, identity_uid, NULL);
g_free (identity_uid);
- return composer;
-}
-
-/**
- * em_utils_redirect_message:
- * @shell: an #EShell
- * @message: message to redirect
- *
- * Opens a composer to redirect @message (Note: only headers will be
- * editable). Adds Resent-From/Resent-To/etc headers.
- *
- * Returns: the resulting #EMsgComposer
- **/
-EMsgComposer *
-em_utils_redirect_message (EShell *shell,
- CamelMimeMessage *message)
-{
- EMsgComposer *composer;
-
- g_return_val_if_fail (E_IS_SHELL (shell), NULL);
- g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), NULL);
-
- composer = redirect_get_composer (shell, message);
-
gtk_widget_show (GTK_WIDGET (composer));
composer_set_no_change (composer);
-
- return composer;
}
/* Replying to messages... */
@@ -2480,33 +2472,30 @@ em_utils_camel_address_to_destination (CamelInternetAddress *iaddr)
return destv;
}
-static EMsgComposer *
-reply_get_composer (EShell *shell,
- CamelMimeMessage *message,
- const gchar *identity_uid,
- CamelInternetAddress *to,
- CamelInternetAddress *cc,
- CamelFolder *folder,
- const gchar *message_uid,
- CamelNNTPAddress *postto)
+static void
+reply_setup_composer (EMsgComposer *composer,
+ CamelMimeMessage *message,
+ const gchar *identity_uid,
+ CamelInternetAddress *to,
+ CamelInternetAddress *cc,
+ CamelFolder *folder,
+ const gchar *message_uid,
+ CamelNNTPAddress *postto)
{
gchar *message_id, *references;
EDestination **tov, **ccv;
- EMsgComposer *composer;
EComposerHeaderTable *table;
CamelMedium *medium;
gchar *subject;
- g_return_val_if_fail (E_IS_SHELL (shell), NULL);
- g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), NULL);
+ g_return_if_fail (E_IS_MSG_COMPOSER (composer));
+ g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message));
if (to != NULL)
- g_return_val_if_fail (CAMEL_IS_INTERNET_ADDRESS (to), NULL);
+ g_return_if_fail (CAMEL_IS_INTERNET_ADDRESS (to));
if (cc != NULL)
- g_return_val_if_fail (CAMEL_IS_INTERNET_ADDRESS (cc), NULL);
-
- composer = e_msg_composer_new (shell);
+ g_return_if_fail (CAMEL_IS_INTERNET_ADDRESS (cc));
/* construct the tov/ccv */
tov = em_utils_camel_address_to_destination (to);
@@ -2605,8 +2594,6 @@ reply_get_composer (EShell *shell,
g_free (message_id);
g_free (references);
-
- return composer;
}
static gboolean
@@ -3327,8 +3314,8 @@ emcu_folder_is_inbox (CamelFolder *folder)
* @folder and @message_uid may be supplied in order to update the message
* flags once it has been replied to.
**/
-EMsgComposer *
-em_utils_reply_to_message (EShell *shell,
+void
+em_utils_reply_to_message (EMsgComposer *composer,
CamelMimeMessage *message,
CamelFolder *folder,
const gchar *message_uid,
@@ -3340,19 +3327,19 @@ em_utils_reply_to_message (EShell *shell,
ESourceRegistry *registry;
CamelInternetAddress *to, *cc;
CamelNNTPAddress *postto = NULL;
- EMsgComposer *composer;
+ EShell *shell;
ESourceMailCompositionReplyStyle prefer_reply_style = E_SOURCE_MAIL_COMPOSITION_REPLY_STYLE_DEFAULT;
ESource *source;
gchar *identity_uid = NULL;
- const gchar *evo_source_header;
guint32 flags;
- g_return_val_if_fail (E_IS_SHELL (shell), NULL);
- g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), NULL);
+ g_return_if_fail (E_IS_MSG_COMPOSER (composer));
+ g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message));
to = camel_internet_address_new ();
cc = camel_internet_address_new ();
+ shell = e_msg_composer_get_shell (composer);
registry = e_shell_get_registry (shell);
/* This returns a new ESource reference. */
@@ -3411,8 +3398,7 @@ em_utils_reply_to_message (EShell *shell,
break;
}
- composer = reply_get_composer (
- shell, message, identity_uid, to, cc, folder, message_uid, postto);
+ reply_setup_composer (composer, message, identity_uid, to, cc, folder, message_uid, postto);
e_msg_composer_add_message_attachments (composer, message, TRUE);
if (postto)
@@ -3420,18 +3406,6 @@ em_utils_reply_to_message (EShell *shell,
g_object_unref (to);
g_object_unref (cc);
- evo_source_header = camel_medium_get_header (
- CAMEL_MEDIUM (message), "X-Evolution-Content-Source");
- if (g_strcmp0 (evo_source_header, "selection") == 0) {
- EHTMLEditor *editor;
- EHTMLEditorView *view;
-
- editor = e_msg_composer_get_editor (composer);
- view = e_html_editor_get_view (editor);
-
- e_html_editor_view_set_is_message_from_selection (view, TRUE);
- }
-
/* If there was no send-account override */
if (!identity_uid) {
EComposerHeaderTable *header_table;
@@ -3488,15 +3462,13 @@ em_utils_reply_to_message (EShell *shell,
}
/* because some reply types can change recipients after the composer is populated */
- em_utils_apply_send_account_override_to_composer (composer, shell, folder);
+ em_utils_apply_send_account_override_to_composer (composer, folder);
composer_set_no_change (composer);
gtk_widget_show (GTK_WIDGET (composer));
g_free (identity_uid);
-
- return composer;
}
static void
@@ -3684,15 +3656,16 @@ em_utils_check_send_account_override (EShell *shell,
void
em_utils_apply_send_account_override_to_composer (EMsgComposer *composer,
- EShell *shell,
CamelFolder *folder)
{
CamelMimeMessage *message;
EComposerHeaderTable *header_table;
+ EShell *shell;
ESource *source;
g_return_if_fail (E_IS_MSG_COMPOSER (composer));
+ shell = e_msg_composer_get_shell (composer);
message = em_utils_get_composer_recipients_as_message (composer);
source = em_utils_check_send_account_override (shell, message, folder);
g_clear_object (&message);
diff --git a/mail/em-composer-utils.h b/mail/em-composer-utils.h
index fc5c0aa..891f68a 100644
--- a/mail/em-composer-utils.h
+++ b/mail/em-composer-utils.h
@@ -33,28 +33,28 @@
G_BEGIN_DECLS
-EMsgComposer * em_utils_compose_new_message (EShell *shell,
+void em_utils_compose_new_message (EMsgComposer *composer,
CamelFolder *folder);
-EMsgComposer * em_utils_compose_new_message_with_mailto
+void em_utils_compose_new_message_with_mailto
(EShell *shell,
const gchar *mailto,
CamelFolder *folder);
-EMsgComposer * em_utils_edit_message (EShell *shell,
+void em_utils_edit_message (EMsgComposer *composer,
CamelFolder *folder,
CamelMimeMessage *message,
const gchar *message_uid,
gboolean keep_signature);
-EMsgComposer * em_utils_forward_message (EMailBackend *backend,
+void em_utils_forward_message (EMsgComposer *composer,
CamelMimeMessage *message,
EMailForwardStyle style,
CamelFolder *folder,
const gchar *uid);
-EMsgComposer * em_utils_forward_attachment (EMailBackend *backend,
+void em_utils_forward_attachment (EMsgComposer *composer,
CamelMimePart *part,
const gchar *subject,
CamelFolder *folder,
GPtrArray *uids);
-EMsgComposer * em_utils_redirect_message (EShell *shell,
+void em_utils_redirect_message (EMsgComposer *composer,
CamelMimeMessage *message);
gchar * em_utils_construct_composer_text
(CamelSession *session,
@@ -69,7 +69,7 @@ void em_utils_get_reply_all (ESourceRegistry *registry,
CamelInternetAddress *to,
CamelInternetAddress *cc,
CamelNNTPAddress *postto);
-EMsgComposer * em_utils_reply_to_message (EShell *shell,
+void em_utils_reply_to_message (EMsgComposer *composer,
CamelMimeMessage *message,
CamelFolder *folder,
const gchar *message_uid,
@@ -92,7 +92,6 @@ ESource * em_utils_check_send_account_override
CamelFolder *folder);
void em_utils_apply_send_account_override_to_composer
(EMsgComposer *composer,
- EShell *shell,
CamelFolder *folder);
G_END_DECLS
diff --git a/modules/Makefile.am b/modules/Makefile.am
index 5dbe228..096146b 100644
--- a/modules/Makefile.am
+++ b/modules/Makefile.am
@@ -51,7 +51,8 @@ SUBDIRS = \
settings \
startup-wizard \
vcard-inline \
- web-inspector \
+ webkit-editor \
+ webkit-inspector \
$(BOGOFILTER_DIR) \
$(SPAMASSASSIN_DIR) \
$(TNEF_ATTACHMENT_DIR) \
diff --git a/modules/addressbook/eab-composer-util.c b/modules/addressbook/eab-composer-util.c
index b2d79de..94e8aaf 100644
--- a/modules/addressbook/eab-composer-util.c
+++ b/modules/addressbook/eab-composer-util.c
@@ -29,28 +29,156 @@
#include "addressbook/util/eab-book-util.h"
#include "addressbook/gui/widgets/eab-gui-util.h"
+static const gchar *
+get_email (EContact *contact,
+ EContactField field_id,
+ gchar **to_free)
+{
+ gchar *name = NULL, *mail = NULL;
+ const gchar *value = e_contact_get_const (contact, field_id);
+
+ *to_free = NULL;
+
+ if (eab_parse_qp_email (value, &name, &mail)) {
+ *to_free = g_strdup_printf ("%s <%s>", name, mail);
+ value = *to_free;
+ }
+
+ g_free (name);
+ g_free (mail);
+
+ return value;
+}
+
+typedef struct _CreateComposerData {
+ EDestination **to_destinations;
+ EDestination **bcc_destinations;
+ GSList *attachment_destinations;
+} CreateComposerData;
+
+static void
+eab_composer_created_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ CreateComposerData *ccd = user_data;
+ EComposerHeaderTable *table;
+ EMsgComposer *composer;
+ GError *error = NULL;
+
+ g_return_if_fail (ccd != NULL);
+
+ composer = e_msg_composer_new_finish (result, &error);
+ if (error) {
+ g_warning ("%s: Failed to create msg composer: %s", G_STRFUNC, error->message);
+ g_clear_error (&error);
+ } else {
+ table = e_msg_composer_get_header_table (composer);
+
+ if (ccd->to_destinations)
+ e_composer_header_table_set_destinations_to (table, ccd->to_destinations);
+
+ if (ccd->bcc_destinations)
+ e_composer_header_table_set_destinations_bcc (table, ccd->bcc_destinations);
+
+ if (ccd->attachment_destinations) {
+ CamelMimePart *attachment;
+ GSList *contacts, *iter;
+ gchar *data;
+
+ attachment = camel_mime_part_new ();
+
+ contacts = g_slist_copy (ccd->attachment_destinations);
+ for (iter = contacts; iter != NULL; iter = iter->next)
+ iter->data = e_destination_get_contact (iter->data);
+ data = eab_contact_list_to_string (contacts);
+ g_slist_free (contacts);
+
+ camel_mime_part_set_content (attachment, data, strlen (data), "text/x-vcard");
+
+ if (ccd->attachment_destinations->next != NULL) {
+ camel_mime_part_set_description (attachment, _("Multiple vCards"));
+ } else {
+ EContact *contact;
+ const gchar *file_as;
+ gchar *description;
+
+ contact = e_destination_get_contact (ccd->attachment_destinations->data);
+ file_as = e_contact_get_const (contact, E_CONTACT_FILE_AS);
+ description = g_strdup_printf (_("vCard for %s"), file_as);
+ camel_mime_part_set_description (attachment, description);
+ g_free (description);
+ }
+
+ camel_mime_part_set_disposition (attachment, "attachment");
+
+ e_msg_composer_attach (composer, attachment);
+ g_object_unref (attachment);
+
+ if (ccd->attachment_destinations->next != NULL) {
+ e_composer_header_table_set_subject (table, _("Contact information"));
+ } else {
+ EContact *contact;
+ gchar *tempstr;
+ const gchar *tempstr2;
+ gchar *tempfree = NULL;
+
+ contact = e_destination_get_contact (ccd->attachment_destinations->data);
+ tempstr2 = e_contact_get_const (contact, E_CONTACT_FILE_AS);
+ if (!tempstr2 || !*tempstr2)
+ tempstr2 = e_contact_get_const (contact, E_CONTACT_FULL_NAME);
+ if (!tempstr2 || !*tempstr2)
+ tempstr2 = e_contact_get_const (contact, E_CONTACT_ORG);
+ if (!tempstr2 || !*tempstr2) {
+ g_free (tempfree);
+ tempstr2 = get_email (contact, E_CONTACT_EMAIL_1, &tempfree);
+ }
+ if (!tempstr2 || !*tempstr2) {
+ g_free (tempfree);
+ tempstr2 = get_email (contact, E_CONTACT_EMAIL_2, &tempfree);
+ }
+ if (!tempstr2 || !*tempstr2) {
+ g_free (tempfree);
+ tempstr2 = get_email (contact, E_CONTACT_EMAIL_3, &tempfree);
+ }
+
+ if (!tempstr2 || !*tempstr2)
+ tempstr = g_strdup_printf (_("Contact information"));
+ else
+ tempstr = g_strdup_printf (_("Contact information for %s"), tempstr2);
+
+ e_composer_header_table_set_subject (table, tempstr);
+
+ g_free (tempstr);
+ g_free (tempfree);
+ }
+ }
+
+ gtk_widget_show (GTK_WIDGET (composer));
+ }
+
+ if (ccd->to_destinations)
+ e_destination_freev (ccd->to_destinations);
+ if (ccd->bcc_destinations)
+ e_destination_freev (ccd->bcc_destinations);
+ g_slist_free_full (ccd->attachment_destinations, g_object_unref);
+
+ g_free (ccd);
+}
+
void
eab_send_as_to (EShell *shell,
GSList *destinations)
{
- EMsgComposer *composer;
- EComposerHeaderTable *table;
GPtrArray *to_array;
GPtrArray *bcc_array;
-
- union {
- gpointer *pdata;
- EDestination **destinations;
- } convert;
+ CreateComposerData *ccd;
g_return_if_fail (E_IS_SHELL (shell));
if (destinations == NULL)
return;
- composer = e_msg_composer_new (shell);
- table = e_msg_composer_get_header_table (composer);
-
to_array = g_ptr_array_new ();
bcc_array = g_ptr_array_new ();
@@ -60,11 +188,11 @@ eab_send_as_to (EShell *shell,
if (e_destination_is_evolution_list (destination)) {
if (e_destination_list_show_addresses (destination))
- g_ptr_array_add (to_array, destination);
+ g_ptr_array_add (to_array, e_destination_copy (destination));
else
- g_ptr_array_add (bcc_array, destination);
+ g_ptr_array_add (bcc_array, e_destination_copy (destination));
} else
- g_ptr_array_add (to_array, destination);
+ g_ptr_array_add (to_array, e_destination_copy (destination));
destinations = g_slist_next (destinations);
}
@@ -73,133 +201,28 @@ eab_send_as_to (EShell *shell,
g_ptr_array_add (to_array, NULL);
g_ptr_array_add (bcc_array, NULL);
- /* XXX Acrobatics like this make me question whether NULL-terminated
- * arrays are really the best argument type for passing a list of
- * destinations to the header table. */
-
- /* Set "To" destinations. */
- convert.pdata = to_array->pdata;
- e_composer_header_table_set_destinations_to (
- table, convert.destinations);
- g_ptr_array_free (to_array, FALSE);
-
- /* Add "Bcc" destinations. */
- convert.pdata = bcc_array->pdata;
- e_composer_header_table_add_destinations_bcc (
- table, convert.destinations);
- g_ptr_array_free (bcc_array, FALSE);
+ ccd = g_new0 (CreateComposerData, 1);
+ ccd->to_destinations = (EDestination **) g_ptr_array_free (to_array, FALSE);
+ ccd->bcc_destinations = (EDestination **) g_ptr_array_free (bcc_array, FALSE);
+ ccd->attachment_destinations = NULL;
- gtk_widget_show (GTK_WIDGET (composer));
-}
-
-static const gchar *
-get_email (EContact *contact,
- EContactField field_id,
- gchar **to_free)
-{
- gchar *name = NULL, *mail = NULL;
- const gchar *value = e_contact_get_const (contact, field_id);
-
- *to_free = NULL;
-
- if (eab_parse_qp_email (value, &name, &mail)) {
- *to_free = g_strdup_printf ("%s <%s>", name, mail);
- value = *to_free;
- }
-
- g_free (name);
- g_free (mail);
-
- return value;
+ e_msg_composer_new (shell, eab_composer_created_cb, ccd);
}
void
eab_send_as_attachment (EShell *shell,
GSList *destinations)
{
- EMsgComposer *composer;
- EComposerHeaderTable *table;
- CamelMimePart *attachment;
- GSList *contacts, *iter;
- gchar *data;
+ CreateComposerData *ccd;
g_return_if_fail (E_IS_SHELL (shell));
if (destinations == NULL)
return;
- composer = e_msg_composer_new (shell);
- table = e_msg_composer_get_header_table (composer);
-
- attachment = camel_mime_part_new ();
-
- contacts = g_slist_copy (destinations);
- for (iter = contacts; iter != NULL; iter = iter->next)
- iter->data = e_destination_get_contact (iter->data);
- data = eab_contact_list_to_string (contacts);
- g_slist_free (contacts);
-
- camel_mime_part_set_content (
- attachment, data, strlen (data), "text/x-vcard");
-
- if (destinations->next != NULL)
- camel_mime_part_set_description (
- attachment, _("Multiple vCards"));
- else {
- EContact *contact;
- const gchar *file_as;
- gchar *description;
-
- contact = e_destination_get_contact (destinations->data);
- file_as = e_contact_get_const (contact, E_CONTACT_FILE_AS);
- description = g_strdup_printf (_("vCard for %s"), file_as);
- camel_mime_part_set_description (attachment, description);
- g_free (description);
- }
-
- camel_mime_part_set_disposition (attachment, "attachment");
-
- e_msg_composer_attach (composer, attachment);
- g_object_unref (attachment);
-
- if (destinations->next != NULL)
- e_composer_header_table_set_subject (
- table, _("Contact information"));
- else {
- EContact *contact;
- gchar *tempstr;
- const gchar *tempstr2;
- gchar *tempfree = NULL;
-
- contact = e_destination_get_contact (destinations->data);
- tempstr2 = e_contact_get_const (contact, E_CONTACT_FILE_AS);
- if (!tempstr2 || !*tempstr2)
- tempstr2 = e_contact_get_const (contact, E_CONTACT_FULL_NAME);
- if (!tempstr2 || !*tempstr2)
- tempstr2 = e_contact_get_const (contact, E_CONTACT_ORG);
- if (!tempstr2 || !*tempstr2) {
- g_free (tempfree);
- tempstr2 = get_email (contact, E_CONTACT_EMAIL_1, &tempfree);
- }
- if (!tempstr2 || !*tempstr2) {
- g_free (tempfree);
- tempstr2 = get_email (contact, E_CONTACT_EMAIL_2, &tempfree);
- }
- if (!tempstr2 || !*tempstr2) {
- g_free (tempfree);
- tempstr2 = get_email (contact, E_CONTACT_EMAIL_3, &tempfree);
- }
-
- if (!tempstr2 || !*tempstr2)
- tempstr = g_strdup_printf (_("Contact information"));
- else
- tempstr = g_strdup_printf (_("Contact information for %s"), tempstr2);
-
- e_composer_header_table_set_subject (table, tempstr);
-
- g_free (tempstr);
- g_free (tempfree);
- }
+ ccd = g_new0 (CreateComposerData, 1);
+ ccd->attachment_destinations = g_slist_copy (destinations);
+ g_slist_foreach (ccd->attachment_destinations, (GFunc) g_object_ref, NULL);
- gtk_widget_show (GTK_WIDGET (composer));
+ e_msg_composer_new (shell, eab_composer_created_cb, ccd);
}
diff --git a/modules/composer-autosave/e-autosave-utils.c b/modules/composer-autosave/e-autosave-utils.c
index 2e83b2a..19a64b1 100644
--- a/modules/composer-autosave/e-autosave-utils.c
+++ b/modules/composer-autosave/e-autosave-utils.c
@@ -116,6 +116,43 @@ create_snapshot_file (EMsgComposer *composer,
return snapshot_file;
}
+typedef struct _CreateComposerData {
+ GSimpleAsyncResult *simple;
+ LoadContext *context;
+ CamelMimeMessage *message;
+ GFile *snapshot_file;
+} CreateComposerData;
+
+static void
+autosave_composer_created_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ CreateComposerData *ccd = user_data;
+ EMsgComposer *composer;
+ GError *error = NULL;
+
+ composer = e_msg_composer_new_finish (result, &error);
+ if (error) {
+ g_warning ("%s: Failed to create msg composer: %s", G_STRFUNC, error->message);
+ g_simple_async_result_take_error (ccd->simple, error);
+ } else {
+ e_msg_composer_setup_with_message (composer, ccd->message, TRUE, NULL, NULL);
+ g_object_set_data_full (
+ G_OBJECT (composer),
+ SNAPSHOT_FILE_KEY, g_object_ref (ccd->snapshot_file),
+ (GDestroyNotify) delete_snapshot_file);
+ ccd->context->composer = g_object_ref_sink (composer);
+ }
+
+ g_simple_async_result_complete (ccd->simple);
+
+ g_clear_object (&ccd->simple);
+ g_clear_object (&ccd->message);
+ g_clear_object (&ccd->snapshot_file);
+ g_free (ccd);
+}
+
static void
load_snapshot_loaded_cb (GFile *snapshot_file,
GAsyncResult *result,
@@ -124,11 +161,11 @@ load_snapshot_loaded_cb (GFile *snapshot_file,
EShell *shell;
GObject *object;
LoadContext *context;
- EMsgComposer *composer;
CamelMimeMessage *message;
CamelStream *camel_stream;
gchar *contents = NULL;
gsize length;
+ CreateComposerData *ccd;
GError *local_error = NULL;
context = g_simple_async_result_get_op_res_gpointer (simple);
@@ -140,6 +177,7 @@ load_snapshot_loaded_cb (GFile *snapshot_file,
g_warn_if_fail (contents == NULL);
g_simple_async_result_take_error (simple, local_error);
g_simple_async_result_complete (simple);
+ g_object_unref (simple);
return;
}
@@ -157,6 +195,7 @@ load_snapshot_loaded_cb (GFile *snapshot_file,
g_simple_async_result_take_error (simple, local_error);
g_simple_async_result_complete (simple);
g_object_unref (message);
+ g_object_unref (simple);
return;
}
@@ -167,19 +206,16 @@ load_snapshot_loaded_cb (GFile *snapshot_file,
* restore its snapshot file so it continues auto-saving to
* the same file. */
shell = E_SHELL (object);
- g_object_ref (snapshot_file);
- composer = e_msg_composer_new_with_message (shell, message, TRUE, NULL, NULL);
- g_object_set_data_full (
- G_OBJECT (composer),
- SNAPSHOT_FILE_KEY, snapshot_file,
- (GDestroyNotify) delete_snapshot_file);
- context->composer = g_object_ref_sink (composer);
- g_object_unref (message);
- g_object_unref (object);
+ ccd = g_new0 (CreateComposerData, 1);
+ ccd->simple = simple;
+ ccd->context = context;
+ ccd->message = message;
+ ccd->snapshot_file = g_object_ref (snapshot_file);
- g_simple_async_result_complete (simple);
- g_object_unref (simple);
+ e_msg_composer_new (shell, autosave_composer_created_cb, ccd);
+
+ g_object_unref (object);
}
static void
diff --git a/modules/composer-autosave/e-composer-autosave.c b/modules/composer-autosave/e-composer-autosave.c
index c794593..eabc2e1 100644
--- a/modules/composer-autosave/e-composer-autosave.c
+++ b/modules/composer-autosave/e-composer-autosave.c
@@ -120,15 +120,15 @@ static void
composer_autosave_changed_cb (EComposerAutosave *autosave)
{
EHTMLEditor *editor;
- EHTMLEditorView *view;
+ EContentEditor *cnt_editor;
EExtensible *extensible;
extensible = e_extension_get_extensible (E_EXTENSION (autosave));
editor = e_msg_composer_get_editor (E_MSG_COMPOSER (extensible));
- view = e_html_editor_get_view (editor);
+ cnt_editor = e_html_editor_get_content_editor (editor);
- if (autosave->priv->timeout_id == 0 && e_html_editor_view_get_changed (view)) {
+ if (autosave->priv->timeout_id == 0 && e_content_editor_get_changed (cnt_editor)) {
autosave->priv->timeout_id = e_named_timeout_add_seconds (
AUTOSAVE_INTERVAL,
composer_autosave_timeout_cb, autosave);
@@ -160,7 +160,7 @@ static void
composer_autosave_constructed (GObject *object)
{
EHTMLEditor *editor;
- EHTMLEditorView *view;
+ EContentEditor *cnt_editor;
EExtensible *extensible;
/* Chain up to parent's constructed() method. */
@@ -168,12 +168,12 @@ composer_autosave_constructed (GObject *object)
extensible = e_extension_get_extensible (E_EXTENSION (object));
editor = e_msg_composer_get_editor (E_MSG_COMPOSER (extensible));
- view = e_html_editor_get_view (editor);
+ cnt_editor = e_html_editor_get_content_editor (editor);
/* Do not use e_signal_connect_notify_swapped() here,
this module relies on "false" change notifications. */
g_signal_connect_swapped (
- view, "notify::changed",
+ cnt_editor, "notify::changed",
G_CALLBACK (composer_autosave_changed_cb), object);
}
diff --git a/modules/itip-formatter/Makefile.am b/modules/itip-formatter/Makefile.am
index 9252ad8..f8a6241 100644
--- a/modules/itip-formatter/Makefile.am
+++ b/modules/itip-formatter/Makefile.am
@@ -1,3 +1,5 @@
+SUBDIRS = web-extension
+
@EVO_PLUGIN_RULE@
module_LTLIBRARIES = module-itip-formatter.la
@@ -21,7 +23,8 @@ module_itip_formatter_la_SOURCES = \
e-mail-part-itip.h \
itip-view.c \
itip-view.h \
- evolution-module-itip-formatter.c
+ evolution-module-itip-formatter.c \
+ itip-view-elements-defines.h
module_itip_formatter_la_LIBADD = \
$(top_builddir)/e-util/libevolution-util.la \
diff --git a/modules/itip-formatter/e-mail-formatter-itip.c b/modules/itip-formatter/e-mail-formatter-itip.c
index 1439cf1..9ac5751 100644
--- a/modules/itip-formatter/e-mail-formatter-itip.c
+++ b/modules/itip-formatter/e-mail-formatter-itip.c
@@ -66,18 +66,25 @@ emfe_itip_format (EMailFormatterExtension *extension,
itip_part = (EMailPartItip *) part;
if (context->mode == E_MAIL_FORMATTER_MODE_PRINTING) {
- buffer = g_string_sized_new (1024);
+ ItipView *itip_view;
- itip_part->view = itip_view_new (
- itip_part, itip_part->client_cache);
+ buffer = g_string_sized_new (1024);
- itip_view_init_view (itip_part->view);
- itip_view_write_for_printing (itip_part->view, buffer);
+ itip_view = itip_view_new (0, e_mail_part_get_id (part),
+ itip_part,
+ itip_part->folder,
+ itip_part->message_uid,
+ itip_part->message,
+ itip_part->itip_mime_part,
+ itip_part->vcalendar,
+ itip_part->cancellable);
+ itip_view_init_view (itip_view);
+ itip_view_write_for_printing (itip_view, buffer);
} else if (context->mode == E_MAIL_FORMATTER_MODE_RAW) {
buffer = g_string_sized_new (2048);
- itip_view_write (formatter, buffer);
+ itip_view_write (itip_part, formatter, buffer);
} else {
CamelFolder *folder;
@@ -101,8 +108,8 @@ emfe_itip_format (EMailFormatterExtension *extension,
}
itip_part->folder = g_object_ref (folder);
- itip_part->uid = g_strdup (message_uid);
- itip_part->msg = g_object_ref (message);
+ itip_part->message_uid = g_strdup (message_uid);
+ itip_part->message = g_object_ref (message);
default_charset = e_mail_formatter_get_default_charset (formatter);
charset = e_mail_formatter_get_charset (formatter);
diff --git a/modules/itip-formatter/e-mail-parser-itip.c b/modules/itip-formatter/e-mail-parser-itip.c
index bd2e961..6b60153 100644
--- a/modules/itip-formatter/e-mail-parser-itip.c
+++ b/modules/itip-formatter/e-mail-parser-itip.c
@@ -38,8 +38,6 @@
#include "e-mail-part-itip.h"
#include "itip-view.h"
-#define CONF_KEY_DELETE "delete-processed"
-
#define d(x)
typedef EMailParserExtension EMailParserItip;
@@ -69,9 +67,6 @@ empe_itip_parse (EMailParserExtension *extension,
GCancellable *cancellable,
GQueue *out_mail_parts)
{
- EShell *shell;
- GSettings *settings;
- EClientCache *client_cache;
EMailPartItip *itip_part;
CamelDataWrapper *content;
CamelStream *stream;
@@ -83,21 +78,8 @@ empe_itip_parse (EMailParserExtension *extension,
len = part_id->len;
g_string_append_printf (part_id, ".itip");
- settings = e_util_ref_settings ("org.gnome.evolution.plugin.itip");
-
- shell = e_shell_get_default ();
- client_cache = e_shell_get_client_cache (shell);
-
itip_part = e_mail_part_itip_new (part, part_id->str);
- itip_part->delete_message = g_settings_get_boolean (settings, CONF_KEY_DELETE);
- itip_part->has_organizer = FALSE;
- itip_part->no_reply_wanted = FALSE;
- itip_part->part = part;
- itip_part->cancellable = g_cancellable_new ();
- itip_part->real_comps = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
- itip_part->client_cache = g_object_ref (client_cache);
-
- g_object_unref (settings);
+ itip_part->itip_mime_part = g_object_ref (part);
/* This is non-gui thread. Download the part for using in the main thread */
content = camel_medium_get_content ((CamelMedium *) part);
@@ -153,4 +135,3 @@ e_mail_parser_itip_type_register (GTypeModule *type_module)
{
e_mail_parser_itip_register_type (type_module);
}
-
diff --git a/modules/itip-formatter/e-mail-part-itip.c b/modules/itip-formatter/e-mail-part-itip.c
index 8a84ae7..fbb4ffb 100644
--- a/modules/itip-formatter/e-mail-part-itip.c
+++ b/modules/itip-formatter/e-mail-part-itip.c
@@ -15,6 +15,13 @@
*
*/
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <e-util/e-util.h>
+
#include "e-mail-part-itip.h"
#define E_MAIL_PART_ITIP_GET_PRIVATE(obj) \
@@ -22,7 +29,7 @@
((obj), E_TYPE_MAIL_PART_ITIP, EMailPartItipPrivate))
struct _EMailPartItipPrivate {
- gint placeholder;
+ GSList *views; /* ItipView * */
};
G_DEFINE_DYNAMIC_TYPE (
@@ -37,10 +44,16 @@ mail_part_itip_dispose (GObject *object)
g_cancellable_cancel (part->cancellable);
+ g_free (part->message_uid);
+ part->message_uid = NULL;
+
+ g_free (part->vcalendar);
+ part->vcalendar = NULL;
+
+ g_clear_object (&part->folder);
+ g_clear_object (&part->message);
+ g_clear_object (&part->itip_mime_part);
g_clear_object (&part->cancellable);
- g_clear_object (&part->client_cache);
- g_clear_object (&part->comp);
- g_clear_object (&part->view);
/* Chain up to parent's dispose() method. */
G_OBJECT_CLASS (e_mail_part_itip_parent_class)->dispose (object);
@@ -51,66 +64,48 @@ mail_part_itip_finalize (GObject *object)
{
EMailPartItip *part = E_MAIL_PART_ITIP (object);
- g_free (part->vcalendar);
- g_free (part->calendar_uid);
- g_free (part->from_address);
- g_free (part->from_name);
- g_free (part->to_address);
- g_free (part->to_name);
- g_free (part->delegator_address);
- g_free (part->delegator_name);
- g_free (part->my_address);
- g_free (part->uid);
-
- if (part->top_level != NULL)
- icalcomponent_free (part->top_level);
-
- if (part->main_comp != NULL)
- icalcomponent_free (part->main_comp);
-
- g_hash_table_destroy (part->real_comps);
+ g_slist_free_full (part->priv->views, g_object_unref);
+ part->priv->views = NULL;
/* Chain up to parent's finalize() method. */
G_OBJECT_CLASS (e_mail_part_itip_parent_class)->finalize (object);
}
static void
-mail_part_itip_bind_dom_element (EMailPart *part,
- WebKitDOMElement *element)
+mail_part_itip_web_view_loaded (EMailPart *mail_part,
+ EWebView *web_view)
{
- GString *buffer;
- WebKitDOMDocument *document;
- WebKitDOMElement *bind_element, *document_element;
- ItipView *view;
EMailPartItip *pitip;
-
- pitip = E_MAIL_PART_ITIP (part);
-
- bind_element = element;
- if (!WEBKIT_DOM_IS_HTML_IFRAME_ELEMENT (bind_element))
- element = webkit_dom_element_query_selector (element, "iframe", NULL);
-
- g_return_if_fail (WEBKIT_DOM_IS_HTML_IFRAME_ELEMENT (element));
-
- /* A view is already assigned for this element. */
- if (g_object_get_data (G_OBJECT (element), "view"))
- return;
-
- buffer = g_string_new ("");
- document = webkit_dom_html_iframe_element_get_content_document (
- WEBKIT_DOM_HTML_IFRAME_ELEMENT (element));
-
- view = itip_view_new (pitip, pitip->client_cache);
- g_object_set_data_full (
- G_OBJECT (element), "view", view,
- (GDestroyNotify) g_object_unref);
-
- document_element = webkit_dom_document_get_document_element (document);
- itip_view_create_dom_bindings (view, document_element);
- g_object_unref (document_element);
-
- itip_view_init_view (view);
- g_string_free (buffer, TRUE);
+ ItipView *itip_view;
+
+ g_return_if_fail (E_IS_MAIL_PART_ITIP (mail_part));
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+ pitip = E_MAIL_PART_ITIP (mail_part);
+
+ /* FIXME WK2 - it can sometimes happen that the pitip members, like the folder, message_uid and
message,
+ are not initialized yet, because the internal frame in the main EWebView is not passed
+ through the EMailFormatter, where these are set. This requires a new signal on the WebKitWebView,
+ ideally, to call this only after the iframe is truly loaded (these pitip members are only a side
+ effect of a whole issue with non-knowing that a particular iframe was fully loaded).
+
+ Also retest what happens when the same meeting is opened in multiple windows; it could crash in
gtk+
+ when a button was clicked in one or the other, but also not always.
+ */
+ itip_view = itip_view_new (
+ webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (web_view)),
+ e_mail_part_get_id (mail_part),
+ pitip,
+ pitip->folder,
+ pitip->message_uid,
+ pitip->message,
+ pitip->itip_mime_part,
+ pitip->vcalendar,
+ pitip->cancellable);
+
+ itip_view_set_web_view (itip_view, web_view);
+
+ pitip->priv->views = g_slist_prepend (pitip->priv->views, itip_view);
}
static void
@@ -126,7 +121,7 @@ e_mail_part_itip_class_init (EMailPartItipClass *class)
object_class->finalize = mail_part_itip_finalize;
mail_part_class = E_MAIL_PART_CLASS (class);
- mail_part_class->bind_dom_element = mail_part_itip_bind_dom_element;
+ mail_part_class->web_view_loaded = mail_part_itip_web_view_loaded;
}
static void
@@ -138,6 +133,7 @@ static void
e_mail_part_itip_init (EMailPartItip *part)
{
part->priv = E_MAIL_PART_ITIP_GET_PRIVATE (part);
+ part->cancellable = g_cancellable_new ();
e_mail_part_set_mime_type (E_MAIL_PART (part), "text/calendar");
@@ -163,4 +159,3 @@ e_mail_part_itip_new (CamelMimePart *mime_part,
E_TYPE_MAIL_PART_ITIP,
"id", id, "mime-part", mime_part, NULL);
}
-
diff --git a/modules/itip-formatter/e-mail-part-itip.h b/modules/itip-formatter/e-mail-part-itip.h
index 42c1828..49f5374 100644
--- a/modules/itip-formatter/e-mail-part-itip.h
+++ b/modules/itip-formatter/e-mail-part-itip.h
@@ -55,79 +55,13 @@ struct _EMailPartItip {
EMailPartItipPrivate *priv;
CamelFolder *folder;
- CamelMimeMessage *msg;
- CamelMimePart *part;
-
- gchar *uid;
-
- EClientCache *client_cache;
-
- ECalClient *current_client;
- ECalClientSourceType type;
+ CamelMimeMessage *message;
+ gchar *message_uid;
+ CamelMimePart *itip_mime_part;
+ gchar *vcalendar;
/* cancelled when freeing the puri */
GCancellable *cancellable;
-
- gchar *vcalendar;
- ECalComponent *comp;
- icalcomponent *main_comp;
- icalcomponent *ical_comp;
- icalcomponent *top_level;
- icalcompiter iter;
- icalproperty_method method;
- time_t start_time;
- time_t end_time;
-
- gint current;
- gint total;
-
- gchar *calendar_uid;
-
- gchar *from_address;
- gchar *from_name;
- gchar *to_address;
- gchar *to_name;
- gchar *delegator_address;
- gchar *delegator_name;
- gchar *my_address;
- gint view_only;
-
- guint progress_info_id;
-
- gboolean delete_message;
- /* a reply can only be sent if and only if there is an organizer */
- gboolean has_organizer;
- /*
- * Usually replies are sent unless the user unchecks that option.
- * There are some cases when the default is not to sent a reply
- * (but the user can still chose to do so by checking the option):
- * - the organizer explicitly set RSVP=FALSE for the current user
- * - the event has no ATTENDEEs: that's the case for most non-meeting
- * events
- *
- * The last case is meant for forwarded non-meeting
- * events. Traditionally Evolution hasn't offered to send a
- * reply, therefore the updated implementation mimics that
- * behavior.
- *
- * Unfortunately some software apparently strips all ATTENDEEs
- * when forwarding a meeting; in that case sending a reply is
- * also unchecked by default. So the check for ATTENDEEs is a
- * tradeoff between sending unwanted replies in cases where
- * that wasn't done in the past and not sending a possibly
- * wanted reply where that wasn't possible in the past
- * (because replies to forwarded events were not
- * supported). Overall that should be an improvement, and the
- * user can always override the default.
- */
- gboolean no_reply_wanted;
-
- guint update_item_progress_info_id;
- guint update_item_error_info_id;
- ItipViewResponse update_item_response;
- GHashTable *real_comps; /* ESource's UID -> ECalComponent stored on the server */
-
- ItipView *view;
};
struct _EMailPartItipClass {
diff --git a/modules/itip-formatter/itip-view-elements-defines.h
b/modules/itip-formatter/itip-view-elements-defines.h
new file mode 100644
index 0000000..35bf653
--- /dev/null
+++ b/modules/itip-formatter/itip-view-elements-defines.h
@@ -0,0 +1,65 @@
+/*
+ * itip-view-elements-defines.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/>
+ *
+ */
+
+#ifndef ITIP_VIEW_ELEMENTS_DEFINES_H
+#define ITIP_VIEW_ELEMENTS_DEFINES_H
+
+#define TEXT_ROW_SENDER "text_row_sender"
+#define TABLE_ROW_SUMMARY "table_row_summary"
+#define TABLE_ROW_LOCATION "table_row_location"
+#define TABLE_ROW_START_DATE "table_row_start_time"
+#define TABLE_ROW_END_DATE "table_row_end_time"
+#define TABLE_ROW_STATUS "table_row_status"
+#define TABLE_ROW_COMMENT "table_row_comment"
+#define TABLE_ROW_DESCRIPTION "table_row_description"
+#define TABLE_ROW_RSVP_COMMENT "table_row_rsvp_comment"
+#define TABLE_ROW_ESCB "table_row_escb"
+#define TABLE_ROW_BUTTONS "table_row_buttons"
+#define TABLE_ROW_ESCB_LABEL "table_row_escb_label"
+
+#define TABLE_BUTTONS "table_buttons"
+
+#define SELECT_ESOURCE "select_esource"
+#define TEXTAREA_RSVP_COMMENT "textarea_rsvp_comment"
+
+#define CHECKBOX_RSVP "checkbox_rsvp"
+#define CHECKBOX_RECUR "checkbox_recur"
+#define CHECKBOX_UPDATE "checkbox_update"
+#define CHECKBOX_FREE_TIME "checkbox_free_time"
+#define CHECKBOX_KEEP_ALARM "checkbox_keep_alarm"
+#define CHECKBOX_INHERIT_ALARM "checkbox_inherit_alarm"
+
+#define BUTTON_OPEN_CALENDAR "button_open_calendar"
+#define BUTTON_DECLINE "button_decline"
+#define BUTTON_DECLINE_ALL "button_decline_all"
+#define BUTTON_ACCEPT "button_accept"
+#define BUTTON_ACCEPT_ALL "button_accept_all"
+#define BUTTON_TENTATIVE "button_tentative"
+#define BUTTON_TENTATIVE_ALL "button_tentative_all"
+#define BUTTON_SEND_INFORMATION "button_send_information"
+#define BUTTON_UPDATE "button_update"
+#define BUTTON_UPDATE_ATTENDEE_STATUS "button_update_attendee_status"
+#define BUTTON_SAVE "button_save"
+
+#define TABLE_UPPER_ITIP_INFO "table_upper_itip_info"
+#define TABLE_LOWER_ITIP_INFO "table_lower_itip_info"
+
+#define DIV_ITIP_CONTENT "div_itip_content"
+#define DIV_ITIP_ERROR "div_itip_error"
+
+#endif /* ITIP_VIEW_ELEMENTS_DEFINES_H */
diff --git a/modules/itip-formatter/itip-view.c b/modules/itip-formatter/itip-view.c
index 42b7669..482d2c1 100644
--- a/modules/itip-formatter/itip-view.c
+++ b/modules/itip-formatter/itip-view.c
@@ -25,7 +25,6 @@
#include <string.h>
#include <glib/gi18n.h>
-#include <webkit/webkitdom.h>
#include <libedataserver/libedataserver.h>
#include <shell/e-shell.h>
@@ -40,6 +39,10 @@
#include "itip-view.h"
#include "e-mail-part-itip.h"
+#include "itip-view-elements-defines.h"
+
+#include "web-extension/module-itip-formatter-web-extension.h"
+
#define d(x)
#define MEETING_ICON "stock_people"
@@ -105,54 +108,85 @@ struct _ItipViewPrivate {
gint needs_decline : 1;
- WebKitDOMDocument *dom_document;
- EMailPartItip *itip_part;
+ gpointer itip_part_ptr; /* not referenced, only for a "reference" to which part this belongs */
+
+ GDBusProxy *web_extension;
+ guint web_extension_watch_name_id;
+ guint web_extension_source_changed_cb_signal_id;
+ guint web_extension_recur_toggled_signal_id;
+
+ guint64 page_id;
+ gchar *part_id;
gchar *error;
-};
+ GWeakRef *web_view_weakref;
+
+ CamelFolder *folder;
+ CamelMimeMessage *message;
+ gchar *message_uid;
+ CamelMimePart *itip_mime_part;
+ GCancellable *cancellable;
-#define TEXT_ROW_SENDER "text_row_sender"
-#define TABLE_ROW_SUMMARY "table_row_summary"
-#define TABLE_ROW_LOCATION "table_row_location"
-#define TABLE_ROW_START_DATE "table_row_start_time"
-#define TABLE_ROW_END_DATE "table_row_end_time"
-#define TABLE_ROW_STATUS "table_row_status"
-#define TABLE_ROW_COMMENT "table_row_comment"
-#define TABLE_ROW_DESCRIPTION "table_row_description"
-#define TABLE_ROW_RSVP_COMMENT "table_row_rsvp_comment"
-#define TABLE_ROW_ESCB "table_row_escb"
-#define TABLE_ROW_BUTTONS "table_row_buttons"
-#define TABLE_ROW_ESCB_LABEL "table_row_escb_label"
-
-#define TABLE_BUTTONS "table_buttons"
-
-#define SELECT_ESOURCE "select_esource"
-#define TEXTAREA_RSVP_COMMENT "textarea_rsvp_comment"
-
-#define CHECKBOX_RSVP "checkbox_rsvp"
-#define CHECKBOX_RECUR "checkbox_recur"
-#define CHECKBOX_UPDATE "checkbox_update"
-#define CHECKBOX_FREE_TIME "checkbox_free_time"
-#define CHECKBOX_KEEP_ALARM "checkbox_keep_alarm"
-#define CHECKBOX_INHERIT_ALARM "checkbox_inherit_alarm"
-
-#define BUTTON_OPEN_CALENDAR "button_open_calendar"
-#define BUTTON_DECLINE "button_decline"
-#define BUTTON_DECLINE_ALL "button_decline_all"
-#define BUTTON_ACCEPT "button_accept"
-#define BUTTON_ACCEPT_ALL "button_accept_all"
-#define BUTTON_TENTATIVE "button_tentative"
-#define BUTTON_TENTATIVE_ALL "button_tentative_all"
-#define BUTTON_SEND_INFORMATION "button_send_information"
-#define BUTTON_UPDATE "button_update"
-#define BUTTON_UPDATE_ATTENDEE_STATUS "button_update_attendee_status"
-#define BUTTON_SAVE "button_save"
-
-#define TABLE_UPPER_ITIP_INFO "table_upper_itip_info"
-#define TABLE_LOWER_ITIP_INFO "table_lower_itip_info"
-
-#define DIV_ITIP_CONTENT "div_itip_content"
-#define DIV_ITIP_ERROR "div_itip_error"
+ ECalClient *current_client;
+
+ gchar *vcalendar;
+ ECalComponent *comp;
+ icalcomponent *main_comp;
+ icalcomponent *ical_comp;
+ icalcomponent *top_level;
+ icalcompiter iter;
+ icalproperty_method method;
+ time_t start_time;
+ time_t end_time;
+
+ gint current;
+ gint total;
+
+ gchar *calendar_uid;
+
+ gchar *from_address;
+ gchar *from_name;
+ gchar *to_address;
+ gchar *to_name;
+ gchar *delegator_address;
+ gchar *delegator_name;
+ gchar *my_address;
+ gint view_only;
+
+ guint progress_info_id;
+
+ /* a reply can only be sent if and only if there is an organizer */
+ gboolean has_organizer;
+ /*
+ * Usually replies are sent unless the user unchecks that option.
+ * There are some cases when the default is not to sent a reply
+ * (but the user can still chose to do so by checking the option):
+ * - the organizer explicitly set RSVP=FALSE for the current user
+ * - the event has no ATTENDEEs: that's the case for most non-meeting
+ * events
+ *
+ * The last case is meant for forwarded non-meeting
+ * events. Traditionally Evolution hasn't offered to send a
+ * reply, therefore the updated implementation mimics that
+ * behavior.
+ *
+ * Unfortunately some software apparently strips all ATTENDEEs
+ * when forwarding a meeting; in that case sending a reply is
+ * also unchecked by default. So the check for ATTENDEEs is a
+ * tradeoff between sending unwanted replies in cases where
+ * that wasn't done in the past and not sending a possibly
+ * wanted reply where that wasn't possible in the past
+ * (because replies to forwarded events were not
+ * supported). Overall that should be an improvement, and the
+ * user can always override the default.
+ */
+ gboolean no_reply_wanted;
+
+ guint update_item_progress_info_id;
+ guint update_item_error_info_id;
+ ItipViewResponse update_item_response;
+ GHashTable *real_comps; /* ESource's UID -> ECalComponent stored on the server */
+};
enum {
PROP_0,
@@ -612,6 +646,199 @@ set_journal_sender_text (ItipView *view)
}
static void
+enable_button (ItipView *view,
+ const gchar *button_id,
+ gboolean enable)
+{
+ if (!view->priv->web_extension)
+ return;
+
+ g_dbus_proxy_call (
+ view->priv->web_extension,
+ "EnableButton",
+ g_variant_new ("(tssb)", view->priv->page_id, view->priv->part_id, button_id, enable),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+}
+
+static void
+show_button (ItipView *view,
+ const gchar *id)
+{
+ if (!view->priv->web_extension)
+ return;
+
+ g_dbus_proxy_call (
+ view->priv->web_extension,
+ "ShowButton",
+ g_variant_new ("(tss)", view->priv->page_id, view->priv->part_id, id),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+}
+
+static void
+hide_element (ItipView *view,
+ const gchar *element_id,
+ gboolean hide)
+{
+ if (!view->priv->web_extension)
+ return;
+
+ g_dbus_proxy_call (
+ view->priv->web_extension,
+ "HideElement",
+ g_variant_new ("(tssb)", view->priv->page_id, view->priv->part_id, element_id, hide),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+}
+
+static gboolean
+element_is_hidden (ItipView *view,
+ const gchar *element_id)
+{
+ GVariant *result;
+ gboolean hidden;
+
+ if (!view->priv->web_extension)
+ return FALSE;
+
+ result = g_dbus_proxy_call_sync (
+ view->priv->web_extension,
+ "ElementIsHidden",
+ g_variant_new ("(tss)", view->priv->page_id, view->priv->part_id, element_id),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL);
+
+ if (result) {
+ g_variant_get (result, "(b)", &hidden);
+ g_variant_unref (result);
+ return hidden;
+ }
+
+ return FALSE;
+}
+
+static void
+set_inner_html (ItipView *view,
+ const gchar *element_id,
+ const gchar *inner_html)
+{
+ if (!view->priv->web_extension)
+ return;
+
+ g_dbus_proxy_call (
+ view->priv->web_extension,
+ "ElementSetInnerHTML",
+ g_variant_new ("(tsss)", view->priv->page_id, view->priv->part_id, element_id, inner_html),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+}
+
+static void
+input_set_checked (ItipView *view,
+ const gchar *input_id,
+ gboolean checked)
+{
+ if (!view->priv->web_extension)
+ return;
+
+ g_dbus_proxy_call (
+ view->priv->web_extension,
+ "InputSetChecked",
+ g_variant_new ("(tssb)", view->priv->page_id, view->priv->part_id, input_id, checked),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+}
+
+static gboolean
+input_is_checked (ItipView *view,
+ const gchar *input_id)
+{
+ GVariant *result;
+ gboolean checked;
+
+ if (!view->priv->web_extension)
+ return FALSE;
+
+ result = g_dbus_proxy_call_sync (
+ view->priv->web_extension,
+ "InputIsChecked",
+ g_variant_new ("(tss)", view->priv->page_id, view->priv->part_id, input_id),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL);
+
+ if (result) {
+ g_variant_get (result, "(b)", &checked);
+ g_variant_unref (result);
+ return checked;
+ }
+
+ return FALSE;
+}
+
+static void
+show_checkbox (ItipView *view,
+ const gchar *id,
+ gboolean show,
+ gboolean update_second)
+{
+ g_return_if_fail (ITIP_IS_VIEW (view));
+
+ if (!view->priv->web_extension)
+ return;
+
+ g_dbus_proxy_call (
+ view->priv->web_extension,
+ "ShowCheckbox",
+ g_variant_new ("(tssbb)", view->priv->page_id, view->priv->part_id, id, show, update_second),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+}
+
+static void
+set_area_text (ItipView *view,
+ const gchar *id,
+ const gchar *text)
+{
+ g_return_if_fail (ITIP_IS_VIEW (view));
+
+ if (!view->priv->web_extension)
+ return;
+
+ g_dbus_proxy_call (
+ view->priv->web_extension,
+ "SetAreaText",
+ g_variant_new ("(tsss)", view->priv->page_id, view->priv->part_id, id, text ? text : ""),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+}
+
+static void
set_sender_text (ItipView *view)
{
ItipViewPrivate *priv;
@@ -635,22 +862,14 @@ set_sender_text (ItipView *view)
break;
}
- if (priv->sender && priv->dom_document) {
- WebKitDOMElement *div;
-
- div = webkit_dom_document_get_element_by_id (
- priv->dom_document, TEXT_ROW_SENDER);
- webkit_dom_html_element_set_inner_html (
- WEBKIT_DOM_HTML_ELEMENT (div), priv->sender, NULL);
- g_object_unref (div);
- }
+ if (priv->sender && priv->web_extension)
+ set_inner_html (view, TEXT_ROW_SENDER, priv->sender);
}
static void
update_start_end_times (ItipView *view)
{
ItipViewPrivate *priv;
- WebKitDOMElement *row, *col;
gchar buffer[256];
time_t now;
struct tm *now_tm;
@@ -695,142 +914,155 @@ update_start_end_times (ItipView *view)
}
#undef is_same
- if (priv->dom_document) {
- row = webkit_dom_document_get_element_by_id (
- priv->dom_document, TABLE_ROW_START_DATE);
- if (priv->start_header && priv->start_label) {
- webkit_dom_html_element_set_hidden (
- WEBKIT_DOM_HTML_ELEMENT (row), FALSE);
-
- col = webkit_dom_element_get_first_element_child (row);
- webkit_dom_html_element_set_inner_html (
- WEBKIT_DOM_HTML_ELEMENT (col), priv->start_header, NULL);
- g_object_unref (col);
-
- col = webkit_dom_element_get_last_element_child (row);
- webkit_dom_html_element_set_inner_html (
- WEBKIT_DOM_HTML_ELEMENT (col), priv->start_label, NULL);
- g_object_unref (col);
- } else {
- webkit_dom_html_element_set_hidden (
- WEBKIT_DOM_HTML_ELEMENT (row), TRUE);
- }
- g_object_unref (row);
-
- row = webkit_dom_document_get_element_by_id (
- priv->dom_document, TABLE_ROW_END_DATE);
- if (priv->end_header && priv->end_label) {
- webkit_dom_html_element_set_hidden (
- WEBKIT_DOM_HTML_ELEMENT (row), FALSE);
-
- col = webkit_dom_element_get_first_element_child (row);
- webkit_dom_html_element_set_inner_html (
- WEBKIT_DOM_HTML_ELEMENT (col), priv->end_header, NULL);
- g_object_unref (col);
-
- col = webkit_dom_element_get_last_element_child (row);
- webkit_dom_html_element_set_inner_html (
- WEBKIT_DOM_HTML_ELEMENT (col), priv->end_label, NULL);
- g_object_unref (col);
- } else {
- webkit_dom_html_element_set_hidden (
- WEBKIT_DOM_HTML_ELEMENT (row), TRUE);
- }
- g_object_unref (row);
- }
+ if (!priv->web_extension)
+ return;
+
+ if (priv->start_header && priv->start_label) {
+ g_dbus_proxy_call (
+ priv->web_extension,
+ "UpdateTimes",
+ g_variant_new (
+ "(tssss)",
+ view->priv->page_id,
+ view->priv->part_id,
+ TABLE_ROW_START_DATE,
+ priv->start_header,
+ priv->start_label),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+ } else
+ hide_element (view, TABLE_ROW_START_DATE, TRUE);
+
+ if (priv->end_header && priv->end_label) {
+ g_dbus_proxy_call (
+ priv->web_extension,
+ "UpdateTimes",
+ g_variant_new (
+ "(tssss)",
+ view->priv->page_id,
+ view->priv->part_id,
+ TABLE_ROW_END_DATE,
+ priv->end_header,
+ priv->end_label),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+ } else
+ hide_element (view, TABLE_ROW_END_DATE, TRUE);
}
static void
-button_clicked_cb (WebKitDOMElement *element,
- WebKitDOMEvent *event,
- gpointer data)
+itip_view_itip_button_clicked_cb (EWebView *web_view,
+ const gchar *element_class,
+ const gchar *element_value,
+ const GtkAllocation *element_position,
+ gpointer user_data)
{
- ItipViewResponse response;
- gchar *response_str;
+ ItipView *view = user_data;
+ gboolean can_use;
+ gchar *tmp;
+
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+ g_return_if_fail (element_class && *element_class);
+ g_return_if_fail (element_value && *element_value);
+ g_return_if_fail (ITIP_IS_VIEW (view));
- response_str = webkit_dom_html_button_element_get_value (
- WEBKIT_DOM_HTML_BUTTON_ELEMENT (element));
+ tmp = g_strdup_printf ("%p:", view->priv->itip_part_ptr);
+ can_use = g_str_has_prefix (element_value, tmp);
+ if (can_use)
+ element_value += strlen (tmp);
+ g_free (tmp);
- response = atoi (response_str);
- g_free (response_str);
+ if (can_use) {
+ gint response = atoi (element_value);
- g_signal_emit (data, signals[RESPONSE], 0, response);
+ g_signal_emit (view, signals[RESPONSE], 0, response);
+ }
}
static void
-rsvp_toggled_cb (WebKitDOMHTMLInputElement *input,
- WebKitDOMEvent *event,
- gpointer data)
+itip_view_register_clicked_listener (ItipView *view)
{
- WebKitDOMElement *el;
+ EWebView *web_view;
- ItipView *view = data;
- gboolean rsvp;
+ g_return_if_fail (ITIP_IS_VIEW (view));
- rsvp = webkit_dom_html_input_element_get_checked (input);
+ web_view = itip_view_ref_web_view (view);
+ if (web_view) {
+ e_web_view_register_element_clicked (web_view, "itip-button",
+ itip_view_itip_button_clicked_cb, view);
+ }
- el = webkit_dom_document_get_element_by_id (
- view->priv->dom_document, TEXTAREA_RSVP_COMMENT);
- webkit_dom_html_text_area_element_set_disabled (
- WEBKIT_DOM_HTML_TEXT_AREA_ELEMENT (el), !rsvp);
- g_object_unref (el);
+ g_clear_object (&web_view);
}
static void
-recur_toggled_cb (WebKitDOMHTMLInputElement *input,
- WebKitDOMEvent *event,
- gpointer data)
+recur_toggled_signal_cb (GDBusConnection *connection,
+ const gchar *sender_name,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *signal_name,
+ GVariant *parameters,
+ ItipView *view)
{
- ItipView *view = data;
+ guint64 page_id = 0;
+ const gchar *part_id = NULL;
+
+ g_return_if_fail (ITIP_IS_VIEW (view));
+
+ if (g_strcmp0 (signal_name, "RecurToggled") != 0)
+ return;
+
+ g_variant_get (parameters, "(t&s)", &page_id, &part_id);
- itip_view_set_mode (view, view->priv->mode);
+ if (view->priv->page_id == page_id &&
+ g_strcmp0 (view->priv->part_id, part_id) == 0)
+ itip_view_set_mode (view, view->priv->mode);
}
-/*
- alarm_check_toggled_cb
- check1 was changed, so make the second available based on state of the first check.
-*/
static void
-alarm_check_toggled_cb (WebKitDOMHTMLInputElement *check1,
- WebKitDOMEvent *event,
- ItipView *view)
+source_changed_cb (ItipView *view)
{
- WebKitDOMElement *check2;
- gchar *id;
-
- id = webkit_dom_element_get_id (WEBKIT_DOM_ELEMENT (check1));
+ ESource *source;
- if (g_strcmp0 (id, CHECKBOX_INHERIT_ALARM)) {
- check2 = webkit_dom_document_get_element_by_id (
- view->priv->dom_document, CHECKBOX_KEEP_ALARM);
- } else {
- check2 = webkit_dom_document_get_element_by_id (
- view->priv->dom_document, CHECKBOX_INHERIT_ALARM);
- }
+ source = itip_view_ref_source (view);
- g_free (id);
+ if (source) {
+ d (printf ("Source changed to '%s'\n", e_source_get_display_name (source)));
+ g_signal_emit (view, signals[SOURCE_SELECTED], 0, source);
- webkit_dom_html_input_element_set_disabled (
- WEBKIT_DOM_HTML_INPUT_ELEMENT (check2),
- (webkit_dom_html_element_get_hidden (
- WEBKIT_DOM_HTML_ELEMENT (check1)) &&
- webkit_dom_html_input_element_get_checked (check1)));
- g_object_unref (check2);
+ g_object_unref (source);
+ }
}
static void
-source_changed_cb (WebKitDOMElement *select,
- WebKitDOMEvent *event,
- ItipView *view)
+source_changed_cb_signal_cb (GDBusConnection *connection,
+ const gchar *sender_name,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *signal_name,
+ GVariant *parameters,
+ gpointer user_data)
{
- ESource *source;
+ ItipView *view = user_data;
+ guint64 page_id = 0;
+ const gchar *part_id = NULL;
- source = itip_view_ref_source (view);
+ g_return_if_fail (ITIP_IS_VIEW (view));
+
+ if (g_strcmp0 (signal_name, "SourceChanged") != 0)
+ return;
- d (printf ("Source changed to '%s'\n", e_source_get_display_name (source)));
- g_signal_emit (view, signals[SOURCE_SELECTED], 0, source);
+ g_variant_get (parameters, "(t&s)", &page_id, &part_id);
- g_object_unref (source);
+ if (view->priv->page_id == page_id &&
+ g_strcmp0 (view->priv->part_id, part_id) == 0)
+ source_changed_cb (view);
}
static void
@@ -897,19 +1129,8 @@ append_info_item_row (ItipView *view,
const gchar *table_id,
ItipViewInfoItem *item)
{
- WebKitDOMElement *table;
- WebKitDOMHTMLElement *row, *cell;
const gchar *icon_name;
- gchar *id;
-
- table = webkit_dom_document_get_element_by_id (
- view->priv->dom_document, table_id);
- row = webkit_dom_html_table_element_insert_row (
- WEBKIT_DOM_HTML_TABLE_ELEMENT (table), -1, NULL);
-
- id = g_strdup_printf ("%s_row_%d", table_id, item->id);
- webkit_dom_element_set_id (WEBKIT_DOM_ELEMENT (row), id);
- g_free (id);
+ gchar *row_id;
switch (item->type) {
case ITIP_VIEW_INFO_ITEM_TYPE_INFO:
@@ -929,42 +1150,31 @@ append_info_item_row (ItipView *view,
icon_name = NULL;
}
- cell = webkit_dom_html_table_row_element_insert_cell (
- WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (row), -1, NULL);
-
- if (icon_name) {
- gchar *icon_uri;
- WebKitDOMElement *image;
- WebKitDOMNode *tmp;
+ row_id = g_strdup_printf ("%s_row_%d", table_id, item->id);
- image = webkit_dom_document_create_element (
- view->priv->dom_document, "IMG", NULL);
-
- icon_uri = g_strdup_printf ("gtk-stock://%s", icon_name);
- webkit_dom_html_image_element_set_src (
- WEBKIT_DOM_HTML_IMAGE_ELEMENT (image), icon_uri);
- g_free (icon_uri);
-
- tmp = webkit_dom_node_append_child (
- WEBKIT_DOM_NODE (cell),
- WEBKIT_DOM_NODE (image),
- NULL);
-
- g_object_unref (tmp);
- g_object_unref (image);
- }
+ if (!view->priv->web_extension)
+ return;
- g_object_unref (cell);
- cell = webkit_dom_html_table_row_element_insert_cell (
- WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (row), -1, NULL);
+ g_dbus_proxy_call (
+ view->priv->web_extension,
+ "AppendInfoItemRow",
+ g_variant_new (
+ "(tsssss)",
+ view->priv->page_id,
+ view->priv->part_id,
+ table_id,
+ row_id,
+ icon_name,
+ item->message),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
- webkit_dom_html_element_set_inner_html (cell, item->message, NULL);
+ g_free (row_id);
d (printf ("Added row %s_row_%d ('%s')\n", table_id, item->id, item->message));
-
- g_object_unref (table);
- g_object_unref (row);
- g_object_unref (cell);
}
static void
@@ -972,26 +1182,31 @@ remove_info_item_row (ItipView *view,
const gchar *table_id,
guint id)
{
- WebKitDOMElement *row;
- WebKitDOMNode *parent, *deleted_node;
gchar *row_id;
row_id = g_strdup_printf ("%s_row_%d", table_id, id);
- row = webkit_dom_document_get_element_by_id (
- view->priv->dom_document, row_id);
- g_free (row_id);
- parent = webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (row)),
- deleted_node = webkit_dom_node_remove_child (
- parent, WEBKIT_DOM_NODE (row), NULL);
- g_object_unref (parent);
- g_object_unref (deleted_node);
+ if (!view->priv->web_extension)
+ return;
+
+ g_dbus_proxy_call (
+ view->priv->web_extension,
+ "RemoveElement",
+ g_variant_new ("(tss)", view->priv->page_id, view->priv->part_id, row_id),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+
+ g_free (row_id);
d (printf ("Removed row %s_row_%d\n", table_id, id));
}
static void
buttons_table_write_button (GString *buffer,
+ gpointer itip_part_ptr,
const gchar *name,
const gchar *label,
const gchar *icon,
@@ -1004,18 +1219,18 @@ buttons_table_write_button (GString *buffer,
if (icon) {
g_string_append_printf (
buffer,
- "<td><button type=\"button\" name=\"%s\" value=\"%d\" id=\"%s\" accesskey=\"%s\"
hidden disabled>"
+ "<td><button class=\"itip-button\" type=\"button\" name=\"%s\" value=\"%p:%d\"
id=\"%s\" accesskey=\"%s\" hidden disabled>"
"<div><img src=\"gtk-stock://%s?size=%d\"> <span>%s</span></div>"
"</button></td>\n",
- name, response, name, access_key ? access_key : "" , icon,
+ name, itip_part_ptr, response, name, access_key ? access_key : "" , icon,
GTK_ICON_SIZE_BUTTON, html_label);
} else {
g_string_append_printf (
buffer,
- "<td><button type=\"button\" name=\"%s\" value=\"%d\" id=\"%s\" accesskey=\"%s\"
hidden disabled>"
+ "<td><button class=\"itip-button\" type=\"button\" name=\"%s\" value=\"%p:%d\"
id=\"%s\" accesskey=\"%s\" hidden disabled>"
"<div><span>%s</span></div>"
"</button></td>\n",
- name, response, name, access_key ? access_key : "" , html_label);
+ name, itip_part_ptr, response, name, access_key ? access_key : "" , html_label);
}
g_free (html_label);
@@ -1025,7 +1240,8 @@ buttons_table_write_button (GString *buffer,
}
static void
-append_buttons_table (GString *buffer)
+append_buttons_table (GString *buffer,
+ gpointer itip_part_ptr)
{
g_string_append (
buffer,
@@ -1036,34 +1252,34 @@ append_buttons_table (GString *buffer)
/* Everything gets the open button */
buttons_table_write_button (
- buffer, BUTTON_OPEN_CALENDAR, _("Ope_n Calendar"),
+ buffer, itip_part_ptr, BUTTON_OPEN_CALENDAR, _("Ope_n Calendar"),
"go-jump", ITIP_VIEW_RESPONSE_OPEN);
buttons_table_write_button (
- buffer, BUTTON_DECLINE_ALL, _("_Decline all"),
+ buffer, itip_part_ptr, BUTTON_DECLINE_ALL, _("_Decline all"),
NULL, ITIP_VIEW_RESPONSE_DECLINE);
buttons_table_write_button (
- buffer, BUTTON_DECLINE, _("_Decline"),
+ buffer, itip_part_ptr, BUTTON_DECLINE, _("_Decline"),
NULL, ITIP_VIEW_RESPONSE_DECLINE);
buttons_table_write_button (
- buffer, BUTTON_TENTATIVE_ALL, _("_Tentative all"),
+ buffer, itip_part_ptr, BUTTON_TENTATIVE_ALL, _("_Tentative all"),
NULL, ITIP_VIEW_RESPONSE_TENTATIVE);
buttons_table_write_button (
- buffer, BUTTON_TENTATIVE, _("_Tentative"),
+ buffer, itip_part_ptr, BUTTON_TENTATIVE, _("_Tentative"),
NULL, ITIP_VIEW_RESPONSE_TENTATIVE);
buttons_table_write_button (
- buffer, BUTTON_ACCEPT_ALL, _("Acce_pt all"),
+ buffer, itip_part_ptr, BUTTON_ACCEPT_ALL, _("Acce_pt all"),
NULL, ITIP_VIEW_RESPONSE_ACCEPT);
buttons_table_write_button (
- buffer, BUTTON_ACCEPT, _("Acce_pt"),
+ buffer, itip_part_ptr, BUTTON_ACCEPT, _("Acce_pt"),
NULL, ITIP_VIEW_RESPONSE_ACCEPT);
buttons_table_write_button (
- buffer, BUTTON_SEND_INFORMATION, _("Send _Information"),
+ buffer, itip_part_ptr, BUTTON_SEND_INFORMATION, _("Send _Information"),
NULL, ITIP_VIEW_RESPONSE_REFRESH);
buttons_table_write_button (
- buffer, BUTTON_UPDATE_ATTENDEE_STATUS, _("_Update Attendee Status"),
+ buffer, itip_part_ptr, BUTTON_UPDATE_ATTENDEE_STATUS, _("_Update Attendee Status"),
NULL, ITIP_VIEW_RESPONSE_UPDATE);
buttons_table_write_button (
- buffer, BUTTON_UPDATE, _("_Update"),
+ buffer, itip_part_ptr, BUTTON_UPDATE, _("_Update"),
NULL, ITIP_VIEW_RESPONSE_CANCEL);
g_string_append (buffer, "</tr></table>");
@@ -1073,14 +1289,12 @@ static void
itip_view_rebuild_source_list (ItipView *view)
{
ESourceRegistry *registry;
- WebKitDOMElement *select;
GList *list, *link;
const gchar *extension_name;
- GHashTable *groups;
d (printf ("Assigning a new source list!\n"));
- if (!view->priv->dom_document)
+ if (!view->priv->web_extension)
return;
registry = view->priv->registry;
@@ -1089,92 +1303,49 @@ itip_view_rebuild_source_list (ItipView *view)
if (extension_name == NULL)
return;
- select = webkit_dom_document_get_element_by_id (
- view->priv->dom_document, SELECT_ESOURCE);
-
- while (webkit_dom_node_has_child_nodes (WEBKIT_DOM_NODE (select))) {
- WebKitDOMNode *removed_child, *last_child;
-
- last_child = webkit_dom_node_get_last_child (WEBKIT_DOM_NODE (select));
- removed_child = webkit_dom_node_remove_child (
- WEBKIT_DOM_NODE (select), last_child, NULL);
- g_object_unref (last_child);
- g_object_unref (removed_child);
- }
+ g_dbus_proxy_call (
+ view->priv->web_extension,
+ "ElementRemoveChildNodes",
+ g_variant_new ("(tss)", view->priv->page_id, view->priv->part_id, SELECT_ESOURCE),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
list = e_source_registry_list_enabled (registry, extension_name);
- groups = g_hash_table_new_full (
- g_str_hash, g_str_equal,
- (GDestroyNotify) g_free, g_object_unref);
for (link = list; link != NULL; link = g_list_next (link)) {
ESource *source = E_SOURCE (link->data);
ESource *parent;
- WebKitDOMElement *option;
- WebKitDOMNode *appended_child;
- WebKitDOMHTMLOptGroupElement *optgroup;
parent = e_source_registry_ref_source (
registry, e_source_get_parent (source));
- optgroup = g_hash_table_lookup (groups, e_source_get_uid (parent));
- if (!optgroup) {
- optgroup = WEBKIT_DOM_HTML_OPT_GROUP_ELEMENT (
- webkit_dom_document_create_element (
- view->priv->dom_document,
- "OPTGROUP", NULL));
- webkit_dom_html_opt_group_element_set_label (
- optgroup, e_source_get_display_name (parent));
- g_hash_table_insert (
- groups, g_strdup (e_source_get_uid (parent)), optgroup);
- }
- g_object_unref (parent);
-
- option = webkit_dom_document_create_element (
- view->priv->dom_document, "OPTION", NULL);
- webkit_dom_html_option_element_set_value (
- WEBKIT_DOM_HTML_OPTION_ELEMENT (option),
- e_source_get_uid (source));
- webkit_dom_html_option_element_set_label (
- WEBKIT_DOM_HTML_OPTION_ELEMENT (option),
- e_source_get_display_name (source));
- webkit_dom_html_element_set_inner_html (
- WEBKIT_DOM_HTML_ELEMENT (option),
- e_source_get_display_name (source), NULL);
- webkit_dom_element_set_class_name (
- WEBKIT_DOM_ELEMENT (option), "calendar");
-
- if (!e_source_get_writable (source)) {
- webkit_dom_html_option_element_set_disabled (
- WEBKIT_DOM_HTML_OPTION_ELEMENT (option), TRUE);
- }
-
- appended_child = webkit_dom_node_append_child (
- WEBKIT_DOM_NODE (optgroup),
- WEBKIT_DOM_NODE (option),
+ g_dbus_proxy_call (
+ view->priv->web_extension,
+ "RebuildSourceList",
+ g_variant_new (
+ "(tsssssb)",
+ view->priv->page_id,
+ view->priv->part_id,
+ e_source_get_uid (parent),
+ e_source_get_display_name (parent),
+ e_source_get_uid (source),
+ e_source_get_display_name (source),
+ e_source_get_writable (source)),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
NULL);
- g_object_unref (option);
- g_object_unref (appended_child);
- }
-
- g_list_free_full (list, (GDestroyNotify) g_object_unref);
- list = g_hash_table_get_values (groups);
- for (link = list; link != NULL; link = g_list_next (link)) {
- WebKitDOMNode *appended_child;
- WebKitDOMNode *optgroup = link->data;
-
- appended_child = webkit_dom_node_append_child (
- WEBKIT_DOM_NODE (select), optgroup, NULL);
- g_object_unref (appended_child);
+ g_object_unref (parent);
}
- g_list_free (list);
-
- g_hash_table_destroy (groups);
- source_changed_cb (select, NULL, view);
+ g_list_free_full (list, (GDestroyNotify) g_object_unref);
- g_object_unref (select);
+ source_changed_cb (view);
}
static void
@@ -1292,8 +1463,30 @@ itip_view_dispose (GObject *object)
priv->source_removed_handler_id = 0;
}
+ if (priv->web_extension_watch_name_id > 0) {
+ g_bus_unwatch_name (priv->web_extension_watch_name_id);
+ priv->web_extension_watch_name_id = 0;
+ }
+
+ if (priv->web_extension_recur_toggled_signal_id > 0) {
+ g_dbus_connection_signal_unsubscribe (
+ g_dbus_proxy_get_connection (priv->web_extension),
+ priv->web_extension_recur_toggled_signal_id);
+ priv->web_extension_recur_toggled_signal_id = 0;
+ }
+
+ if (priv->web_extension_source_changed_cb_signal_id > 0) {
+ g_dbus_connection_signal_unsubscribe (
+ g_dbus_proxy_get_connection (priv->web_extension),
+ priv->web_extension_source_changed_cb_signal_id);
+ priv->web_extension_source_changed_cb_signal_id = 0;
+ }
+
g_clear_object (&priv->client_cache);
g_clear_object (&priv->registry);
+ g_clear_object (&priv->web_extension);
+ g_clear_object (&priv->cancellable);
+ g_clear_object (&priv->comp);
/* Chain up to parent's dispose() method. */
G_OBJECT_CLASS (itip_view_parent_class)->dispose (object);
@@ -1309,7 +1502,6 @@ itip_view_finalize (GObject *object)
d (printf ("Itip view finalized!\n"));
- g_clear_object (&priv->dom_document);
g_free (priv->extension_name);
g_free (priv->sender);
g_free (priv->organizer);
@@ -1328,6 +1520,7 @@ itip_view_finalize (GObject *object)
g_free (priv->end_label);
g_free (priv->description);
g_free (priv->error);
+ g_free (priv->part_id);
for (iter = priv->lower_info_items; iter; iter = iter->next) {
ItipViewInfoItem *item = iter->data;
@@ -1345,6 +1538,31 @@ itip_view_finalize (GObject *object)
g_slist_free (priv->upper_info_items);
+ e_weak_ref_free (priv->web_view_weakref);
+
+ g_free (priv->vcalendar);
+ g_free (priv->calendar_uid);
+ g_free (priv->from_address);
+ g_free (priv->from_name);
+ g_free (priv->to_address);
+ g_free (priv->to_name);
+ g_free (priv->delegator_address);
+ g_free (priv->delegator_name);
+ g_free (priv->my_address);
+ g_free (priv->message_uid);
+
+ g_clear_object (&priv->folder);
+ g_clear_object (&priv->message);
+ g_clear_object (&priv->itip_mime_part);
+
+ if (priv->top_level != NULL)
+ icalcomponent_free (priv->top_level);
+
+ if (priv->main_comp != NULL)
+ icalcomponent_free (priv->main_comp);
+
+ g_hash_table_destroy (priv->real_comps);
+
/* Chain up to parent's finalize() method. */
G_OBJECT_CLASS (itip_view_parent_class)->finalize (object);
}
@@ -1403,8 +1621,7 @@ itip_view_class_init (ItipViewClass *class)
"Client Cache",
"Cache of shared EClient instances",
E_TYPE_CLIENT_CACHE,
- G_PARAM_READWRITE |
- G_PARAM_CONSTRUCT_ONLY));
+ G_PARAM_READABLE));
g_object_class_install_property (
object_class,
@@ -1437,14 +1654,6 @@ itip_view_class_init (ItipViewClass *class)
G_TYPE_INT);
}
-EMailPartItip *
-itip_view_get_mail_part (ItipView *view)
-{
- g_return_val_if_fail (ITIP_IS_VIEW (view), NULL);
-
- return view->priv->itip_part;
-}
-
EClientCache *
itip_view_get_client_cache (ItipView *view)
{
@@ -1480,7 +1689,8 @@ itip_view_set_extension_name (ItipView *view,
}
void
-itip_view_write (EMailFormatter *formatter,
+itip_view_write (gpointer itip_part_ptr,
+ EMailFormatter *formatter,
GString *buffer)
{
gchar *header = e_mail_formatter_get_html_header (formatter);
@@ -1577,7 +1787,7 @@ itip_view_write (EMailFormatter *formatter,
g_string_append (buffer, "</table>\n");
/* Buttons table */
- append_buttons_table (buffer);
+ append_buttons_table (buffer, itip_part_ptr);
/* <div class="itip content" > */
g_string_append (buffer, "</div>\n");
@@ -1650,185 +1860,173 @@ itip_view_write_for_printing (ItipView *view,
}
}
-void
-itip_view_create_dom_bindings (ItipView *view,
- WebKitDOMElement *element)
+static void
+web_extension_proxy_created_cb (GDBusProxy *proxy,
+ GAsyncResult *result,
+ ItipView *view)
{
- WebKitDOMElement *el;
- WebKitDOMDocument *doc;
-
- doc = webkit_dom_node_get_owner_document (WEBKIT_DOM_NODE (element));
- view->priv->dom_document = g_object_ref (doc);
-
- el = webkit_dom_document_get_element_by_id (doc, CHECKBOX_RECUR);
- if (el) {
- webkit_dom_event_target_add_event_listener (
- WEBKIT_DOM_EVENT_TARGET (el), "click",
- G_CALLBACK (recur_toggled_cb), FALSE, view);
- }
-
- el = webkit_dom_document_get_element_by_id (doc, CHECKBOX_RSVP);
- if (el) {
- webkit_dom_event_target_add_event_listener (
- WEBKIT_DOM_EVENT_TARGET (el), "click",
- G_CALLBACK (rsvp_toggled_cb), FALSE, view);
- }
-
- el = webkit_dom_document_get_element_by_id (doc, CHECKBOX_INHERIT_ALARM);
- if (el) {
- webkit_dom_event_target_add_event_listener (
- WEBKIT_DOM_EVENT_TARGET (el), "click",
- G_CALLBACK (alarm_check_toggled_cb), FALSE, view);
- }
-
- el = webkit_dom_document_get_element_by_id (doc, CHECKBOX_KEEP_ALARM);
- if (el) {
- webkit_dom_event_target_add_event_listener (
- WEBKIT_DOM_EVENT_TARGET (el), "click",
- G_CALLBACK (alarm_check_toggled_cb), FALSE, view);
- }
-
- el = webkit_dom_document_get_element_by_id (doc, BUTTON_OPEN_CALENDAR);
- if (el) {
- webkit_dom_event_target_add_event_listener (
- WEBKIT_DOM_EVENT_TARGET (el), "click",
- G_CALLBACK (button_clicked_cb), FALSE, view);
- }
+ GError *error = NULL;
- el = webkit_dom_document_get_element_by_id (doc, BUTTON_ACCEPT);
- if (el) {
- webkit_dom_event_target_add_event_listener (
- WEBKIT_DOM_EVENT_TARGET (el), "click",
- G_CALLBACK (button_clicked_cb), FALSE, view);
+ view->priv->web_extension = g_dbus_proxy_new_finish (result, &error);
+ if (!view->priv->web_extension) {
+ g_warning ("Error creating web extension proxy: %s\n", error->message);
+ g_error_free (error);
}
- el = webkit_dom_document_get_element_by_id (doc, BUTTON_ACCEPT_ALL);
- if (el) {
- webkit_dom_event_target_add_event_listener (
- WEBKIT_DOM_EVENT_TARGET (el), "click",
- G_CALLBACK (button_clicked_cb), FALSE, view);
- }
+ view->priv->web_extension_source_changed_cb_signal_id =
+ g_dbus_connection_signal_subscribe (
+ g_dbus_proxy_get_connection (view->priv->web_extension),
+ g_dbus_proxy_get_name (view->priv->web_extension),
+ MODULE_ITIP_FORMATTER_WEB_EXTENSION_INTERFACE,
+ "SourceChanged",
+ MODULE_ITIP_FORMATTER_WEB_EXTENSION_OBJECT_PATH,
+ NULL,
+ G_DBUS_SIGNAL_FLAGS_NONE,
+ source_changed_cb_signal_cb,
+ view,
+ NULL);
- el = webkit_dom_document_get_element_by_id (doc, BUTTON_TENTATIVE);
- if (el) {
- webkit_dom_event_target_add_event_listener (
- WEBKIT_DOM_EVENT_TARGET (el), "click",
- G_CALLBACK (button_clicked_cb), FALSE, view);
- }
+ view->priv->web_extension_recur_toggled_signal_id =
+ g_dbus_connection_signal_subscribe (
+ g_dbus_proxy_get_connection (view->priv->web_extension),
+ g_dbus_proxy_get_name (view->priv->web_extension),
+ MODULE_ITIP_FORMATTER_WEB_EXTENSION_INTERFACE,
+ "RecurToggled",
+ MODULE_ITIP_FORMATTER_WEB_EXTENSION_OBJECT_PATH,
+ NULL,
+ G_DBUS_SIGNAL_FLAGS_NONE,
+ (GDBusSignalCallback) recur_toggled_signal_cb,
+ view,
+ NULL);
- el = webkit_dom_document_get_element_by_id (doc, BUTTON_TENTATIVE_ALL);
- if (el) {
- webkit_dom_event_target_add_event_listener (
- WEBKIT_DOM_EVENT_TARGET (el), "click",
- G_CALLBACK (button_clicked_cb), FALSE, view);
- }
+ g_dbus_proxy_call (
+ view->priv->web_extension,
+ "CreateDOMBindings",
+ g_variant_new ("(ts)", view->priv->page_id, view->priv->part_id),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
- el = webkit_dom_document_get_element_by_id (doc, BUTTON_DECLINE);
- if (el) {
- webkit_dom_event_target_add_event_listener (
- WEBKIT_DOM_EVENT_TARGET (el), "click",
- G_CALLBACK (button_clicked_cb), FALSE, view);
- }
+ itip_view_init_view (view);
+}
- el = webkit_dom_document_get_element_by_id (doc, BUTTON_DECLINE_ALL);
- if (el) {
- webkit_dom_event_target_add_event_listener (
- WEBKIT_DOM_EVENT_TARGET (el), "click",
- G_CALLBACK (button_clicked_cb), FALSE, view);
- }
+static void
+web_extension_appeared_cb (GDBusConnection *connection,
+ const gchar *name,
+ const gchar *name_owner,
+ ItipView *view)
+{
+ g_dbus_proxy_new (
+ connection,
+ G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START |
+ G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
+ G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
+ NULL,
+ name,
+ MODULE_ITIP_FORMATTER_WEB_EXTENSION_OBJECT_PATH,
+ MODULE_ITIP_FORMATTER_WEB_EXTENSION_INTERFACE,
+ NULL,
+ (GAsyncReadyCallback)web_extension_proxy_created_cb,
+ view);
+}
- el = webkit_dom_document_get_element_by_id (doc, BUTTON_UPDATE);
- if (el) {
- webkit_dom_event_target_add_event_listener (
- WEBKIT_DOM_EVENT_TARGET (el), "click",
- G_CALLBACK (button_clicked_cb), FALSE, view);
- }
+static void
+web_extension_vanished_cb (GDBusConnection *connection,
+ const gchar *name,
+ ItipView *view)
+{
+ g_clear_object (&view->priv->web_extension);
+}
- el = webkit_dom_document_get_element_by_id (doc, BUTTON_UPDATE_ATTENDEE_STATUS);
- if (el) {
- webkit_dom_event_target_add_event_listener (
- WEBKIT_DOM_EVENT_TARGET (el), "click",
- G_CALLBACK (button_clicked_cb), FALSE, view);
- }
+static void
+itip_view_watch_web_extension (ItipView *view)
+{
+ view->priv->web_extension_watch_name_id =
+ g_bus_watch_name (
+ G_BUS_TYPE_SESSION,
+ MODULE_ITIP_FORMATTER_WEB_EXTENSION_SERVICE_NAME,
+ G_BUS_NAME_WATCHER_FLAGS_NONE,
+ (GBusNameAppearedCallback) web_extension_appeared_cb,
+ (GBusNameVanishedCallback) web_extension_vanished_cb,
+ view, NULL);
+}
- el = webkit_dom_document_get_element_by_id (doc, BUTTON_SEND_INFORMATION);
- if (el) {
- webkit_dom_event_target_add_event_listener (
- WEBKIT_DOM_EVENT_TARGET (el), "click",
- G_CALLBACK (button_clicked_cb), FALSE, view);
- }
+GDBusProxy *
+itip_view_get_web_extension_proxy (ItipView *view)
+{
+ g_return_val_if_fail (ITIP_IS_VIEW (view), NULL);
- el = webkit_dom_document_get_element_by_id (doc, SELECT_ESOURCE);
- if (el) {
- webkit_dom_event_target_add_event_listener (
- WEBKIT_DOM_EVENT_TARGET (el), "change",
- G_CALLBACK (source_changed_cb), FALSE, view);
- }
+ return view->priv->web_extension;
}
static void
itip_view_init (ItipView *view)
{
+ EShell *shell;
+ EClientCache *client_cache;
+
+ shell = e_shell_get_default ();
+ client_cache = e_shell_get_client_cache (shell);
+
view->priv = ITIP_VIEW_GET_PRIVATE (view);
+ view->priv->web_view_weakref = e_weak_ref_new (NULL);
+ view->priv->real_comps = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
+ view->priv->client_cache = g_object_ref (client_cache);
}
ItipView *
-itip_view_new (EMailPartItip *puri,
- EClientCache *client_cache)
+itip_view_new (guint64 page_id,
+ const gchar *part_id,
+ gpointer itip_part_ptr,
+ CamelFolder *folder,
+ const gchar *message_uid,
+ CamelMimeMessage *message,
+ CamelMimePart *itip_mime_part,
+ const gchar *vcalendar,
+ GCancellable *cancellable)
{
ItipView *view;
- g_return_val_if_fail (E_IS_CLIENT_CACHE (client_cache), NULL);
+ view = ITIP_VIEW (g_object_new (ITIP_TYPE_VIEW, NULL));
+ view->priv->page_id = page_id;
+ view->priv->part_id = g_strdup (part_id);
+ view->priv->itip_part_ptr = itip_part_ptr;
+ view->priv->folder = g_object_ref (folder);
+ view->priv->message_uid = g_strdup (message_uid);
+ view->priv->message = g_object_ref (message);
+ view->priv->itip_mime_part = g_object_ref (itip_mime_part);
+ view->priv->vcalendar = g_strdup (vcalendar);
+ view->priv->cancellable = g_object_ref (cancellable);
- view = ITIP_VIEW (g_object_new (
- ITIP_TYPE_VIEW,
- "client-cache", client_cache,
- NULL));
- view->priv->itip_part = puri;
+ itip_view_watch_web_extension (view);
return view;
}
-static void
-show_button (ItipView *view,
- const gchar *id)
-{
- WebKitDOMElement *button;
-
- button = webkit_dom_document_get_element_by_id (
- view->priv->dom_document, id);
- webkit_dom_html_element_set_hidden (
- WEBKIT_DOM_HTML_ELEMENT (button), FALSE);
- g_object_unref (button);
-}
-
void
itip_view_set_mode (ItipView *view,
ItipViewMode mode)
{
- WebKitDOMElement *row, *cell;
- WebKitDOMElement *button;
-
g_return_if_fail (ITIP_IS_VIEW (view));
view->priv->mode = mode;
set_sender_text (view);
- if (!view->priv->dom_document)
+ if (!view->priv->web_extension)
return;
- row = webkit_dom_document_get_element_by_id (
- view->priv->dom_document, TABLE_ROW_BUTTONS);
- cell = webkit_dom_element_get_first_element_child (row);
- do {
- button = webkit_dom_element_get_first_element_child (cell);
- webkit_dom_html_element_set_hidden (
- WEBKIT_DOM_HTML_ELEMENT (button), TRUE);
- g_object_unref (button);
- } while ((cell = webkit_dom_element_get_next_element_sibling (cell)) != NULL);
-
- g_object_unref (row);
+ g_dbus_proxy_call (
+ view->priv->web_extension,
+ "ElementHideChildNodes",
+ g_variant_new ("(tss)", view->priv->page_id, view->priv->part_id, TABLE_ROW_BUTTONS),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
view->priv->is_recur_set = itip_view_get_recur_check_state (view);
@@ -1886,7 +2084,6 @@ void
itip_view_set_item_type (ItipView *view,
ECalClientSourceType type)
{
- WebKitDOMElement *label;
const gchar *header;
gchar *access_key, *html_label;
@@ -1894,12 +2091,9 @@ itip_view_set_item_type (ItipView *view,
view->priv->type = type;
- if (!view->priv->dom_document)
+ if (!view->priv->web_extension)
return;
- label = webkit_dom_document_get_element_by_id (
- view->priv->dom_document, TABLE_ROW_ESCB_LABEL);
-
switch (view->priv->type) {
case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
header = _("_Calendar:");
@@ -1922,12 +2116,18 @@ itip_view_set_item_type (ItipView *view,
html_label = e_mail_formatter_parse_html_mnemonics (header, &access_key);
- webkit_dom_html_element_set_access_key (
- WEBKIT_DOM_HTML_ELEMENT (label), access_key);
- webkit_dom_html_element_set_inner_html (
- WEBKIT_DOM_HTML_ELEMENT (label), html_label, NULL);
+ g_dbus_proxy_call (
+ view->priv->web_extension,
+ "ElementSetAccessKey",
+ g_variant_new ("(tsss)", view->priv->page_id, view->priv->part_id, TABLE_ROW_ESCB_LABEL,
access_key),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+
+ set_inner_html (view, TABLE_ROW_ESCB_LABEL, html_label);
- g_object_unref (label);
g_free (html_label);
if (access_key)
@@ -2080,8 +2280,6 @@ void
itip_view_set_summary (ItipView *view,
const gchar *summary)
{
- WebKitDOMElement *row, *col;
-
g_return_if_fail (ITIP_IS_VIEW (view));
if (view->priv->summary)
@@ -2089,21 +2287,7 @@ itip_view_set_summary (ItipView *view,
view->priv->summary = summary ? g_strstrip (e_utf8_ensure_valid (summary)) : NULL;
- if (!view->priv->dom_document)
- return;
-
- row = webkit_dom_document_get_element_by_id (
- view->priv->dom_document, TABLE_ROW_SUMMARY);
- webkit_dom_html_element_set_hidden (
- WEBKIT_DOM_HTML_ELEMENT (row), (view->priv->summary == NULL));
-
- col = webkit_dom_element_get_last_element_child (row);
- webkit_dom_html_element_set_inner_html (
- WEBKIT_DOM_HTML_ELEMENT (col),
- view->priv->summary ? view->priv->summary : "",
- NULL);
- g_object_unref (row);
- g_object_unref (col);
+ set_area_text (view, TABLE_ROW_SUMMARY, view->priv->summary);
}
const gchar *
@@ -2118,8 +2302,6 @@ void
itip_view_set_location (ItipView *view,
const gchar *location)
{
- WebKitDOMElement *row, *col;
-
g_return_if_fail (ITIP_IS_VIEW (view));
if (view->priv->location)
@@ -2127,21 +2309,7 @@ itip_view_set_location (ItipView *view,
view->priv->location = location ? g_strstrip (e_utf8_ensure_valid (location)) : NULL;
- if (!view->priv->dom_document)
- return;
-
- row = webkit_dom_document_get_element_by_id (
- view->priv->dom_document, TABLE_ROW_LOCATION);
- webkit_dom_html_element_set_hidden (
- WEBKIT_DOM_HTML_ELEMENT (row), (view->priv->location == NULL));
-
- col = webkit_dom_element_get_last_element_child (row);
- webkit_dom_html_element_set_inner_html (
- WEBKIT_DOM_HTML_ELEMENT (col),
- view->priv->location ? view->priv->location : "",
- NULL);
- g_object_unref (row);
- g_object_unref (col);
+ set_area_text (view, TABLE_ROW_LOCATION, view->priv->location);
}
const gchar *
@@ -2156,8 +2324,6 @@ void
itip_view_set_status (ItipView *view,
const gchar *status)
{
- WebKitDOMElement *row, *col;
-
g_return_if_fail (ITIP_IS_VIEW (view));
if (view->priv->status)
@@ -2165,21 +2331,7 @@ itip_view_set_status (ItipView *view,
view->priv->status = status ? g_strstrip (e_utf8_ensure_valid (status)) : NULL;
- if (!view->priv->dom_document)
- return;
-
- row = webkit_dom_document_get_element_by_id (
- view->priv->dom_document, TABLE_ROW_STATUS);
- webkit_dom_html_element_set_hidden (
- WEBKIT_DOM_HTML_ELEMENT (row), (view->priv->status == NULL));
-
- col = webkit_dom_element_get_last_element_child (row);
- webkit_dom_html_element_set_inner_html (
- WEBKIT_DOM_HTML_ELEMENT (col),
- view->priv->status ? view->priv->status : "",
- NULL);
- g_object_unref (row);
- g_object_unref (col);
+ set_area_text (view, TABLE_ROW_STATUS, view->priv->status);
}
const gchar *
@@ -2194,8 +2346,6 @@ void
itip_view_set_comment (ItipView *view,
const gchar *comment)
{
- WebKitDOMElement *row, *col;
-
g_return_if_fail (ITIP_IS_VIEW (view));
if (view->priv->comment)
@@ -2203,21 +2353,7 @@ itip_view_set_comment (ItipView *view,
view->priv->comment = comment ? g_strstrip (e_utf8_ensure_valid (comment)) : NULL;
- if (!view->priv->dom_document)
- return;
-
- row = webkit_dom_document_get_element_by_id (
- view->priv->dom_document, TABLE_ROW_COMMENT);
- webkit_dom_html_element_set_hidden (
- WEBKIT_DOM_HTML_ELEMENT (row), (view->priv->comment == NULL));
-
- col = webkit_dom_element_get_last_element_child (row);
- webkit_dom_html_element_set_inner_html (
- WEBKIT_DOM_HTML_ELEMENT (col),
- view->priv->comment ? view->priv->comment : "",
- NULL);
- g_object_unref (row);
- g_object_unref (col);
+ set_area_text (view, TABLE_ROW_COMMENT, view->priv->comment);
}
const gchar *
@@ -2232,8 +2368,6 @@ void
itip_view_set_description (ItipView *view,
const gchar *description)
{
- WebKitDOMElement *div;
-
g_return_if_fail (ITIP_IS_VIEW (view));
if (view->priv->description)
@@ -2241,19 +2375,11 @@ itip_view_set_description (ItipView *view,
view->priv->description = description ? g_strstrip (e_utf8_ensure_valid (description)) : NULL;
- if (!view->priv->dom_document)
- return;
-
- div = webkit_dom_document_get_element_by_id (
- view->priv->dom_document, TABLE_ROW_DESCRIPTION);
- webkit_dom_html_element_set_hidden (
- WEBKIT_DOM_HTML_ELEMENT (div), (view->priv->description == NULL));
-
- webkit_dom_html_element_set_inner_html (
- WEBKIT_DOM_HTML_ELEMENT (div),
- view->priv->description ? view->priv->description : "",
- NULL);
- g_object_unref (div);
+ hide_element (view, TABLE_ROW_DESCRIPTION, (view->priv->description == NULL));
+ set_inner_html (
+ view,
+ TABLE_ROW_DESCRIPTION,
+ view->priv->description ? view->priv->description : "");
}
const gchar *
@@ -2360,7 +2486,7 @@ itip_view_add_upper_info_item (ItipView *view,
priv->upper_info_items = g_slist_append (priv->upper_info_items, item);
- if (!view->priv->dom_document)
+ if (!view->priv->web_extension)
return item->id;
append_info_item_row (view, TABLE_UPPER_ITIP_INFO, item);
@@ -2410,8 +2536,7 @@ itip_view_remove_upper_info_item (ItipView *view,
g_free (item->message);
g_free (item);
- if (!view->priv->dom_document)
- remove_info_item_row (view, TABLE_UPPER_ITIP_INFO, id);
+ remove_info_item_row (view, TABLE_UPPER_ITIP_INFO, id);
return;
}
@@ -2431,8 +2556,7 @@ itip_view_clear_upper_info_items (ItipView *view)
for (l = priv->upper_info_items; l; l = l->next) {
ItipViewInfoItem *item = l->data;
- if (view->priv->dom_document)
- remove_info_item_row (view, TABLE_UPPER_ITIP_INFO, item->id);
+ remove_info_item_row (view, TABLE_UPPER_ITIP_INFO, item->id);
g_free (item->message);
g_free (item);
@@ -2462,7 +2586,7 @@ itip_view_add_lower_info_item (ItipView *view,
priv->lower_info_items = g_slist_append (priv->lower_info_items, item);
- if (!view->priv->dom_document)
+ if (!view->priv->web_extension)
return item->id;
append_info_item_row (view, TABLE_LOWER_ITIP_INFO, item);
@@ -2512,8 +2636,7 @@ itip_view_remove_lower_info_item (ItipView *view,
g_free (item->message);
g_free (item);
- if (view->priv->dom_document)
- remove_info_item_row (view, TABLE_LOWER_ITIP_INFO, id);
+ remove_info_item_row (view, TABLE_LOWER_ITIP_INFO, id);
return;
}
@@ -2533,8 +2656,7 @@ itip_view_clear_lower_info_items (ItipView *view)
for (l = priv->lower_info_items; l; l = l->next) {
ItipViewInfoItem *item = l->data;
- if (view->priv->dom_document)
- remove_info_item_row (view, TABLE_LOWER_ITIP_INFO, item->id);
+ remove_info_item_row (view, TABLE_LOWER_ITIP_INFO, item->id);
g_free (item->message);
g_free (item);
@@ -2548,112 +2670,124 @@ void
itip_view_set_source (ItipView *view,
ESource *source)
{
- WebKitDOMElement *select;
- WebKitDOMElement *row;
ESource *selected_source;
- gulong i, len;
g_return_if_fail (ITIP_IS_VIEW (view));
d (printf ("Settings default source '%s'\n", e_source_get_display_name (source)));
- if (!view->priv->dom_document)
- return;
+ hide_element (view, TABLE_ROW_ESCB, (source == NULL));
- row = webkit_dom_document_get_element_by_id (
- view->priv->dom_document, TABLE_ROW_ESCB);
- webkit_dom_html_element_set_hidden (
- WEBKIT_DOM_HTML_ELEMENT (row), (source == NULL));
- g_object_unref (row);
- if (source == NULL)
+ if (!source)
return;
- select = webkit_dom_document_get_element_by_id (
- view->priv->dom_document, SELECT_ESOURCE);
-
/* <select> does not emit 'change' event when already selected
* <option> is re-selected, but we need to notify itip formatter,
* so that it would make all the buttons sensitive */
selected_source = itip_view_ref_source (view);
if (source == selected_source) {
- source_changed_cb (select, NULL, view);
+ source_changed_cb (view);
return;
}
if (selected_source != NULL)
g_object_unref (selected_source);
- if (webkit_dom_html_select_element_get_disabled (
- WEBKIT_DOM_HTML_SELECT_ELEMENT (select))) {
- webkit_dom_html_select_element_set_disabled (
- WEBKIT_DOM_HTML_SELECT_ELEMENT (select), FALSE);
- }
-
- len = webkit_dom_html_select_element_get_length (
- WEBKIT_DOM_HTML_SELECT_ELEMENT (select));
- for (i = 0; i < len; i++) {
-
- WebKitDOMNode *node;
- WebKitDOMHTMLOptionElement *option;
- gchar *value;
-
- node = webkit_dom_html_select_element_item (
- WEBKIT_DOM_HTML_SELECT_ELEMENT (select), i);
- option = WEBKIT_DOM_HTML_OPTION_ELEMENT (node);
-
- value = webkit_dom_html_option_element_get_value (option);
- if (g_strcmp0 (value, e_source_get_uid (source)) == 0) {
- webkit_dom_html_option_element_set_selected (
- option, TRUE);
-
- g_free (value);
- break;
- }
+ if (!view->priv->web_extension)
+ return;
- g_object_unref (node);
- g_free (value);
- }
+ g_dbus_proxy_call (
+ view->priv->web_extension,
+ "EnableSelect",
+ g_variant_new ("(tssb)", view->priv->page_id, view->priv->part_id, SELECT_ESOURCE, TRUE),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
- source_changed_cb (select, NULL, view);
+ g_dbus_proxy_call (
+ view->priv->web_extension,
+ "SelectSetSelected",
+ g_variant_new ("(tsss)", view->priv->page_id, view->priv->part_id, SELECT_ESOURCE,
e_source_get_uid (source)),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
- g_object_unref (select);
+ source_changed_cb (view);
}
ESource *
itip_view_ref_source (ItipView *view)
{
- WebKitDOMElement *select;
- gchar *uid;
- ESource *source;
- gboolean disable = FALSE;
+ ESource *source = NULL;
+ gboolean disable = FALSE, enabled = FALSE;
+ GVariant *result;
g_return_val_if_fail (ITIP_IS_VIEW (view), NULL);
- if (!view->priv->dom_document)
+ if (!view->priv->web_extension)
return NULL;
- select = webkit_dom_document_get_element_by_id (
- view->priv->dom_document, SELECT_ESOURCE);
- if (webkit_dom_html_select_element_get_disabled (
- WEBKIT_DOM_HTML_SELECT_ELEMENT (select))) {
- webkit_dom_html_select_element_set_disabled (
- WEBKIT_DOM_HTML_SELECT_ELEMENT (select), FALSE);
+ result = g_dbus_proxy_call_sync (
+ view->priv->web_extension,
+ "SelectIsEnabled",
+ g_variant_new ("(tss)", view->priv->page_id, view->priv->part_id, SELECT_ESOURCE),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL);
+
+ if (result) {
+ g_variant_get (result, "(b)", &enabled);
+ g_variant_unref (result);
+ }
+
+ if (enabled) {
+ g_dbus_proxy_call (
+ view->priv->web_extension,
+ "EnableSelect",
+ g_variant_new ("(tssb)", view->priv->page_id, view->priv->part_id, SELECT_ESOURCE,
TRUE),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+
disable = TRUE;
}
- uid = webkit_dom_html_select_element_get_value (
- WEBKIT_DOM_HTML_SELECT_ELEMENT (select));
+ result = g_dbus_proxy_call_sync (
+ view->priv->web_extension,
+ "SelectGetValue",
+ g_variant_new ("(tss)", view->priv->page_id, view->priv->part_id, SELECT_ESOURCE),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL);
- source = e_source_registry_ref_source (view->priv->registry, uid);
+ if (result) {
+ const gchar *uid;
- g_free (uid);
+ g_variant_get (result, "(&s)", &uid);
+ source = e_source_registry_ref_source (view->priv->registry, uid);
+ g_variant_unref (result);
+ }
if (disable) {
- webkit_dom_html_select_element_set_disabled (
- WEBKIT_DOM_HTML_SELECT_ELEMENT (select), TRUE);
+ g_dbus_proxy_call (
+ view->priv->web_extension,
+ "EnableSelect",
+ g_variant_new ("(tssb)", view->priv->page_id, view->priv->part_id, SELECT_ESOURCE,
FALSE),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
}
- g_object_unref (select);
return source;
}
@@ -2661,227 +2795,137 @@ void
itip_view_set_rsvp (ItipView *view,
gboolean rsvp)
{
- WebKitDOMElement *el;
-
g_return_if_fail (ITIP_IS_VIEW (view));
- if (!view->priv->dom_document)
+ if (!view->priv->web_extension)
return;
- el = webkit_dom_document_get_element_by_id (
- view->priv->dom_document, CHECKBOX_RSVP);
- webkit_dom_html_input_element_set_checked (
- WEBKIT_DOM_HTML_INPUT_ELEMENT (el), rsvp);
- g_object_unref (el);
+ input_set_checked (view, CHECKBOX_RSVP, rsvp);
- el = webkit_dom_document_get_element_by_id (
- view->priv->dom_document, TEXTAREA_RSVP_COMMENT);
- webkit_dom_html_text_area_element_set_disabled (
- WEBKIT_DOM_HTML_TEXT_AREA_ELEMENT (el), !rsvp);
- g_object_unref (el);
+ g_dbus_proxy_call (
+ view->priv->web_extension,
+ "EnableTextArea",
+ g_variant_new ("(tssb)", view->priv->page_id, view->priv->part_id, TEXTAREA_RSVP_COMMENT,
!rsvp),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
}
gboolean
itip_view_get_rsvp (ItipView *view)
{
- gboolean value;
- WebKitDOMElement *el;
-
g_return_val_if_fail (ITIP_IS_VIEW (view), FALSE);
- if (!view->priv->dom_document)
- return FALSE;
-
- el = webkit_dom_document_get_element_by_id (
- view->priv->dom_document, CHECKBOX_RSVP);
- value = webkit_dom_html_input_element_get_checked (WEBKIT_DOM_HTML_INPUT_ELEMENT (el));
- g_object_unref (el);
- return value;
+ return input_is_checked (view, CHECKBOX_RSVP);
}
void
itip_view_set_show_rsvp_check (ItipView *view,
gboolean show)
{
- WebKitDOMElement *label;
- WebKitDOMElement *el;
-
g_return_if_fail (ITIP_IS_VIEW (view));
- if (!view->priv->dom_document)
- return;
-
- el = webkit_dom_document_get_element_by_id (
- view->priv->dom_document, "table_row_" CHECKBOX_RSVP);
- webkit_dom_html_element_set_hidden (WEBKIT_DOM_HTML_ELEMENT (el), !show);
- g_object_unref (el);
-
- el = webkit_dom_document_get_element_by_id (
- view->priv->dom_document, CHECKBOX_RSVP);
- label = webkit_dom_element_get_next_element_sibling (el);
- webkit_dom_html_element_set_hidden (WEBKIT_DOM_HTML_ELEMENT (label), !show);
- g_object_unref (label);
-
- if (!show) {
- webkit_dom_html_input_element_set_checked (
- WEBKIT_DOM_HTML_INPUT_ELEMENT (el), FALSE);
- }
- g_object_unref (el);
-
- el = webkit_dom_document_get_element_by_id (
- view->priv->dom_document, TABLE_ROW_RSVP_COMMENT);
- webkit_dom_html_element_set_hidden (WEBKIT_DOM_HTML_ELEMENT (el), !show);
- g_object_unref (el);
+ show_checkbox (view, CHECKBOX_RSVP, show, FALSE);
+ hide_element (view, TABLE_ROW_RSVP_COMMENT, !show);
}
gboolean
itip_view_get_show_rsvp_check (ItipView *view)
{
- gboolean value;
- WebKitDOMElement *el;
-
g_return_val_if_fail (ITIP_IS_VIEW (view), FALSE);
- if (!view->priv->dom_document)
- return FALSE;
-
- el = webkit_dom_document_get_element_by_id (
- view->priv->dom_document, CHECKBOX_RSVP);
- value = webkit_dom_html_element_get_hidden (WEBKIT_DOM_HTML_ELEMENT (el));
- g_object_unref (el);
- return !value;
+ return !element_is_hidden (view, CHECKBOX_RSVP);
}
void
itip_view_set_update (ItipView *view,
gboolean update)
{
- WebKitDOMElement *el;
-
g_return_if_fail (ITIP_IS_VIEW (view));
- if (!view->priv->dom_document)
- return;
-
- el = webkit_dom_document_get_element_by_id (
- view->priv->dom_document, CHECKBOX_UPDATE);
-
- webkit_dom_html_input_element_set_checked (
- WEBKIT_DOM_HTML_INPUT_ELEMENT (el), update);
- g_object_unref (el);
+ input_set_checked (view, CHECKBOX_UPDATE, update);
}
gboolean
itip_view_get_update (ItipView *view)
{
- gboolean value;
- WebKitDOMElement *el;
-
g_return_val_if_fail (ITIP_IS_VIEW (view), FALSE);
- if (!view->priv->dom_document)
- return FALSE;
-
- el = webkit_dom_document_get_element_by_id (
- view->priv->dom_document, CHECKBOX_UPDATE);
- value = webkit_dom_html_input_element_get_checked (WEBKIT_DOM_HTML_INPUT_ELEMENT (el));
- g_object_unref (el);
- return value;
+ return input_is_checked (view, CHECKBOX_UPDATE);
}
void
itip_view_set_show_update_check (ItipView *view,
gboolean show)
{
- WebKitDOMElement *label;
- WebKitDOMElement *el;
-
g_return_if_fail (ITIP_IS_VIEW (view));
- if (!view->priv->dom_document)
- return;
-
- el = webkit_dom_document_get_element_by_id (
- view->priv->dom_document, "table_row_" CHECKBOX_UPDATE);
- webkit_dom_html_element_set_hidden (WEBKIT_DOM_HTML_ELEMENT (el), !show);
- g_object_unref (el);
-
- el = webkit_dom_document_get_element_by_id (
- view->priv->dom_document, CHECKBOX_UPDATE);
- label = webkit_dom_element_get_next_element_sibling (el);
- webkit_dom_html_element_set_hidden (WEBKIT_DOM_HTML_ELEMENT (label), !show);
- g_object_unref (label);
-
- if (!show) {
- webkit_dom_html_input_element_set_checked (
- WEBKIT_DOM_HTML_INPUT_ELEMENT (el), FALSE);
- }
- g_object_unref (el);
+ show_checkbox (view, CHECKBOX_UPDATE, show, FALSE);
}
gboolean
itip_view_get_show_update_check (ItipView *view)
{
- gboolean value;
- WebKitDOMElement *el;
-
g_return_val_if_fail (ITIP_IS_VIEW (view), FALSE);
- if (!view->priv->dom_document)
- return FALSE;
-
- el = webkit_dom_document_get_element_by_id (
- view->priv->dom_document, CHECKBOX_UPDATE);
- value = webkit_dom_html_element_get_hidden (WEBKIT_DOM_HTML_ELEMENT (el));
- g_object_unref (el);
- return !value;
+ return !element_is_hidden (view, CHECKBOX_UPDATE);
}
void
itip_view_set_rsvp_comment (ItipView *view,
const gchar *comment)
{
- WebKitDOMElement *el;
-
g_return_if_fail (ITIP_IS_VIEW (view));
- if (!view->priv->dom_document)
+ if (!view->priv->web_extension)
return;
- el = webkit_dom_document_get_element_by_id (
- view->priv->dom_document, TEXTAREA_RSVP_COMMENT);
- webkit_dom_html_element_set_hidden (
- WEBKIT_DOM_HTML_ELEMENT (el), (comment == NULL));
-
if (comment) {
- webkit_dom_html_text_area_element_set_value (
- WEBKIT_DOM_HTML_TEXT_AREA_ELEMENT (el), comment);
+ g_dbus_proxy_call (
+ view->priv->web_extension,
+ "TextAreaSetValue",
+ g_variant_new ("(tsss)", view->priv->page_id, view->priv->part_id,
TEXTAREA_RSVP_COMMENT, comment),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
}
- g_object_unref (el);
}
gchar *
itip_view_get_rsvp_comment (ItipView *view)
{
- gchar *value;
- WebKitDOMElement *el;
+ GVariant *result;
g_return_val_if_fail (ITIP_IS_VIEW (view), NULL);
- if (!view->priv->dom_document)
+ if (!view->priv->web_extension)
return NULL;
- el = webkit_dom_document_get_element_by_id (
- view->priv->dom_document, TEXTAREA_RSVP_COMMENT);
-
- if (webkit_dom_html_element_get_hidden (WEBKIT_DOM_HTML_ELEMENT (el))) {
+ if (element_is_hidden (view, TEXTAREA_RSVP_COMMENT))
return NULL;
+
+ result = g_dbus_proxy_call_sync (
+ view->priv->web_extension,
+ "TextAreaGetValue",
+ g_variant_new ("(tss)", view->priv->page_id, view->priv->part_id, TEXTAREA_RSVP_COMMENT),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL);
+
+ if (result) {
+ gchar *value;
+
+ g_variant_get (result, "(s)", &value);
+ g_variant_unref (result);
+ return value;
}
- value = webkit_dom_html_text_area_element_get_value (
- WEBKIT_DOM_HTML_TEXT_AREA_ELEMENT (el));
- g_object_unref (el);
- return value;
+ return NULL;
}
void
@@ -2897,77 +2941,24 @@ void
itip_view_set_buttons_sensitive (ItipView *view,
gboolean sensitive)
{
- WebKitDOMElement *el, *cell;
-
g_return_if_fail (ITIP_IS_VIEW (view));
d (printf ("Settings buttons %s\n", sensitive ? "sensitive" : "insensitive"));
view->priv->buttons_sensitive = sensitive;
- if (!view->priv->dom_document)
+ if (!view->priv->web_extension)
return;
- el = webkit_dom_document_get_element_by_id (
- view->priv->dom_document, CHECKBOX_UPDATE);
- webkit_dom_html_input_element_set_disabled (
- WEBKIT_DOM_HTML_INPUT_ELEMENT (el), !sensitive);
- g_object_unref (el);
-
- el = webkit_dom_document_get_element_by_id (
- view->priv->dom_document, CHECKBOX_RECUR);
- webkit_dom_html_input_element_set_disabled (
- WEBKIT_DOM_HTML_INPUT_ELEMENT (el), !sensitive);
- g_object_unref (el);
-
- el = webkit_dom_document_get_element_by_id (
- view->priv->dom_document, CHECKBOX_FREE_TIME);
- webkit_dom_html_input_element_set_disabled (
- WEBKIT_DOM_HTML_INPUT_ELEMENT (el), !sensitive);
- g_object_unref (el);
-
- el = webkit_dom_document_get_element_by_id (
- view->priv->dom_document, CHECKBOX_KEEP_ALARM);
- webkit_dom_html_input_element_set_disabled (
- WEBKIT_DOM_HTML_INPUT_ELEMENT (el), !sensitive);
- g_object_unref (el);
-
- el = webkit_dom_document_get_element_by_id (
- view->priv->dom_document, CHECKBOX_INHERIT_ALARM);
- webkit_dom_html_input_element_set_disabled (
- WEBKIT_DOM_HTML_INPUT_ELEMENT (el), !sensitive);
- g_object_unref (el);
-
- el = webkit_dom_document_get_element_by_id (
- view->priv->dom_document, CHECKBOX_RSVP);
- webkit_dom_html_input_element_set_disabled (
- WEBKIT_DOM_HTML_INPUT_ELEMENT (el), !sensitive);
- g_object_unref (el);
-
- el = webkit_dom_document_get_element_by_id (
- view->priv->dom_document, TEXTAREA_RSVP_COMMENT);
- webkit_dom_html_text_area_element_set_disabled (
- WEBKIT_DOM_HTML_TEXT_AREA_ELEMENT (el), !sensitive);
- g_object_unref (el);
-
- el = webkit_dom_document_get_element_by_id (
- view->priv->dom_document, TABLE_ROW_BUTTONS);
- cell = webkit_dom_element_get_first_element_child (el);
- do {
- WebKitDOMElement *btn, *next_cell;
-
- next_cell = webkit_dom_element_get_next_element_sibling (cell);
- btn = webkit_dom_element_get_first_element_child (cell);
- if (!webkit_dom_html_element_get_hidden (
- WEBKIT_DOM_HTML_ELEMENT (btn))) {
- webkit_dom_html_button_element_set_disabled (
- WEBKIT_DOM_HTML_BUTTON_ELEMENT (btn), !sensitive);
- }
- g_object_unref (btn);
- g_object_unref (cell);
- cell = next_cell;
- } while (cell);
- g_object_unref (el);
+ g_dbus_proxy_call (
+ view->priv->web_extension,
+ "SetButtonsSensitive",
+ g_variant_new ("(tsb)", view->priv->page_id, view->priv->part_id, sensitive),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
}
gboolean
@@ -2981,217 +2972,69 @@ itip_view_get_buttons_sensitive (ItipView *view)
gboolean
itip_view_get_recur_check_state (ItipView *view)
{
- gboolean value;
- WebKitDOMElement *el;
-
g_return_val_if_fail (ITIP_IS_VIEW (view), FALSE);
- if (!view->priv->dom_document)
- return FALSE;
-
- el = webkit_dom_document_get_element_by_id (
- view->priv->dom_document, CHECKBOX_RECUR);
- value = webkit_dom_html_input_element_get_checked (
- WEBKIT_DOM_HTML_INPUT_ELEMENT (el));
- g_object_unref (el);
- return value;
+ return input_is_checked (view, CHECKBOX_RECUR);
}
void
itip_view_set_show_recur_check (ItipView *view,
gboolean show)
{
- WebKitDOMElement *label;
- WebKitDOMElement *el;
-
g_return_if_fail (ITIP_IS_VIEW (view));
- if (!view->priv->dom_document)
- return;
-
- el = webkit_dom_document_get_element_by_id (
- view->priv->dom_document, "table_row_" CHECKBOX_RECUR);
- webkit_dom_html_element_set_hidden (WEBKIT_DOM_HTML_ELEMENT (el), !show);
- g_object_unref (el);
-
- el = webkit_dom_document_get_element_by_id (
- view->priv->dom_document, CHECKBOX_RECUR);
- label = webkit_dom_element_get_next_element_sibling (el);
- webkit_dom_html_element_set_hidden (WEBKIT_DOM_HTML_ELEMENT (label), !show);
- g_object_unref (label);
-
- if (!show) {
- webkit_dom_html_input_element_set_checked (
- WEBKIT_DOM_HTML_INPUT_ELEMENT (el), FALSE);
- }
-
- /* and update state of the second check */
- alarm_check_toggled_cb (
- WEBKIT_DOM_HTML_INPUT_ELEMENT (el),
- NULL, view);
- g_object_unref (el);
+ show_checkbox (view, CHECKBOX_RECUR, show, TRUE);
}
void
itip_view_set_show_free_time_check (ItipView *view,
gboolean show)
{
- WebKitDOMElement *label;
- WebKitDOMElement *el;
-
g_return_if_fail (ITIP_IS_VIEW (view));
- if (!view->priv->dom_document)
- return;
-
- el = webkit_dom_document_get_element_by_id (
- view->priv->dom_document, "table_row_" CHECKBOX_FREE_TIME);
- webkit_dom_html_element_set_hidden (WEBKIT_DOM_HTML_ELEMENT (el), !show);
- g_object_unref (el);
-
- el = webkit_dom_document_get_element_by_id (
- view->priv->dom_document, CHECKBOX_FREE_TIME);
- label = webkit_dom_element_get_next_element_sibling (el);
- webkit_dom_html_element_set_hidden (WEBKIT_DOM_HTML_ELEMENT (label), !show);
- g_object_unref (label);
-
- if (!show) {
- webkit_dom_html_input_element_set_checked (
- WEBKIT_DOM_HTML_INPUT_ELEMENT (el), FALSE);
- }
-
- /* and update state of the second check */
- alarm_check_toggled_cb (
- WEBKIT_DOM_HTML_INPUT_ELEMENT (el),
- NULL, view);
- g_object_unref (el);
+ show_checkbox (view, CHECKBOX_FREE_TIME, show, TRUE);
}
gboolean
itip_view_get_free_time_check_state (ItipView *view)
{
- gboolean value;
- WebKitDOMElement *el;
-
g_return_val_if_fail (ITIP_IS_VIEW (view), FALSE);
- if (!view->priv->dom_document)
- return FALSE;
-
- el = webkit_dom_document_get_element_by_id (
- view->priv->dom_document, CHECKBOX_FREE_TIME);
- value = webkit_dom_html_input_element_get_checked (
- WEBKIT_DOM_HTML_INPUT_ELEMENT (el));
- g_object_unref (el);
- return value;
+ return input_is_checked (view, CHECKBOX_FREE_TIME);
}
void
itip_view_set_show_keep_alarm_check (ItipView *view,
gboolean show)
{
- WebKitDOMElement *label;
- WebKitDOMElement *el;
-
g_return_if_fail (ITIP_IS_VIEW (view));
- if (!view->priv->dom_document)
- return;
-
- el = webkit_dom_document_get_element_by_id (
- view->priv->dom_document, "table_row_" CHECKBOX_KEEP_ALARM);
- webkit_dom_html_element_set_hidden (WEBKIT_DOM_HTML_ELEMENT (el), !show);
- g_object_unref (el);
-
- el = webkit_dom_document_get_element_by_id (
- view->priv->dom_document, CHECKBOX_KEEP_ALARM);
- label = webkit_dom_element_get_next_element_sibling (el);
- webkit_dom_html_element_set_hidden (WEBKIT_DOM_HTML_ELEMENT (label), !show);
- g_object_unref (label);
-
- if (!show) {
- webkit_dom_html_input_element_set_checked (
- WEBKIT_DOM_HTML_INPUT_ELEMENT (el), FALSE);
- }
-
- /* and update state of the second check */
- alarm_check_toggled_cb (
- WEBKIT_DOM_HTML_INPUT_ELEMENT (el),
- NULL, view);
- g_object_unref (el);
+ show_checkbox (view, CHECKBOX_KEEP_ALARM, show, TRUE);
}
gboolean
itip_view_get_keep_alarm_check_state (ItipView *view)
{
- gboolean value;
- WebKitDOMElement *el;
-
g_return_val_if_fail (ITIP_IS_VIEW (view), FALSE);
- if (!view->priv->dom_document)
- return FALSE;
-
- el = webkit_dom_document_get_element_by_id (
- view->priv->dom_document, CHECKBOX_KEEP_ALARM);
- value = webkit_dom_html_input_element_get_checked (
- WEBKIT_DOM_HTML_INPUT_ELEMENT (el));
- g_object_unref (el);
- return value;
+ return input_is_checked (view, CHECKBOX_KEEP_ALARM);
}
void
itip_view_set_show_inherit_alarm_check (ItipView *view,
gboolean show)
{
- WebKitDOMElement *label;
- WebKitDOMElement *el;
-
g_return_if_fail (ITIP_IS_VIEW (view));
- if (!view->priv->dom_document)
- return;
-
- el = webkit_dom_document_get_element_by_id (
- view->priv->dom_document, "table_row_" CHECKBOX_INHERIT_ALARM);
- webkit_dom_html_element_set_hidden (WEBKIT_DOM_HTML_ELEMENT (el), !show);
- g_object_unref (el);
-
- el = webkit_dom_document_get_element_by_id (
- view->priv->dom_document, CHECKBOX_INHERIT_ALARM);
- label = webkit_dom_element_get_next_element_sibling (el);
- webkit_dom_html_element_set_hidden (WEBKIT_DOM_HTML_ELEMENT (label), !show);
- g_object_unref (label);
-
- if (!show) {
- webkit_dom_html_input_element_set_checked (
- WEBKIT_DOM_HTML_INPUT_ELEMENT (el), FALSE);
- }
-
- /* and update state of the second check */
- alarm_check_toggled_cb (
- WEBKIT_DOM_HTML_INPUT_ELEMENT (el),
- NULL, view);
- g_object_unref (el);
+ show_checkbox (view, CHECKBOX_INHERIT_ALARM, show, TRUE);
}
gboolean
itip_view_get_inherit_alarm_check_state (ItipView *view)
{
- gboolean value;
- WebKitDOMElement *el;
-
g_return_val_if_fail (ITIP_IS_VIEW (view), FALSE);
- if (!view->priv->dom_document)
- return FALSE;
-
- el = webkit_dom_document_get_element_by_id (
- view->priv->dom_document, CHECKBOX_INHERIT_ALARM);
- value = webkit_dom_html_input_element_get_checked (
- WEBKIT_DOM_HTML_INPUT_ELEMENT (el));
- g_object_unref (el);
- return value;
+ return input_is_checked (view, CHECKBOX_INHERIT_ALARM);
}
void
@@ -3199,7 +3042,6 @@ itip_view_set_error (ItipView *view,
const gchar *error_html,
gboolean show_save_btn)
{
- WebKitDOMElement *content, *error;
GString *str;
g_return_if_fail (ITIP_IS_VIEW (view));
@@ -3214,7 +3056,7 @@ itip_view_set_error (ItipView *view,
"<tr width=\"100%\" id=\"" TABLE_ROW_BUTTONS "\">");
buttons_table_write_button (
- str, BUTTON_SAVE, _("Sa_ve"),
+ str, view->priv->itip_part_ptr, BUTTON_SAVE, _("Sa_ve"),
"document-save", ITIP_VIEW_RESPONSE_SAVE);
g_string_append (str, "</tr></table>");
@@ -3223,43 +3065,24 @@ itip_view_set_error (ItipView *view,
view->priv->error = str->str;
g_string_free (str, FALSE);
- if (!view->priv->dom_document)
+ if (!view->priv->web_extension)
return;
- content = webkit_dom_document_get_element_by_id (
- view->priv->dom_document, DIV_ITIP_CONTENT);
- webkit_dom_html_element_set_hidden (
- WEBKIT_DOM_HTML_ELEMENT (content), TRUE);
- g_object_unref (content);
-
- error = webkit_dom_document_get_element_by_id (
- view->priv->dom_document, DIV_ITIP_ERROR);
- webkit_dom_html_element_set_hidden (
- WEBKIT_DOM_HTML_ELEMENT (error), FALSE);
-
- webkit_dom_html_element_set_inner_html (
- WEBKIT_DOM_HTML_ELEMENT (error), view->priv->error, NULL);
- g_object_unref (error);
+ hide_element (view, DIV_ITIP_CONTENT, TRUE);
+ hide_element (view, DIV_ITIP_ERROR, FALSE);
+ set_inner_html (view, DIV_ITIP_ERROR, view->priv->error);
if (show_save_btn) {
- WebKitDOMElement *el;
-
show_button (view, BUTTON_SAVE);
+ enable_button (view, BUTTON_SAVE, TRUE);
- el = webkit_dom_document_get_element_by_id (
- view->priv->dom_document, BUTTON_SAVE);
- webkit_dom_html_button_element_set_disabled (
- WEBKIT_DOM_HTML_BUTTON_ELEMENT (el), FALSE);
- webkit_dom_event_target_add_event_listener (
- WEBKIT_DOM_EVENT_TARGET (el), "click",
- G_CALLBACK (button_clicked_cb), FALSE, view);
+ itip_view_register_clicked_listener (view);
}
}
/******************************************************************************/
typedef struct {
- EMailPartItip *puri;
ItipView *view;
GCancellable *itip_cancellable;
GCancellable *cancellable;
@@ -3350,7 +3173,6 @@ find_attendee_if_sentby (icalcomponent *ical_comp,
static void
find_to_address (ItipView *view,
- EMailPartItip *itip_part,
icalcomponent *ical_comp,
icalparameter_partstat *status)
{
@@ -3362,26 +3184,26 @@ find_to_address (ItipView *view,
registry = view->priv->registry;
extension_name = E_SOURCE_EXTENSION_MAIL_IDENTITY;
- if (itip_part->to_address != NULL)
+ if (view->priv->to_address != NULL)
return;
- if (itip_part->msg != NULL && itip_part->folder != NULL) {
+ if (view->priv->message != NULL && view->priv->folder != NULL) {
ESource *source;
source = em_utils_guess_mail_identity (
- registry, itip_part->msg,
- itip_part->folder, itip_part->uid);
+ registry, view->priv->message,
+ view->priv->folder, view->priv->message_uid);
if (source != NULL) {
extension = e_source_get_extension (source, extension_name);
- itip_part->to_address = e_source_mail_identity_dup_address (extension);
+ view->priv->to_address = e_source_mail_identity_dup_address (extension);
g_object_unref (source);
}
}
- if (itip_part->to_address != NULL)
+ if (view->priv->to_address != NULL)
return;
/* Look through the list of attendees to find the user's address */
@@ -3403,20 +3225,20 @@ find_to_address (ItipView *view,
param = icalproperty_get_first_parameter (prop, ICAL_CN_PARAMETER);
if (param != NULL)
- itip_part->to_name = g_strdup (icalparameter_get_cn (param));
+ view->priv->to_name = g_strdup (icalparameter_get_cn (param));
text = icalproperty_get_value_as_string_r (prop);
- itip_part->to_address = g_strdup (itip_strip_mailto (text));
+ view->priv->to_address = g_strdup (itip_strip_mailto (text));
g_free (text);
- g_strstrip (itip_part->to_address);
+ g_strstrip (view->priv->to_address);
- itip_part->my_address = g_strdup (address);
+ view->priv->my_address = g_strdup (address);
param = icalproperty_get_first_parameter (prop, ICAL_RSVP_PARAMETER);
if (param != NULL &&
icalparameter_get_rsvp (param) == ICAL_RSVP_FALSE)
- itip_part->no_reply_wanted = TRUE;
+ view->priv->no_reply_wanted = TRUE;
if (status) {
param = icalproperty_get_first_parameter (prop, ICAL_PARTSTAT_PARAMETER);
@@ -3428,7 +3250,7 @@ find_to_address (ItipView *view,
g_list_free_full (list, (GDestroyNotify) g_object_unref);
- if (itip_part->to_address != NULL)
+ if (view->priv->to_address != NULL)
return;
/* If the user's address was not found in the attendee's list,
@@ -3461,20 +3283,20 @@ find_to_address (ItipView *view,
param = icalproperty_get_first_parameter (prop, ICAL_CN_PARAMETER);
if (param != NULL)
- itip_part->to_name = g_strdup (icalparameter_get_cn (param));
+ view->priv->to_name = g_strdup (icalparameter_get_cn (param));
text = icalproperty_get_value_as_string_r (prop);
- itip_part->to_address = g_strdup (itip_strip_mailto (text));
+ view->priv->to_address = g_strdup (itip_strip_mailto (text));
g_free (text);
- g_strstrip (itip_part->to_address);
+ g_strstrip (view->priv->to_address);
- itip_part->my_address = g_strdup (address);
+ view->priv->my_address = g_strdup (address);
param = icalproperty_get_first_parameter (prop, ICAL_RSVP_PARAMETER);
if (param != NULL &&
ICAL_RSVP_FALSE == icalparameter_get_rsvp (param))
- itip_part->no_reply_wanted = TRUE;
+ view->priv->no_reply_wanted = TRUE;
if (status) {
param = icalproperty_get_first_parameter (prop, ICAL_PARTSTAT_PARAMETER);
@@ -3489,7 +3311,6 @@ find_to_address (ItipView *view,
static void
find_from_address (ItipView *view,
- EMailPartItip *pitip,
icalcomponent *ical_comp)
{
ESourceRegistry *registry;
@@ -3528,11 +3349,11 @@ find_from_address (ItipView *view,
if (!(organizer_sentby_clean || organizer_clean))
return;
- pitip->from_address = g_strdup (organizer_clean);
+ view->priv->from_address = g_strdup (organizer_clean);
param = icalproperty_get_first_parameter (prop, ICAL_CN_PARAMETER);
if (param)
- pitip->from_name = g_strdup (icalparameter_get_cn (param));
+ view->priv->from_name = g_strdup (icalparameter_get_cn (param));
extension_name = E_SOURCE_EXTENSION_MAIL_IDENTITY;
list = e_source_registry_list_enabled (registry, extension_name);
@@ -3550,7 +3371,7 @@ find_from_address (ItipView *view,
if ((organizer_clean && !g_ascii_strcasecmp (organizer_clean, address))
|| (organizer_sentby_clean && !g_ascii_strcasecmp (organizer_sentby_clean, address))) {
- pitip->my_address = g_strdup (address);
+ view->priv->my_address = g_strdup (address);
break;
}
@@ -3563,14 +3384,14 @@ find_from_address (ItipView *view,
}
static ECalComponent *
-get_real_item (EMailPartItip *pitip)
+get_real_item (ItipView *view)
{
ECalComponent *comp = NULL;
ESource *source;
- source = e_client_get_source (E_CLIENT (pitip->current_client));
+ source = e_client_get_source (E_CLIENT (view->priv->current_client));
if (source)
- comp = g_hash_table_lookup (pitip->real_comps, e_source_get_uid (source));
+ comp = g_hash_table_lookup (view->priv->real_comps, e_source_get_uid (source));
if (!comp) {
return NULL;
@@ -3580,12 +3401,12 @@ get_real_item (EMailPartItip *pitip)
}
static void
-adjust_item (EMailPartItip *pitip,
+adjust_item (ItipView *view,
ECalComponent *comp)
{
ECalComponent *real_comp;
- real_comp = get_real_item (pitip);
+ real_comp = get_real_item (view);
if (real_comp != NULL) {
ECalComponentText text;
const gchar *string;
@@ -3608,16 +3429,16 @@ adjust_item (EMailPartItip *pitip,
}
static gboolean
-same_attendee_status (EMailPartItip *pitip,
+same_attendee_status (ItipView *view,
ECalComponent *received_comp)
{
ECalComponent *saved_comp;
GSList *received_attendees = NULL, *saved_attendees = NULL, *riter, *siter;
gboolean same = FALSE;
- g_return_val_if_fail (pitip != NULL, FALSE);
+ g_return_val_if_fail (ITIP_IS_VIEW (view), FALSE);
- saved_comp = get_real_item (pitip);
+ saved_comp = get_real_item (view);
if (!saved_comp)
return FALSE;
@@ -3662,31 +3483,22 @@ same_attendee_status (EMailPartItip *pitip,
}
static void
-set_buttons_sensitive (EMailPartItip *pitip,
- ItipView *view)
+set_buttons_sensitive (ItipView *view)
{
- gboolean enabled = pitip->current_client != NULL;
+ gboolean enabled = view->priv->current_client != NULL;
- if (enabled && pitip->current_client)
- enabled = !e_client_is_readonly (E_CLIENT (pitip->current_client));
+ if (enabled && view->priv->current_client)
+ enabled = !e_client_is_readonly (E_CLIENT (view->priv->current_client));
itip_view_set_buttons_sensitive (view, enabled);
if (enabled && itip_view_get_mode (view) == ITIP_VIEW_MODE_REPLY &&
- pitip->comp && same_attendee_status (pitip, pitip->comp)) {
+ view->priv->comp && same_attendee_status (view, view->priv->comp)) {
itip_view_add_lower_info_item (
view, ITIP_VIEW_INFO_ITEM_TYPE_INFO,
_("Attendee status updated"));
- if (view->priv->dom_document) {
- WebKitDOMElement *el;
-
- el = webkit_dom_document_get_element_by_id (
- view->priv->dom_document, BUTTON_UPDATE_ATTENDEE_STATUS);
- webkit_dom_html_button_element_set_disabled (
- WEBKIT_DOM_HTML_BUTTON_ELEMENT (el), TRUE);
- g_object_unref (el);
- }
+ enable_button (view, BUTTON_UPDATE_ATTENDEE_STATUS, FALSE);
}
}
@@ -3707,12 +3519,10 @@ itip_view_cal_opened_cb (GObject *source_object,
gpointer user_data)
{
ItipView *view;
- EMailPartItip *pitip;
EClient *client;
GError *error = NULL;
view = ITIP_VIEW (user_data);
- pitip = itip_view_get_mail_part (view);
client = e_client_cache_get_client_finish (
E_CLIENT_CACHE (source_object), result, &error);
@@ -3737,13 +3547,13 @@ itip_view_cal_opened_cb (GObject *source_object,
icalcomponent *icalcomp;
gboolean show_recur_check;
- icalcomp = e_cal_component_get_icalcomponent (pitip->comp);
+ icalcomp = e_cal_component_get_icalcomponent (view->priv->comp);
show_recur_check = check_is_instance (icalcomp);
itip_view_set_show_recur_check (view, show_recur_check);
}
- if (pitip->type == E_CAL_CLIENT_SOURCE_TYPE_MEMOS) {
+ if (view->priv->type == E_CAL_CLIENT_SOURCE_TYPE_MEMOS) {
gboolean needs_decline;
needs_decline = e_client_check_capability (
@@ -3753,9 +3563,9 @@ itip_view_cal_opened_cb (GObject *source_object,
itip_view_set_mode (view, ITIP_VIEW_MODE_PUBLISH);
}
- pitip->current_client = g_object_ref (client);
+ view->priv->current_client = g_object_ref (client);
- set_buttons_sensitive (pitip, view);
+ set_buttons_sensitive (view);
exit:
g_clear_object (&client);
@@ -3763,8 +3573,7 @@ exit:
}
static void
-start_calendar_server (EMailPartItip *pitip,
- ItipView *view,
+start_calendar_server (ItipView *view,
ESource *source,
ECalClientSourceType type,
GAsyncReadyCallback func,
@@ -3793,12 +3602,11 @@ start_calendar_server (EMailPartItip *pitip,
e_client_cache_get_client (
client_cache, source, extension_name, 30,
- pitip->cancellable, func, data);
+ view->priv->cancellable, func, data);
}
static void
-start_calendar_server_by_uid (EMailPartItip *pitip,
- ItipView *view,
+start_calendar_server_by_uid (ItipView *view,
const gchar *uid,
ECalClientSourceType type)
{
@@ -3810,7 +3618,7 @@ start_calendar_server_by_uid (EMailPartItip *pitip,
if (source != NULL) {
start_calendar_server (
- pitip, view, source, type,
+ view, source, type,
itip_view_cal_opened_cb,
g_object_ref (view));
g_object_unref (source);
@@ -3820,16 +3628,15 @@ start_calendar_server_by_uid (EMailPartItip *pitip,
static void
source_selected_cb (ItipView *view,
ESource *source,
- gpointer data)
+ gpointer user_data)
{
- EMailPartItip *pitip = data;
+ g_return_if_fail (ITIP_IS_VIEW (view));
+ g_return_if_fail (E_IS_SOURCE (source));
itip_view_set_buttons_sensitive (view, FALSE);
- g_return_if_fail (source != NULL);
-
start_calendar_server (
- pitip, view, source, pitip->type,
+ view, source, view->priv->type,
itip_view_cal_opened_cb,
g_object_ref (view));
}
@@ -3838,13 +3645,11 @@ static void
find_cal_update_ui (FormatItipFindData *fd,
ECalClient *cal_client)
{
- EMailPartItip *pitip;
ItipView *view;
ESource *source;
g_return_if_fail (fd != NULL);
- pitip = fd->puri;
view = fd->view;
/* UI part gone */
@@ -3862,26 +3667,26 @@ find_cal_update_ui (FormatItipFindData *fd,
}
/* search for a master object if the detached object doesn't exist in the calendar */
- if (pitip->current_client && pitip->current_client == cal_client) {
+ if (view->priv->current_client && view->priv->current_client == cal_client) {
const gchar *extension_name;
gboolean rsvp_enabled = FALSE;
itip_view_set_show_keep_alarm_check (view, fd->keep_alarm_check);
- pitip->current_client = cal_client;
+ view->priv->current_client = cal_client;
/* Provide extra info, since its not in the component */
/* FIXME Check sequence number of meeting? */
/* FIXME Do we need to adjust elsewhere for the delegated calendar item? */
/* FIXME Need to update the fields in the view now */
- if (pitip->method == ICAL_METHOD_REPLY || pitip->method == ICAL_METHOD_REFRESH)
- adjust_item (pitip, pitip->comp);
+ if (view->priv->method == ICAL_METHOD_REPLY || view->priv->method == ICAL_METHOD_REFRESH)
+ adjust_item (view, view->priv->comp);
/* We clear everything because we don't really care
* about any other info/warnings now we found an
* existing versions */
itip_view_clear_lower_info_items (view);
- pitip->progress_info_id = 0;
+ view->priv->progress_info_id = 0;
/* FIXME Check read only state of calendar? */
itip_view_add_lower_info_item_printf (
@@ -3894,21 +3699,21 @@ find_cal_update_ui (FormatItipFindData *fd,
* invitiations (REQUEST), but not replies (REPLY).
* Replies only make sense for events with an organizer.
*/
- if ((!pitip->current_client || !e_cal_client_check_save_schedules (pitip->current_client)) &&
- (pitip->method == ICAL_METHOD_PUBLISH || pitip->method == ICAL_METHOD_REQUEST) &&
- pitip->has_organizer) {
+ if ((!view->priv->current_client || !e_cal_client_check_save_schedules
(view->priv->current_client)) &&
+ (view->priv->method == ICAL_METHOD_PUBLISH || view->priv->method == ICAL_METHOD_REQUEST)
&&
+ view->priv->has_organizer) {
rsvp_enabled = TRUE;
}
itip_view_set_show_rsvp_check (view, rsvp_enabled);
/* default is chosen in extract_itip_data() based on content of the VEVENT */
- itip_view_set_rsvp (view, !pitip->no_reply_wanted);
+ itip_view_set_rsvp (view, !view->priv->no_reply_wanted);
- set_buttons_sensitive (pitip, view);
+ set_buttons_sensitive (view);
g_cancellable_cancel (fd->cancellable);
- switch (pitip->type) {
+ switch (view->priv->type) {
case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
extension_name = E_SOURCE_EXTENSION_CALENDAR;
break;
@@ -3926,15 +3731,15 @@ find_cal_update_ui (FormatItipFindData *fd,
g_signal_connect (
view, "source_selected",
- G_CALLBACK (source_selected_cb), pitip);
+ G_CALLBACK (source_selected_cb), NULL);
itip_view_set_source (view, source);
- } else if (!pitip->current_client)
+ } else if (!view->priv->current_client)
itip_view_set_show_keep_alarm_check (view, FALSE);
- if (pitip->current_client && pitip->current_client == cal_client) {
- if (e_cal_client_check_recurrences_no_master (pitip->current_client)) {
- icalcomponent *icalcomp = e_cal_component_get_icalcomponent (pitip->comp);
+ if (view->priv->current_client && view->priv->current_client == cal_client) {
+ if (e_cal_client_check_recurrences_no_master (view->priv->current_client)) {
+ icalcomponent *icalcomp = e_cal_component_get_icalcomponent (view->priv->comp);
if (check_is_instance (icalcomp))
itip_view_set_show_recur_check (view, TRUE);
@@ -3942,9 +3747,9 @@ find_cal_update_ui (FormatItipFindData *fd,
itip_view_set_show_recur_check (view, FALSE);
}
- if (pitip->type == E_CAL_CLIENT_SOURCE_TYPE_MEMOS) {
+ if (view->priv->type == E_CAL_CLIENT_SOURCE_TYPE_MEMOS) {
/* TODO The static capability should be made generic to convey that the calendar
contains unaccepted items */
- if (e_client_check_capability (E_CLIENT (pitip->current_client),
CAL_STATIC_CAPABILITY_HAS_UNACCEPTED_MEETING))
+ if (e_client_check_capability (E_CLIENT (view->priv->current_client),
CAL_STATIC_CAPABILITY_HAS_UNACCEPTED_MEETING))
itip_view_set_needs_decline (view, TRUE);
else
itip_view_set_needs_decline (view, FALSE);
@@ -3964,11 +3769,10 @@ decrease_find_data (FormatItipFindData *fd)
if (fd->count == 0 && !g_cancellable_is_cancelled (fd->cancellable)) {
gboolean rsvp_enabled = FALSE;
- EMailPartItip *pitip = fd->puri;
ItipView *view = fd->view;
- itip_view_remove_lower_info_item (view, pitip->progress_info_id);
- pitip->progress_info_id = 0;
+ itip_view_remove_lower_info_item (view, view->priv->progress_info_id);
+ view->priv->progress_info_id = 0;
/*
* Only allow replies if backend doesn't do that automatically.
@@ -3976,23 +3780,23 @@ decrease_find_data (FormatItipFindData *fd)
* invitiations (REQUEST), but not replies (REPLY).
* Replies only make sense for events with an organizer.
*/
- if ((!pitip->current_client || !e_cal_client_check_save_schedules (pitip->current_client)) &&
- (pitip->method == ICAL_METHOD_PUBLISH || pitip->method == ICAL_METHOD_REQUEST) &&
- pitip->has_organizer) {
+ if ((!view->priv->current_client || !e_cal_client_check_save_schedules
(view->priv->current_client)) &&
+ (view->priv->method == ICAL_METHOD_PUBLISH || view->priv->method == ICAL_METHOD_REQUEST)
&&
+ view->priv->has_organizer) {
rsvp_enabled = TRUE;
}
itip_view_set_show_rsvp_check (view, rsvp_enabled);
/* default is chosen in extract_itip_data() based on content of the VEVENT */
- itip_view_set_rsvp (view, !pitip->no_reply_wanted);
+ itip_view_set_rsvp (view, !view->priv->no_reply_wanted);
- if ((pitip->method == ICAL_METHOD_PUBLISH || pitip->method == ICAL_METHOD_REQUEST)
- && !pitip->current_client) {
+ if ((view->priv->method == ICAL_METHOD_PUBLISH || view->priv->method == ICAL_METHOD_REQUEST)
+ && !view->priv->current_client) {
/* Reuse already declared one or rename? */
ESource *source = NULL;
const gchar *extension_name;
- switch (pitip->type) {
+ switch (view->priv->type) {
case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
extension_name = E_SOURCE_EXTENSION_CALENDAR;
break;
@@ -4013,7 +3817,7 @@ decrease_find_data (FormatItipFindData *fd)
g_signal_connect (
view, "source_selected",
- G_CALLBACK (source_selected_cb), pitip);
+ G_CALLBACK (source_selected_cb), NULL);
if (source != NULL) {
itip_view_set_source (view, source);
@@ -4024,8 +3828,8 @@ decrease_find_data (FormatItipFindData *fd)
itip_view_add_lower_info_item (view, ITIP_VIEW_INFO_ITEM_TYPE_ERROR,
_("Unable to find any calendars"));
itip_view_set_buttons_sensitive (view, FALSE);
}
- } else if (!pitip->current_client) {
- switch (pitip->type) {
+ } else if (!view->priv->current_client) {
+ switch (view->priv->type) {
case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
itip_view_add_lower_info_item_printf (
view, ITIP_VIEW_INFO_ITEM_TYPE_WARNING,
@@ -4087,8 +3891,8 @@ get_object_without_rid_ready_cb (GObject *source_object,
if (icalcomp) {
ECalComponent *comp;
- fd->puri->current_client = cal_client;
- fd->keep_alarm_check = (fd->puri->method == ICAL_METHOD_PUBLISH || fd->puri->method ==
ICAL_METHOD_REQUEST) &&
+ fd->view->priv->current_client = cal_client;
+ fd->keep_alarm_check = (fd->view->priv->method == ICAL_METHOD_PUBLISH ||
fd->view->priv->method == ICAL_METHOD_REQUEST) &&
(icalcomponent_get_first_component (icalcomp, ICAL_VALARM_COMPONENT) ||
icalcomponent_get_first_component (icalcomp, ICAL_XAUDIOALARM_COMPONENT) ||
icalcomponent_get_first_component (icalcomp, ICAL_XDISPLAYALARM_COMPONENT) ||
@@ -4099,7 +3903,7 @@ get_object_without_rid_ready_cb (GObject *source_object,
if (comp) {
ESource *source = e_client_get_source (E_CLIENT (cal_client));
- g_hash_table_insert (fd->puri->real_comps, g_strdup (e_source_get_uid (source)),
comp);
+ g_hash_table_insert (fd->view->priv->real_comps, g_strdup (e_source_get_uid
(source)), comp);
}
find_cal_update_ui (fd, cal_client);
@@ -4136,8 +3940,8 @@ get_object_with_rid_ready_cb (GObject *source_object,
if (icalcomp) {
ECalComponent *comp;
- fd->puri->current_client = cal_client;
- fd->keep_alarm_check = (fd->puri->method == ICAL_METHOD_PUBLISH || fd->puri->method ==
ICAL_METHOD_REQUEST) &&
+ fd->view->priv->current_client = cal_client;
+ fd->keep_alarm_check = (fd->view->priv->method == ICAL_METHOD_PUBLISH ||
fd->view->priv->method == ICAL_METHOD_REQUEST) &&
(icalcomponent_get_first_component (icalcomp, ICAL_VALARM_COMPONENT) ||
icalcomponent_get_first_component (icalcomp, ICAL_XAUDIOALARM_COMPONENT) ||
icalcomponent_get_first_component (icalcomp, ICAL_XDISPLAYALARM_COMPONENT) ||
@@ -4148,7 +3952,7 @@ get_object_with_rid_ready_cb (GObject *source_object,
if (comp) {
ESource *source = e_client_get_source (E_CLIENT (cal_client));
- g_hash_table_insert (fd->puri->real_comps, g_strdup (e_source_get_uid (source)),
comp);
+ g_hash_table_insert (fd->view->priv->real_comps, g_strdup (e_source_get_uid
(source)), comp);
}
find_cal_update_ui (fd, cal_client);
@@ -4210,7 +4014,6 @@ find_cal_opened_cb (GObject *source_object,
gpointer user_data)
{
FormatItipFindData *fd = user_data;
- EMailPartItip *pitip = fd->puri;
ItipView *view = fd->view;
EClient *client;
ESource *source;
@@ -4260,7 +4063,7 @@ find_cal_opened_cb (GObject *source_object,
extension = e_source_get_extension (source, extension_name);
search_for_conflicts =
- (pitip->type == E_CAL_CLIENT_SOURCE_TYPE_EVENTS) &&
+ (view->priv->type == E_CAL_CLIENT_SOURCE_TYPE_EVENTS) &&
e_source_conflict_search_get_include_me (extension);
}
@@ -4282,7 +4085,7 @@ find_cal_opened_cb (GObject *source_object,
return;
}
- if (!pitip->current_client) {
+ if (!view->priv->current_client) {
e_cal_client_get_object (
cal_client, fd->uid, fd->rid,
fd->cancellable,
@@ -4302,8 +4105,7 @@ itip_cancellable_cancelled (GCancellable *itip_cancellable,
}
static void
-find_server (EMailPartItip *pitip,
- ItipView *view,
+find_server (ItipView *view,
ECalComponent *comp)
{
FormatItipFindData *fd = NULL;
@@ -4316,9 +4118,10 @@ find_server (EMailPartItip *pitip,
const gchar *extension_name;
const gchar *store_uid;
- g_return_if_fail (pitip->folder != NULL);
+ g_return_if_fail (ITIP_IS_VIEW (view));
+ g_return_if_fail (view->priv->folder != NULL);
- switch (pitip->type) {
+ switch (view->priv->type) {
case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
extension_name = E_SOURCE_EXTENSION_CALENDAR;
break;
@@ -4341,7 +4144,7 @@ find_server (EMailPartItip *pitip,
/* XXX Not sure what this was trying to do,
* but it propbably doesn't work anymore.
* Some comments would have been helpful. */
- parent_store = camel_folder_get_parent_store (pitip->folder);
+ parent_store = camel_folder_get_parent_store (view->priv->folder);
store_uid = camel_service_get_uid (CAMEL_SERVICE (parent_store));
@@ -4382,12 +4185,12 @@ find_server (EMailPartItip *pitip,
if (current_source) {
link = conflict_list;
- pitip->progress_info_id = itip_view_add_lower_info_item (
+ view->priv->progress_info_id = itip_view_add_lower_info_item (
view, ITIP_VIEW_INFO_ITEM_TYPE_PROGRESS,
_("Opening the calendar. Please wait..."));
} else {
link = list;
- pitip->progress_info_id = itip_view_add_lower_info_item (
+ view->priv->progress_info_id = itip_view_add_lower_info_item (
view, ITIP_VIEW_INFO_ITEM_TYPE_PROGRESS,
_("Searching for an existing version of this appointment"));
}
@@ -4399,9 +4202,8 @@ find_server (EMailPartItip *pitip,
gchar *start = NULL, *end = NULL;
fd = g_new0 (FormatItipFindData, 1);
- fd->puri = pitip;
fd->view = g_object_ref (view);
- fd->itip_cancellable = g_object_ref (pitip->cancellable);
+ fd->itip_cancellable = g_object_ref (view->priv->cancellable);
fd->cancellable = g_cancellable_new ();
fd->cancelled_id = g_cancellable_connect (
fd->itip_cancellable,
@@ -4412,9 +4214,9 @@ find_server (EMailPartItip *pitip,
/* avoid free this at the end */
rid = NULL;
- if (pitip->start_time && pitip->end_time) {
- start = isodate_from_time_t (pitip->start_time);
- end = isodate_from_time_t (pitip->end_time);
+ if (view->priv->start_time && view->priv->end_time) {
+ start = isodate_from_time_t (view->priv->start_time);
+ end = isodate_from_time_t (view->priv->end_time);
fd->sexp = g_strdup_printf (
"(and (occur-in-time-range? "
@@ -4422,7 +4224,7 @@ find_server (EMailPartItip *pitip,
"(make-time \"%s\")) "
"(not (uid? \"%s\")))",
start, end,
- icalcomponent_get_uid (pitip->ical_comp));
+ icalcomponent_get_uid (view->priv->ical_comp));
}
g_free (start);
@@ -4432,7 +4234,7 @@ find_server (EMailPartItip *pitip,
d (printf ("Increasing itip formatter search count to %d\n", fd->count));
start_calendar_server (
- pitip, view, source, pitip->type,
+ view, source, view->priv->type,
find_cal_opened_cb, fd);
}
@@ -4633,26 +4435,25 @@ get_uri_for_part (CamelMimePart *mime_part)
}
static void
-update_item_progress_info (EMailPartItip *pitip,
- ItipView *view,
+update_item_progress_info (ItipView *view,
const gchar *message)
{
- if (pitip->update_item_progress_info_id) {
- itip_view_remove_lower_info_item (view, pitip->update_item_progress_info_id);
- pitip->update_item_progress_info_id = 0;
+ if (view->priv->update_item_progress_info_id) {
+ itip_view_remove_lower_info_item (view, view->priv->update_item_progress_info_id);
+ view->priv->update_item_progress_info_id = 0;
if (!message)
itip_view_set_buttons_sensitive (view, TRUE);
}
- if (pitip->update_item_error_info_id) {
- itip_view_remove_lower_info_item (view, pitip->update_item_error_info_id);
- pitip->update_item_error_info_id = 0;
+ if (view->priv->update_item_error_info_id) {
+ itip_view_remove_lower_info_item (view, view->priv->update_item_error_info_id);
+ view->priv->update_item_error_info_id = 0;
}
if (message) {
itip_view_set_buttons_sensitive (view, FALSE);
- pitip->update_item_progress_info_id =
+ view->priv->update_item_progress_info_id =
itip_view_add_lower_info_item (
view,
ITIP_VIEW_INFO_ITEM_TYPE_PROGRESS,
@@ -4660,13 +4461,25 @@ update_item_progress_info (EMailPartItip *pitip,
}
}
+static gboolean
+itip_view_get_delete_message (void)
+{
+ GSettings *settings;
+ gboolean delete_message;
+
+ settings = e_util_ref_settings ("org.gnome.evolution.plugin.itip");
+ delete_message = g_settings_get_boolean (settings, "delete-processed");
+ g_clear_object (&settings);
+
+ return delete_message;
+}
+
static void
-finish_message_delete_with_rsvp (EMailPartItip *pitip,
- ItipView *view,
+finish_message_delete_with_rsvp (ItipView *view,
ECalClient *client)
{
- if (pitip->delete_message && pitip->folder)
- camel_folder_delete_message (pitip->folder, pitip->uid);
+ if (itip_view_get_delete_message () && view->priv->folder)
+ camel_folder_delete_message (view->priv->folder, view->priv->message_uid);
if (itip_view_get_rsvp (view)) {
ECalComponent *comp = NULL;
@@ -4678,13 +4491,13 @@ finish_message_delete_with_rsvp (EMailPartItip *pitip,
GSList *l, *list = NULL;
gboolean found;
- comp = e_cal_component_clone (pitip->comp);
+ comp = e_cal_component_clone (view->priv->comp);
if (comp == NULL)
return;
- if (pitip->to_address == NULL)
- find_to_address (view, pitip, pitip->ical_comp, NULL);
- g_return_if_fail (pitip->to_address != NULL);
+ if (view->priv->to_address == NULL)
+ find_to_address (view, view->priv->ical_comp, NULL);
+ g_return_if_fail (view->priv->to_address != NULL);
ical_comp = e_cal_component_get_icalcomponent (comp);
@@ -4706,9 +4519,9 @@ finish_message_delete_with_rsvp (EMailPartItip *pitip,
/* We do this to ensure there is at most one
* attendee in the response */
- if (found || g_ascii_strcasecmp (pitip->to_address, text))
+ if (found || g_ascii_strcasecmp (view->priv->to_address, text))
list = g_slist_prepend (list, prop);
- else if (!g_ascii_strcasecmp (pitip->to_address, text))
+ else if (!g_ascii_strcasecmp (view->priv->to_address, text))
found = TRUE;
g_free (text);
}
@@ -4742,11 +4555,11 @@ finish_message_delete_with_rsvp (EMailPartItip *pitip,
if (itip_send_comp_sync (
view->priv->registry,
E_CAL_COMPONENT_METHOD_REPLY,
- comp, pitip->current_client,
- pitip->top_level, NULL, NULL, TRUE, FALSE, NULL, NULL) &&
- pitip->folder) {
+ comp, view->priv->current_client,
+ view->priv->top_level, NULL, NULL, TRUE, FALSE, NULL, NULL) &&
+ view->priv->folder) {
camel_folder_set_message_flags (
- pitip->folder, pitip->uid,
+ view->priv->folder, view->priv->message_uid,
CAMEL_MESSAGE_ANSWERED,
CAMEL_MESSAGE_ANSWERED);
}
@@ -4754,7 +4567,7 @@ finish_message_delete_with_rsvp (EMailPartItip *pitip,
g_object_unref (comp);
}
- update_item_progress_info (pitip, view, NULL);
+ update_item_progress_info (view, NULL);
}
static void
@@ -4765,7 +4578,6 @@ receive_objects_ready_cb (GObject *ecalclient,
ECalClient *client = E_CAL_CLIENT (ecalclient);
ESource *source = e_client_get_source (E_CLIENT (client));
ItipView *view = user_data;
- EMailPartItip *pitip = itip_view_get_mail_part (view);
GError *error = NULL;
e_cal_client_receive_objects_finish (client, result, &error);
@@ -4775,8 +4587,8 @@ receive_objects_ready_cb (GObject *ecalclient,
return;
} else if (error != NULL) {
- update_item_progress_info (pitip, view, NULL);
- pitip->update_item_error_info_id =
+ update_item_progress_info (view, NULL);
+ view->priv->update_item_error_info_id =
itip_view_add_lower_info_item_printf (
view, ITIP_VIEW_INFO_ITEM_TYPE_INFO,
_("Unable to send item to calendar '%s'. %s"),
@@ -4790,7 +4602,7 @@ receive_objects_ready_cb (GObject *ecalclient,
itip_view_clear_lower_info_items (view);
- switch (pitip->update_item_response) {
+ switch (view->priv->update_item_response) {
case ITIP_VIEW_RESPONSE_ACCEPT:
itip_view_add_lower_info_item_printf (
view, ITIP_VIEW_INFO_ITEM_TYPE_INFO,
@@ -4818,12 +4630,11 @@ receive_objects_ready_cb (GObject *ecalclient,
break;
}
- finish_message_delete_with_rsvp (pitip, view, client);
+ finish_message_delete_with_rsvp (view, client);
}
static void
-update_item (EMailPartItip *pitip,
- ItipView *view,
+update_item (ItipView *view,
ItipViewResponse response)
{
struct icaltimetype stamp;
@@ -4832,7 +4643,7 @@ update_item (EMailPartItip *pitip,
ECalComponent *clone_comp;
gchar *str;
- update_item_progress_info (pitip, view, _("Saving changes to the calendar. Please wait..."));
+ update_item_progress_info (view, _("Saving changes to the calendar. Please wait..."));
/* Set X-MICROSOFT-CDO-REPLYTIME to record the time at which
* the user accepted/declined the request. (Outlook ignores
@@ -4848,11 +4659,11 @@ update_item (EMailPartItip *pitip,
prop = icalproperty_new_x (str);
g_free (str);
icalproperty_set_x_name (prop, "X-MICROSOFT-CDO-REPLYTIME");
- icalcomponent_add_property (pitip->ical_comp, prop);
+ icalcomponent_add_property (view->priv->ical_comp, prop);
- clone = icalcomponent_new_clone (pitip->ical_comp);
- icalcomponent_add_component (pitip->top_level, clone);
- icalcomponent_set_method (pitip->top_level, pitip->method);
+ clone = icalcomponent_new_clone (view->priv->ical_comp);
+ icalcomponent_add_component (view->priv->top_level, clone);
+ icalcomponent_set_method (view->priv->top_level, view->priv->method);
if (!itip_view_get_inherit_alarm_check_state (view)) {
icalcomponent *alarm_comp;
@@ -4869,8 +4680,8 @@ update_item (EMailPartItip *pitip,
clone_comp = e_cal_component_new ();
if (!e_cal_component_set_icalcomponent (clone_comp, clone)) {
- update_item_progress_info (pitip, view, NULL);
- pitip->update_item_error_info_id =
+ update_item_progress_info (view, NULL);
+ view->priv->update_item_error_info_id =
itip_view_add_lower_info_item (
view, ITIP_VIEW_INFO_ITEM_TYPE_ERROR,
_("Unable to parse item"));
@@ -4882,7 +4693,7 @@ update_item (EMailPartItip *pitip,
GList *alarms, *l;
ECalComponentAlarm *alarm;
- real_comp = get_real_item (pitip);
+ real_comp = get_real_item (view);
if (real_comp != NULL) {
alarms = e_cal_component_get_alarm_uids (real_comp);
@@ -4910,7 +4721,7 @@ update_item (EMailPartItip *pitip,
if ((response != ITIP_VIEW_RESPONSE_CANCEL)
&& (response != ITIP_VIEW_RESPONSE_DECLINE)) {
GSList *attachments = NULL, *new_attachments = NULL, *l;
- CamelMimeMessage *msg = pitip->msg;
+ CamelMimeMessage *msg = view->priv->message;
e_cal_component_get_attachment_list (clone_comp, &attachments);
@@ -4929,7 +4740,7 @@ update_item (EMailPartItip *pitip,
/* Skip the actual message and the text/calendar part */
/* FIXME Do we need to skip anything else? */
- if (part == (CamelMimePart *) msg || part == pitip->part)
+ if (part == (CamelMimePart *) msg || part ==
view->priv->itip_mime_part)
continue;
new_uri = get_uri_for_part (part);
@@ -4959,17 +4770,17 @@ update_item (EMailPartItip *pitip,
e_cal_component_set_attachment_list (clone_comp, new_attachments);
}
- pitip->update_item_response = response;
+ view->priv->update_item_response = response;
e_cal_client_receive_objects (
- pitip->current_client,
- pitip->top_level,
- pitip->cancellable,
+ view->priv->current_client,
+ view->priv->top_level,
+ view->priv->cancellable,
receive_objects_ready_cb,
view);
cleanup:
- icalcomponent_remove_component (pitip->top_level, clone);
+ icalcomponent_remove_component (view->priv->top_level, clone);
g_object_unref (clone_comp);
}
@@ -5056,8 +4867,7 @@ send_comp_to_attendee (ESourceRegistry *registry,
}
static void
-remove_delegate (EMailPartItip *pitip,
- ItipView *view,
+remove_delegate (ItipView *view,
const gchar *delegate,
const gchar *delegator,
ECalComponent *comp)
@@ -5072,13 +4882,13 @@ remove_delegate (EMailPartItip *pitip,
/* send cancellation notice to delegate */
status = send_comp_to_attendee (
view->priv->registry,
- E_CAL_COMPONENT_METHOD_CANCEL, pitip->comp,
- delegate, pitip->current_client, comment);
+ E_CAL_COMPONENT_METHOD_CANCEL, view->priv->comp,
+ delegate, view->priv->current_client, comment);
if (status != 0) {
send_comp_to_attendee (
view->priv->registry,
- E_CAL_COMPONENT_METHOD_REQUEST, pitip->comp,
- delegator, pitip->current_client, comment);
+ E_CAL_COMPONENT_METHOD_REQUEST, view->priv->comp,
+ delegator, view->priv->current_client, comment);
}
if (status != 0) {
itip_view_add_lower_info_item (
@@ -5095,10 +4905,10 @@ remove_delegate (EMailPartItip *pitip,
}
static void
-update_x (ECalComponent *pitip_comp,
+update_x (ECalComponent *view_comp,
ECalComponent *comp)
{
- icalcomponent *itip_icalcomp = e_cal_component_get_icalcomponent (pitip_comp);
+ icalcomponent *itip_icalcomp = e_cal_component_get_icalcomponent (view_comp);
icalcomponent *icalcomp = e_cal_component_get_icalcomponent (comp);
icalproperty *prop = icalcomponent_get_first_property (itip_icalcomp, ICAL_X_PROPERTY);
@@ -5122,7 +4932,6 @@ modify_object_cb (GObject *ecalclient,
{
ECalClient *client = E_CAL_CLIENT (ecalclient);
ItipView *view = user_data;
- EMailPartItip *pitip = itip_view_get_mail_part (view);
GError *error = NULL;
e_cal_client_modify_object_finish (client, result, &error);
@@ -5131,8 +4940,8 @@ modify_object_cb (GObject *ecalclient,
g_error_free (error);
} else if (error != NULL) {
- update_item_progress_info (pitip, view, NULL);
- pitip->update_item_error_info_id =
+ update_item_progress_info (view, NULL);
+ view->priv->update_item_error_info_id =
itip_view_add_lower_info_item_printf (
view, ITIP_VIEW_INFO_ITEM_TYPE_ERROR,
_("Unable to update attendee. %s"),
@@ -5140,29 +4949,20 @@ modify_object_cb (GObject *ecalclient,
g_error_free (error);
} else {
- update_item_progress_info (pitip, view, NULL);
+ update_item_progress_info (view, NULL);
itip_view_add_lower_info_item (
view, ITIP_VIEW_INFO_ITEM_TYPE_INFO,
_("Attendee status updated"));
- if (view->priv->dom_document) {
- WebKitDOMElement *el;
-
- el = webkit_dom_document_get_element_by_id (
- view->priv->dom_document, BUTTON_UPDATE_ATTENDEE_STATUS);
- webkit_dom_html_button_element_set_disabled (
- WEBKIT_DOM_HTML_BUTTON_ELEMENT (el), TRUE);
- g_object_unref (el);
- }
+ enable_button (view, BUTTON_UPDATE_ATTENDEE_STATUS, FALSE);
- if (pitip->delete_message && pitip->folder)
- camel_folder_delete_message (pitip->folder, pitip->uid);
+ if (itip_view_get_delete_message () && view->priv->folder)
+ camel_folder_delete_message (view->priv->folder, view->priv->message_uid);
}
}
static void
-update_attendee_status_icalcomp (EMailPartItip *pitip,
- ItipView *view,
+update_attendee_status_icalcomp (ItipView *view,
icalcomponent *icalcomp)
{
ECalComponent *comp;
@@ -5170,8 +4970,8 @@ update_attendee_status_icalcomp (EMailPartItip *pitip,
gchar *rid;
GSList *attendees;
- e_cal_component_get_uid (pitip->comp, &uid);
- rid = e_cal_component_get_recurid_as_string (pitip->comp);
+ e_cal_component_get_uid (view->priv->comp, &uid);
+ rid = e_cal_component_get_recurid_as_string (view->priv->comp);
comp = e_cal_component_new ();
if (!e_cal_component_set_icalcomponent (comp, icalcomp)) {
@@ -5184,9 +4984,9 @@ update_attendee_status_icalcomp (EMailPartItip *pitip,
icalcomponent *org_icalcomp;
const gchar *delegate;
- org_icalcomp = e_cal_component_get_icalcomponent (pitip->comp);
+ org_icalcomp = e_cal_component_get_icalcomponent (view->priv->comp);
- e_cal_component_get_attendee_list (pitip->comp, &attendees);
+ e_cal_component_get_attendee_list (view->priv->comp, &attendees);
if (attendees != NULL) {
ECalComponentAttendee *a = attendees->data;
icalproperty *prop, *del_prop;
@@ -5205,7 +5005,7 @@ update_attendee_status_icalcomp (EMailPartItip *pitip,
icalcomponent_add_property (icalcomp, icalproperty_new_clone
(del_prop));
e_cal_component_rescan (comp);
} else if (response == GTK_RESPONSE_NO) {
- remove_delegate (pitip, view, delegate, itip_strip_mailto (a->value),
comp);
+ remove_delegate (view, delegate, itip_strip_mailto (a->value), comp);
goto cleanup;
} else {
goto cleanup;
@@ -5228,7 +5028,6 @@ update_attendee_status_icalcomp (EMailPartItip *pitip,
e_cal_component_rescan (comp);
} else if (response == GTK_RESPONSE_NO) {
remove_delegate (
- pitip,
view,
itip_strip_mailto (a->value),
itip_strip_mailto (a->delfrom),
@@ -5279,23 +5078,23 @@ update_attendee_status_icalcomp (EMailPartItip *pitip,
}
}
- update_x (pitip->comp, comp);
+ update_x (view->priv->comp, comp);
if (itip_view_get_update (view)) {
e_cal_component_commit_sequence (comp);
itip_send_comp_sync (
view->priv->registry,
E_CAL_COMPONENT_METHOD_REQUEST,
- comp, pitip->current_client,
+ comp, view->priv->current_client,
NULL, NULL, NULL, TRUE, FALSE, NULL, NULL);
}
- update_item_progress_info (pitip, view, _("Saving changes to the calendar. Please wait..."));
+ update_item_progress_info (view, _("Saving changes to the calendar. Please wait..."));
e_cal_client_modify_object (
- pitip->current_client,
+ view->priv->current_client,
icalcomp, rid ? E_CAL_OBJ_MOD_THIS : E_CAL_OBJ_MOD_ALL,
- pitip->cancellable,
+ view->priv->cancellable,
modify_object_cb,
view);
@@ -5310,7 +5109,6 @@ update_attendee_status_get_object_without_rid_cb (GObject *ecalclient,
{
ECalClient *client = E_CAL_CLIENT (ecalclient);
ItipView *view = user_data;
- EMailPartItip *pitip = itip_view_get_mail_part (view);
icalcomponent *icalcomp = NULL;
GError *error = NULL;
@@ -5322,8 +5120,8 @@ update_attendee_status_get_object_without_rid_cb (GObject *ecalclient,
} else if (error != NULL) {
g_error_free (error);
- update_item_progress_info (pitip, view, NULL);
- pitip->update_item_error_info_id =
+ update_item_progress_info (view, NULL);
+ view->priv->update_item_error_info_id =
itip_view_add_lower_info_item (
view,
ITIP_VIEW_INFO_ITEM_TYPE_WARNING,
@@ -5331,7 +5129,7 @@ update_attendee_status_get_object_without_rid_cb (GObject *ecalclient,
"because the item no longer exists"));
} else {
- update_attendee_status_icalcomp (pitip, view, icalcomp);
+ update_attendee_status_icalcomp (view, icalcomp);
}
}
@@ -5342,7 +5140,6 @@ update_attendee_status_get_object_with_rid_cb (GObject *ecalclient,
{
ECalClient *client = E_CAL_CLIENT (ecalclient);
ItipView *view = user_data;
- EMailPartItip *pitip = itip_view_get_mail_part (view);
icalcomponent *icalcomp = NULL;
GError *error = NULL;
@@ -5357,12 +5154,12 @@ update_attendee_status_get_object_with_rid_cb (GObject *ecalclient,
g_error_free (error);
- e_cal_component_get_uid (pitip->comp, &uid);
- rid = e_cal_component_get_recurid_as_string (pitip->comp);
+ e_cal_component_get_uid (view->priv->comp, &uid);
+ rid = e_cal_component_get_recurid_as_string (view->priv->comp);
if (rid == NULL || *rid == '\0') {
- update_item_progress_info (pitip, view, NULL);
- pitip->update_item_error_info_id =
+ update_item_progress_info (view, NULL);
+ view->priv->update_item_error_info_id =
itip_view_add_lower_info_item (
view,
ITIP_VIEW_INFO_ITEM_TYPE_WARNING,
@@ -5370,10 +5167,10 @@ update_attendee_status_get_object_with_rid_cb (GObject *ecalclient,
"because the item no longer exists"));
} else {
e_cal_client_get_object (
- pitip->current_client,
+ view->priv->current_client,
uid,
NULL,
- pitip->cancellable,
+ view->priv->cancellable,
update_attendee_status_get_object_without_rid_cb,
view);
}
@@ -5381,28 +5178,27 @@ update_attendee_status_get_object_with_rid_cb (GObject *ecalclient,
g_free (rid);
} else {
- update_attendee_status_icalcomp (pitip, view, icalcomp);
+ update_attendee_status_icalcomp (view, icalcomp);
}
}
static void
-update_attendee_status (EMailPartItip *pitip,
- ItipView *view)
+update_attendee_status (ItipView *view)
{
const gchar *uid = NULL;
gchar *rid;
/* Obtain our version */
- e_cal_component_get_uid (pitip->comp, &uid);
- rid = e_cal_component_get_recurid_as_string (pitip->comp);
+ e_cal_component_get_uid (view->priv->comp, &uid);
+ rid = e_cal_component_get_recurid_as_string (view->priv->comp);
- update_item_progress_info (pitip, view, _("Saving changes to the calendar. Please wait..."));
+ update_item_progress_info (view, _("Saving changes to the calendar. Please wait..."));
/* search for a master object if the detached object doesn't exist in the calendar */
e_cal_client_get_object (
- pitip->current_client,
+ view->priv->current_client,
uid, rid,
- pitip->cancellable,
+ view->priv->cancellable,
update_attendee_status_get_object_with_rid_cb,
view);
@@ -5410,22 +5206,21 @@ update_attendee_status (EMailPartItip *pitip,
}
static void
-send_item (EMailPartItip *pitip,
- ItipView *view)
+send_item (ItipView *view)
{
ECalComponent *comp;
- comp = get_real_item (pitip);
+ comp = get_real_item (view);
if (comp != NULL) {
itip_send_comp_sync (
view->priv->registry,
E_CAL_COMPONENT_METHOD_REQUEST,
- comp, pitip->current_client,
+ comp, view->priv->current_client,
NULL, NULL, NULL, TRUE, FALSE, NULL, NULL);
g_object_unref (comp);
- switch (pitip->type) {
+ switch (view->priv->type) {
case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
itip_view_add_lower_info_item (
view, ITIP_VIEW_INFO_ITEM_TYPE_INFO,
@@ -5446,7 +5241,7 @@ send_item (EMailPartItip *pitip,
break;
}
} else {
- switch (pitip->type) {
+ switch (view->priv->type) {
case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
itip_view_add_lower_info_item (
view, ITIP_VIEW_INFO_ITEM_TYPE_ERROR,
@@ -5511,18 +5306,18 @@ attachment_load_finish (EAttachment *attachment,
}
static void
-save_vcalendar_cb (EMailPartItip *pitip)
+save_vcalendar_cb (ItipView *view)
{
EAttachment *attachment;
EShell *shell;
GFile *file;
const gchar *suggestion;
- g_return_if_fail (pitip != NULL);
- g_return_if_fail (pitip->vcalendar != NULL);
- g_return_if_fail (pitip->part != NULL);
+ g_return_if_fail (ITIP_IS_VIEW (view));
+ g_return_if_fail (view->priv->vcalendar != NULL);
+ g_return_if_fail (view->priv->itip_mime_part != NULL);
- suggestion = camel_mime_part_get_filename (pitip->part);
+ suggestion = camel_mime_part_get_filename (view->priv->itip_mime_part);
if (suggestion == NULL) {
/* Translators: This is a default filename for a calendar. */
suggestion = _("calendar.ics");
@@ -5535,7 +5330,7 @@ save_vcalendar_cb (EMailPartItip *pitip)
return;
attachment = e_attachment_new ();
- e_attachment_set_mime_part (attachment, pitip->part);
+ e_attachment_set_mime_part (attachment, view->priv->itip_mime_part);
e_attachment_load_async (
attachment, (GAsyncReadyCallback)
@@ -5562,8 +5357,7 @@ set_itip_error (ItipView *view,
}
static gboolean
-extract_itip_data (EMailPartItip *pitip,
- ItipView *view,
+extract_itip_data (ItipView *view,
gboolean *have_alarms)
{
GSettings *settings;
@@ -5576,7 +5370,7 @@ extract_itip_data (EMailPartItip *pitip,
ECalComponent *comp;
gboolean use_default_reminder;
- if (!pitip->vcalendar) {
+ if (!view->priv->vcalendar) {
set_itip_error (
view,
_("The calendar attached is not valid"),
@@ -5586,53 +5380,53 @@ extract_itip_data (EMailPartItip *pitip,
return FALSE;
}
- pitip->top_level = e_cal_util_new_top_level ();
+ view->priv->top_level = e_cal_util_new_top_level ();
- pitip->main_comp = icalparser_parse_string (pitip->vcalendar);
- if (pitip->main_comp == NULL || !is_icalcomp_valid (pitip->main_comp)) {
+ view->priv->main_comp = icalparser_parse_string (view->priv->vcalendar);
+ if (view->priv->main_comp == NULL || !is_icalcomp_valid (view->priv->main_comp)) {
set_itip_error (
view,
_("The calendar attached is not valid"),
_("The message claims to contain a calendar, but the calendar is not a valid
iCalendar."),
FALSE);
- if (pitip->main_comp) {
- icalcomponent_free (pitip->main_comp);
- pitip->main_comp = NULL;
+ if (view->priv->main_comp) {
+ icalcomponent_free (view->priv->main_comp);
+ view->priv->main_comp = NULL;
}
return FALSE;
}
- prop = icalcomponent_get_first_property (pitip->main_comp, ICAL_METHOD_PROPERTY);
+ prop = icalcomponent_get_first_property (view->priv->main_comp, ICAL_METHOD_PROPERTY);
if (prop == NULL) {
- pitip->method = ICAL_METHOD_PUBLISH;
+ view->priv->method = ICAL_METHOD_PUBLISH;
} else {
- pitip->method = icalproperty_get_method (prop);
+ view->priv->method = icalproperty_get_method (prop);
}
- tz_iter = icalcomponent_begin_component (pitip->main_comp, ICAL_VTIMEZONE_COMPONENT);
+ tz_iter = icalcomponent_begin_component (view->priv->main_comp, ICAL_VTIMEZONE_COMPONENT);
while ((tz_comp = icalcompiter_deref (&tz_iter)) != NULL) {
icalcomponent *clone;
clone = icalcomponent_new_clone (tz_comp);
- icalcomponent_add_component (pitip->top_level, clone);
+ icalcomponent_add_component (view->priv->top_level, clone);
icalcompiter_next (&tz_iter);
}
- pitip->iter = icalcomponent_begin_component (pitip->main_comp, ICAL_ANY_COMPONENT);
- pitip->ical_comp = icalcompiter_deref (&pitip->iter);
- if (pitip->ical_comp != NULL) {
- kind = icalcomponent_isa (pitip->ical_comp);
+ view->priv->iter = icalcomponent_begin_component (view->priv->main_comp, ICAL_ANY_COMPONENT);
+ view->priv->ical_comp = icalcompiter_deref (&view->priv->iter);
+ if (view->priv->ical_comp != NULL) {
+ kind = icalcomponent_isa (view->priv->ical_comp);
if (kind != ICAL_VEVENT_COMPONENT
&& kind != ICAL_VTODO_COMPONENT
&& kind != ICAL_VFREEBUSY_COMPONENT
&& kind != ICAL_VJOURNAL_COMPONENT)
- pitip->ical_comp = get_next (&pitip->iter);
+ view->priv->ical_comp = get_next (&view->priv->iter);
}
- if (pitip->ical_comp == NULL) {
+ if (view->priv->ical_comp == NULL) {
set_itip_error (
view,
_("The item in the calendar is not valid"),
@@ -5642,13 +5436,13 @@ extract_itip_data (EMailPartItip *pitip,
return FALSE;
}
- switch (icalcomponent_isa (pitip->ical_comp)) {
+ switch (icalcomponent_isa (view->priv->ical_comp)) {
case ICAL_VEVENT_COMPONENT:
- pitip->type = E_CAL_CLIENT_SOURCE_TYPE_EVENTS;
- pitip->has_organizer = icalcomponent_get_first_property (pitip->ical_comp,
ICAL_ORGANIZER_PROPERTY) != NULL;
- if (icalcomponent_get_first_property (pitip->ical_comp, ICAL_ATTENDEE_PROPERTY) == NULL) {
+ view->priv->type = E_CAL_CLIENT_SOURCE_TYPE_EVENTS;
+ view->priv->has_organizer = icalcomponent_get_first_property (view->priv->ical_comp,
ICAL_ORGANIZER_PROPERTY) != NULL;
+ if (icalcomponent_get_first_property (view->priv->ical_comp, ICAL_ATTENDEE_PROPERTY) == NULL)
{
/* no attendees: assume that that this is not a meeting and organizer doesn't want a
reply */
- pitip->no_reply_wanted = TRUE;
+ view->priv->no_reply_wanted = TRUE;
} else {
/*
* if we have attendees, then find_to_address() will check for our RSVP
@@ -5657,10 +5451,10 @@ extract_itip_data (EMailPartItip *pitip,
}
break;
case ICAL_VTODO_COMPONENT:
- pitip->type = E_CAL_CLIENT_SOURCE_TYPE_TASKS;
+ view->priv->type = E_CAL_CLIENT_SOURCE_TYPE_TASKS;
break;
case ICAL_VJOURNAL_COMPONENT:
- pitip->type = E_CAL_CLIENT_SOURCE_TYPE_MEMOS;
+ view->priv->type = E_CAL_CLIENT_SOURCE_TYPE_MEMOS;
break;
default:
set_itip_error (
@@ -5672,12 +5466,12 @@ extract_itip_data (EMailPartItip *pitip,
return FALSE;
}
- pitip->total = icalcomponent_count_components (pitip->main_comp, ICAL_VEVENT_COMPONENT);
- pitip->total += icalcomponent_count_components (pitip->main_comp, ICAL_VTODO_COMPONENT);
- pitip->total += icalcomponent_count_components (pitip->main_comp, ICAL_VFREEBUSY_COMPONENT);
- pitip->total += icalcomponent_count_components (pitip->main_comp, ICAL_VJOURNAL_COMPONENT);
+ view->priv->total = icalcomponent_count_components (view->priv->main_comp, ICAL_VEVENT_COMPONENT);
+ view->priv->total += icalcomponent_count_components (view->priv->main_comp, ICAL_VTODO_COMPONENT);
+ view->priv->total += icalcomponent_count_components (view->priv->main_comp, ICAL_VFREEBUSY_COMPONENT);
+ view->priv->total += icalcomponent_count_components (view->priv->main_comp, ICAL_VJOURNAL_COMPONENT);
- if (pitip->total > 1) {
+ if (view->priv->total > 1) {
set_itip_error (
view,
@@ -5685,27 +5479,29 @@ extract_itip_data (EMailPartItip *pitip,
_("To process all of these items, the file should be saved and the calendar
imported"),
TRUE);
- } if (pitip->total > 0) {
- pitip->current = 1;
+ }
+
+ if (view->priv->total > 0) {
+ view->priv->current = 1;
} else {
- pitip->current = 0;
+ view->priv->current = 0;
}
- if (icalcomponent_isa (pitip->ical_comp) != ICAL_VJOURNAL_COMPONENT) {
+ if (icalcomponent_isa (view->priv->ical_comp) != ICAL_VJOURNAL_COMPONENT) {
gchar *my_address;
prop = NULL;
comp = e_cal_component_new ();
- e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (pitip->ical_comp));
+ e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (view->priv->ical_comp));
my_address = itip_get_comp_attendee (
view->priv->registry, comp, NULL);
g_object_unref (comp);
comp = NULL;
if (!prop)
- prop = find_attendee (pitip->ical_comp, my_address);
+ prop = find_attendee (view->priv->ical_comp, my_address);
if (!prop)
- prop = find_attendee_if_sentby (pitip->ical_comp, my_address);
+ prop = find_attendee_if_sentby (view->priv->ical_comp, my_address);
if (prop) {
icalparameter *param;
const gchar * delfrom;
@@ -5713,14 +5509,14 @@ extract_itip_data (EMailPartItip *pitip,
if ((param = icalproperty_get_first_parameter (prop, ICAL_DELEGATEDFROM_PARAMETER))) {
delfrom = icalparameter_get_delegatedfrom (param);
- pitip->delegator_address = g_strdup (itip_strip_mailto (delfrom));
+ view->priv->delegator_address = g_strdup (itip_strip_mailto (delfrom));
}
}
g_free (my_address);
prop = NULL;
/* Determine any delegate sections */
- prop = icalcomponent_get_first_property (pitip->ical_comp, ICAL_X_PROPERTY);
+ prop = icalcomponent_get_first_property (view->priv->ical_comp, ICAL_X_PROPERTY);
while (prop) {
const gchar *x_name, *x_val;
@@ -5728,19 +5524,19 @@ extract_itip_data (EMailPartItip *pitip,
x_val = icalproperty_get_x (prop);
if (!strcmp (x_name, "X-EVOLUTION-DELEGATOR-CALENDAR-UID"))
- pitip->calendar_uid = g_strdup (x_val);
+ view->priv->calendar_uid = g_strdup (x_val);
else if (!strcmp (x_name, "X-EVOLUTION-DELEGATOR-CALENDAR-URI"))
g_warning (G_STRLOC ": X-EVOLUTION-DELEGATOR-CALENDAR-URI used");
else if (!strcmp (x_name, "X-EVOLUTION-DELEGATOR-ADDRESS"))
- pitip->delegator_address = g_strdup (x_val);
+ view->priv->delegator_address = g_strdup (x_val);
else if (!strcmp (x_name, "X-EVOLUTION-DELEGATOR-NAME"))
- pitip->delegator_name = g_strdup (x_val);
+ view->priv->delegator_name = g_strdup (x_val);
- prop = icalcomponent_get_next_property (pitip->ical_comp, ICAL_X_PROPERTY);
+ prop = icalcomponent_get_next_property (view->priv->ical_comp, ICAL_X_PROPERTY);
}
/* Strip out procedural alarms for security purposes */
- alarm_iter = icalcomponent_begin_component (pitip->ical_comp, ICAL_VALARM_COMPONENT);
+ alarm_iter = icalcomponent_begin_component (view->priv->ical_comp, ICAL_VALARM_COMPONENT);
while ((alarm_comp = icalcompiter_deref (&alarm_iter)) != NULL) {
icalproperty *p;
@@ -5748,21 +5544,21 @@ extract_itip_data (EMailPartItip *pitip,
p = icalcomponent_get_first_property (alarm_comp, ICAL_ACTION_PROPERTY);
if (!p || icalproperty_get_action (p) == ICAL_ACTION_PROCEDURE)
- icalcomponent_remove_component (pitip->ical_comp, alarm_comp);
+ icalcomponent_remove_component (view->priv->ical_comp, alarm_comp);
icalcomponent_free (alarm_comp);
}
if (have_alarms) {
- alarm_iter = icalcomponent_begin_component (pitip->ical_comp, ICAL_VALARM_COMPONENT);
+ alarm_iter = icalcomponent_begin_component (view->priv->ical_comp,
ICAL_VALARM_COMPONENT);
*have_alarms = icalcompiter_deref (&alarm_iter) != NULL;
}
}
- pitip->comp = e_cal_component_new ();
- if (!e_cal_component_set_icalcomponent (pitip->comp, pitip->ical_comp)) {
- g_object_unref (pitip->comp);
- pitip->comp = NULL;
+ view->priv->comp = e_cal_component_new ();
+ if (!e_cal_component_set_icalcomponent (view->priv->comp, view->priv->ical_comp)) {
+ g_object_unref (view->priv->comp);
+ view->priv->comp = NULL;
set_itip_error (
view,
@@ -5816,29 +5612,29 @@ extract_itip_data (EMailPartItip *pitip,
}
e_cal_component_alarm_set_trigger (acomp, trigger);
- e_cal_component_add_alarm (pitip->comp, acomp);
+ e_cal_component_add_alarm (view->priv->comp, acomp);
e_cal_component_alarm_free (acomp);
}
g_object_unref (settings);
- find_from_address (view, pitip, pitip->ical_comp);
- find_to_address (view, pitip, pitip->ical_comp, NULL);
+ find_from_address (view, view->priv->ical_comp);
+ find_to_address (view, view->priv->ical_comp, NULL);
return TRUE;
}
static gboolean
-idle_open_cb (gpointer data)
+idle_open_cb (gpointer user_data)
{
- EMailPartItip *pitip = data;
+ ItipView *view = user_data;
EShell *shell;
const gchar *uris[2];
gchar *start, *end, *shell_uri;
- start = isodate_from_time_t (pitip->start_time ? pitip->start_time : time (NULL));
- end = isodate_from_time_t (pitip->end_time ? pitip->end_time : time (NULL));
+ start = isodate_from_time_t (view->priv->start_time ? view->priv->start_time : time (NULL));
+ end = isodate_from_time_t (view->priv->end_time ? view->priv->end_time : time (NULL));
shell_uri = g_strdup_printf ("calendar:///?startdate=%s&enddate=%s", start, end);
uris[0] = shell_uri;
@@ -5857,100 +5653,99 @@ idle_open_cb (gpointer data)
static void
view_response_cb (ItipView *view,
ItipViewResponse response,
- gpointer data)
+ gpointer user_data)
{
- EMailPartItip *pitip = data;
gboolean status = FALSE;
icalproperty *prop;
ECalComponentTransparency trans;
if (response == ITIP_VIEW_RESPONSE_SAVE) {
- save_vcalendar_cb (pitip);
+ save_vcalendar_cb (view);
return;
}
- if (pitip->method == ICAL_METHOD_PUBLISH || pitip->method == ICAL_METHOD_REQUEST) {
+ if (view->priv->method == ICAL_METHOD_PUBLISH || view->priv->method == ICAL_METHOD_REQUEST) {
if (itip_view_get_free_time_check_state (view))
- e_cal_component_set_transparency (pitip->comp, E_CAL_COMPONENT_TRANSP_TRANSPARENT);
+ e_cal_component_set_transparency (view->priv->comp,
E_CAL_COMPONENT_TRANSP_TRANSPARENT);
else
- e_cal_component_set_transparency (pitip->comp, E_CAL_COMPONENT_TRANSP_OPAQUE);
+ e_cal_component_set_transparency (view->priv->comp, E_CAL_COMPONENT_TRANSP_OPAQUE);
} else {
- e_cal_component_get_transparency (pitip->comp, &trans);
+ e_cal_component_get_transparency (view->priv->comp, &trans);
if (trans == E_CAL_COMPONENT_TRANSP_NONE)
- e_cal_component_set_transparency (pitip->comp, E_CAL_COMPONENT_TRANSP_OPAQUE);
+ e_cal_component_set_transparency (view->priv->comp, E_CAL_COMPONENT_TRANSP_OPAQUE);
}
- if (!pitip->to_address && pitip->current_client != NULL)
- e_client_get_backend_property_sync (E_CLIENT (pitip->current_client),
CAL_BACKEND_PROPERTY_CAL_EMAIL_ADDRESS, &pitip->to_address, NULL, NULL);
+ if (!view->priv->to_address && view->priv->current_client != NULL)
+ e_client_get_backend_property_sync (E_CLIENT (view->priv->current_client),
CAL_BACKEND_PROPERTY_CAL_EMAIL_ADDRESS, &view->priv->to_address, NULL, NULL);
/* check if it is a recur instance (no master object) and
* add a property */
if (itip_view_get_recur_check_state (view)) {
prop = icalproperty_new_x ("All");
icalproperty_set_x_name (prop, "X-GW-RECUR-INSTANCES-MOD-TYPE");
- icalcomponent_add_property (pitip->ical_comp, prop);
+ icalcomponent_add_property (view->priv->ical_comp, prop);
}
switch (response) {
case ITIP_VIEW_RESPONSE_ACCEPT:
- if (pitip->type != E_CAL_CLIENT_SOURCE_TYPE_MEMOS)
+ if (view->priv->type != E_CAL_CLIENT_SOURCE_TYPE_MEMOS)
status = change_status (
view->priv->registry,
- pitip->ical_comp,
- pitip->to_address,
+ view->priv->ical_comp,
+ view->priv->to_address,
ICAL_PARTSTAT_ACCEPTED);
else
status = TRUE;
if (status) {
- e_cal_component_rescan (pitip->comp);
- update_item (pitip, view, response);
+ e_cal_component_rescan (view->priv->comp);
+ update_item (view, response);
}
break;
case ITIP_VIEW_RESPONSE_TENTATIVE:
status = change_status (
view->priv->registry,
- pitip->ical_comp,
- pitip->to_address,
+ view->priv->ical_comp,
+ view->priv->to_address,
ICAL_PARTSTAT_TENTATIVE);
if (status) {
- e_cal_component_rescan (pitip->comp);
- update_item (pitip, view, response);
+ e_cal_component_rescan (view->priv->comp);
+ update_item (view, response);
}
break;
case ITIP_VIEW_RESPONSE_DECLINE:
- if (pitip->type != E_CAL_CLIENT_SOURCE_TYPE_MEMOS)
+ if (view->priv->type != E_CAL_CLIENT_SOURCE_TYPE_MEMOS)
status = change_status (
view->priv->registry,
- pitip->ical_comp,
- pitip->to_address,
+ view->priv->ical_comp,
+ view->priv->to_address,
ICAL_PARTSTAT_DECLINED);
else {
prop = icalproperty_new_x ("1");
icalproperty_set_x_name (prop, "X-GW-DECLINED");
- icalcomponent_add_property (pitip->ical_comp, prop);
+ icalcomponent_add_property (view->priv->ical_comp, prop);
status = TRUE;
}
if (status) {
- e_cal_component_rescan (pitip->comp);
- update_item (pitip, view, response);
+ e_cal_component_rescan (view->priv->comp);
+ update_item (view, response);
}
break;
case ITIP_VIEW_RESPONSE_UPDATE:
- update_attendee_status (pitip, view);
+ update_attendee_status (view);
break;
case ITIP_VIEW_RESPONSE_CANCEL:
- update_item (pitip, view, response);
+ update_item (view, response);
break;
case ITIP_VIEW_RESPONSE_REFRESH:
- send_item (pitip, view);
+ send_item (view);
break;
case ITIP_VIEW_RESPONSE_OPEN:
/* Prioritize ahead of GTK+ redraws. */
g_idle_add_full (
G_PRIORITY_HIGH_IDLE,
- idle_open_cb, pitip, NULL);
+ idle_open_cb, g_object_ref (view), g_object_unref);
return;
default:
break;
@@ -6035,8 +5830,6 @@ in_proper_folder (CamelFolder *folder)
void
itip_view_init_view (ItipView *view)
{
- EShell *shell;
- EClientCache *client_cache;
ECalComponentText text;
ECalComponentOrganizer organizer;
ECalComponentDateTime datetime;
@@ -6049,33 +5842,26 @@ itip_view_init_view (ItipView *view)
const gchar *string, *org;
gboolean response_enabled;
gboolean have_alarms = FALSE;
- EMailPartItip *info;
-
- info = view->priv->itip_part;
- g_return_if_fail (info != NULL);
-
- shell = e_shell_get_default ();
- client_cache = e_shell_get_client_cache (shell);
- info->client_cache = g_object_ref (client_cache);
+ g_return_if_fail (ITIP_IS_VIEW (view));
/* Reset current client before initializing view */
- info->current_client = NULL;
+ view->priv->current_client = NULL;
/* FIXME Handle multiple VEVENTS with the same UID, ie detached instances */
- if (!extract_itip_data (info, view, &have_alarms))
+ if (!extract_itip_data (view, &have_alarms))
return;
- response_enabled = in_proper_folder (info->folder);
+ response_enabled = in_proper_folder (view->priv->folder);
if (!response_enabled) {
itip_view_set_mode (view, ITIP_VIEW_MODE_HIDE_ALL);
} else {
itip_view_set_show_inherit_alarm_check (
view,
- have_alarms && (info->method == ICAL_METHOD_PUBLISH || info->method ==
ICAL_METHOD_REQUEST));
+ have_alarms && (view->priv->method == ICAL_METHOD_PUBLISH || view->priv->method ==
ICAL_METHOD_REQUEST));
- switch (info->method) {
+ switch (view->priv->method) {
case ICAL_METHOD_PUBLISH:
case ICAL_METHOD_REQUEST:
/*
@@ -6087,7 +5873,7 @@ itip_view_init_view (ItipView *view)
*/
itip_view_set_mode (
view,
- info->has_organizer ?
+ view->priv->has_organizer ?
ITIP_VIEW_MODE_REQUEST :
ITIP_VIEW_MODE_PUBLISH);
break;
@@ -6113,7 +5899,7 @@ itip_view_init_view (ItipView *view)
/* Handle appointment requests from Microsoft Live. This is
* a best-at-hand-now handling. Must be revisited when we have
* better access to the source of such meetings */
- info->method = ICAL_METHOD_REQUEST;
+ view->priv->method = ICAL_METHOD_REQUEST;
itip_view_set_mode (view, ITIP_VIEW_MODE_REQUEST);
break;
default:
@@ -6121,13 +5907,13 @@ itip_view_init_view (ItipView *view)
}
}
- itip_view_set_item_type (view, info->type);
+ itip_view_set_item_type (view, view->priv->type);
if (response_enabled) {
- switch (info->method) {
+ switch (view->priv->method) {
case ICAL_METHOD_REQUEST:
/* FIXME What about the name? */
- itip_view_set_delegator (view, info->delegator_name ? info->delegator_name :
info->delegator_address);
+ itip_view_set_delegator (view, view->priv->delegator_name ?
view->priv->delegator_name : view->priv->delegator_address);
/* coverity[fallthrough] */
case ICAL_METHOD_PUBLISH:
case ICAL_METHOD_ADD:
@@ -6136,7 +5922,7 @@ itip_view_init_view (ItipView *view)
itip_view_set_show_update_check (view, FALSE);
/* An organizer sent this */
- e_cal_component_get_organizer (info->comp, &organizer);
+ e_cal_component_get_organizer (view->priv->comp, &organizer);
org = organizer.cn ? organizer.cn : itip_strip_mailto (organizer.value);
itip_view_set_organizer (view, org);
@@ -6144,11 +5930,11 @@ itip_view_init_view (ItipView *view)
itip_view_set_organizer_sentby (
view, itip_strip_mailto (organizer.sentby));
- if (info->my_address) {
- if (!(organizer.value && !g_ascii_strcasecmp (itip_strip_mailto
(organizer.value), info->my_address))
- && !(organizer.sentby && !g_ascii_strcasecmp
(itip_strip_mailto (organizer.sentby), info->my_address))
- && (info->to_address && g_ascii_strcasecmp (info->to_address,
info->my_address)))
- itip_view_set_proxy (view, info->to_name ? info->to_name :
info->to_address);
+ if (view->priv->my_address) {
+ if (!(organizer.value && !g_ascii_strcasecmp (itip_strip_mailto
(organizer.value), view->priv->my_address))
+ && !(organizer.sentby && !g_ascii_strcasecmp
(itip_strip_mailto (organizer.sentby), view->priv->my_address))
+ && (view->priv->to_address && g_ascii_strcasecmp
(view->priv->to_address, view->priv->my_address)))
+ itip_view_set_proxy (view, view->priv->to_name ?
view->priv->to_name : view->priv->to_address);
}
break;
case ICAL_METHOD_REPLY:
@@ -6157,7 +5943,7 @@ itip_view_init_view (ItipView *view)
itip_view_set_show_update_check (view, TRUE);
/* An attendee sent this */
- e_cal_component_get_attendee_list (info->comp, &list);
+ e_cal_component_get_attendee_list (view->priv->comp, &list);
if (list != NULL) {
ECalComponentAttendee *attendee;
@@ -6168,11 +5954,11 @@ itip_view_init_view (ItipView *view)
if (attendee->sentby)
itip_view_set_attendee_sentby (view, itip_strip_mailto
(attendee->sentby));
- if (info->my_address) {
- if (!(attendee->value && !g_ascii_strcasecmp
(itip_strip_mailto (attendee->value), info->my_address))
- && !(attendee->sentby && !g_ascii_strcasecmp
(itip_strip_mailto (attendee->sentby), info->my_address))
- && (info->from_address && g_ascii_strcasecmp
(info->from_address, info->my_address)))
- itip_view_set_proxy (view, info->from_name ?
info->from_name : info->from_address);
+ if (view->priv->my_address) {
+ if (!(attendee->value && !g_ascii_strcasecmp
(itip_strip_mailto (attendee->value), view->priv->my_address))
+ && !(attendee->sentby && !g_ascii_strcasecmp
(itip_strip_mailto (attendee->sentby), view->priv->my_address))
+ && (view->priv->from_address && g_ascii_strcasecmp
(view->priv->from_address, view->priv->my_address)))
+ itip_view_set_proxy (view, view->priv->from_name ?
view->priv->from_name : view->priv->from_address);
}
e_cal_component_free_attendee_list (list);
@@ -6184,15 +5970,15 @@ itip_view_init_view (ItipView *view)
}
}
- e_cal_component_get_summary (info->comp, &text);
+ e_cal_component_get_summary (view->priv->comp, &text);
itip_view_set_summary (view, text.value ? text.value : C_("cal-itip", "None"));
- e_cal_component_get_location (info->comp, &string);
+ e_cal_component_get_location (view->priv->comp, &string);
itip_view_set_location (view, string);
/* Status really only applies for REPLY */
- if (response_enabled && info->method == ICAL_METHOD_REPLY) {
- e_cal_component_get_attendee_list (info->comp, &list);
+ if (response_enabled && view->priv->method == ICAL_METHOD_REPLY) {
+ e_cal_component_get_attendee_list (view->priv->comp, &list);
if (list != NULL) {
ECalComponentAttendee *a = list->data;
@@ -6216,12 +6002,12 @@ itip_view_init_view (ItipView *view)
e_cal_component_free_attendee_list (list);
}
- if (info->method == ICAL_METHOD_REPLY
- || info->method == ICAL_METHOD_COUNTER
- || info->method == ICAL_METHOD_DECLINECOUNTER) {
+ if (view->priv->method == ICAL_METHOD_REPLY
+ || view->priv->method == ICAL_METHOD_COUNTER
+ || view->priv->method == ICAL_METHOD_DECLINECOUNTER) {
/* FIXME Check spec to see if multiple comments are actually valid */
/* Comments for iTIP are limited to one per object */
- e_cal_component_get_comment_list (info->comp, &list);
+ e_cal_component_get_comment_list (view->priv->comp, &list);
if (list) {
ECalComponentText *text = list->data;
@@ -6243,7 +6029,7 @@ itip_view_init_view (ItipView *view)
e_cal_component_free_text_list (list);
}
- e_cal_component_get_description_list (info->comp, &list);
+ e_cal_component_get_description_list (view->priv->comp, &list);
for (l = list; l; l = l->next) {
ECalComponentText *text = l->data;
@@ -6291,8 +6077,8 @@ itip_view_init_view (ItipView *view)
g_object_unref (settings);
- e_cal_component_get_dtstart (info->comp, &datetime);
- info->start_time = 0;
+ e_cal_component_get_dtstart (view->priv->comp, &datetime);
+ view->priv->start_time = 0;
if (datetime.value) {
struct tm start_tm;
@@ -6301,17 +6087,17 @@ itip_view_init_view (ItipView *view)
if (datetime.value->is_utc)
from_zone = icaltimezone_get_utc_timezone ();
else if (!datetime.value->is_utc && datetime.tzid)
- from_zone = icalcomponent_get_timezone (info->top_level, datetime.tzid);
+ from_zone = icalcomponent_get_timezone (view->priv->top_level, datetime.tzid);
else
from_zone = NULL;
start_tm = icaltimetype_to_tm_with_zone (datetime.value, from_zone, to_zone);
itip_view_set_start (view, &start_tm, datetime.value->is_date);
- info->start_time = icaltime_as_timet_with_zone (*datetime.value, from_zone);
+ view->priv->start_time = icaltime_as_timet_with_zone (*datetime.value, from_zone);
}
- icalcomp = e_cal_component_get_icalcomponent (info->comp);
+ icalcomp = e_cal_component_get_icalcomponent (view->priv->comp);
/* Set the recurrence id */
if (check_is_instance (icalcomp) && datetime.value) {
@@ -6322,13 +6108,13 @@ itip_view_init_view (ItipView *view)
recur_id->type = E_CAL_COMPONENT_RANGE_SINGLE;
recur_id->datetime.value = &icaltime;
recur_id->datetime.tzid = icaltimezone_get_tzid (to_zone);
- e_cal_component_set_recurid (info->comp, recur_id);
+ e_cal_component_set_recurid (view->priv->comp, recur_id);
g_free (recur_id); /* it's ok to call g_free here */
}
e_cal_component_free_datetime (&datetime);
- e_cal_component_get_dtend (info->comp, &datetime);
- info->end_time = 0;
+ e_cal_component_get_dtend (view->priv->comp, &datetime);
+ view->priv->end_time = 0;
if (datetime.value) {
struct tm end_tm;
@@ -6337,7 +6123,7 @@ itip_view_init_view (ItipView *view)
if (datetime.value->is_utc)
from_zone = icaltimezone_get_utc_timezone ();
else if (!datetime.value->is_utc && datetime.tzid)
- from_zone = icalcomponent_get_timezone (info->top_level, datetime.tzid);
+ from_zone = icalcomponent_get_timezone (view->priv->top_level, datetime.tzid);
else
from_zone = NULL;
@@ -6351,15 +6137,15 @@ itip_view_init_view (ItipView *view)
end_tm = icaltimetype_to_tm_with_zone (datetime.value, from_zone, to_zone);
itip_view_set_end (view, &end_tm, datetime.value->is_date);
- info->end_time = icaltime_as_timet_with_zone (*datetime.value, from_zone);
+ view->priv->end_time = icaltime_as_timet_with_zone (*datetime.value, from_zone);
}
e_cal_component_free_datetime (&datetime);
/* Recurrence info */
/* FIXME Better recurring description */
- if (e_cal_component_has_recurrences (info->comp)) {
+ if (e_cal_component_has_recurrences (view->priv->comp)) {
/* FIXME Tell the user we don't support recurring tasks */
- switch (info->type) {
+ switch (view->priv->type) {
case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
itip_view_add_upper_info_item (view, ITIP_VIEW_INFO_ITEM_TYPE_INFO, _("This
meeting recurs"));
break;
@@ -6377,25 +6163,40 @@ itip_view_init_view (ItipView *view)
g_signal_connect (
view, "response",
- G_CALLBACK (view_response_cb), info);
+ G_CALLBACK (view_response_cb), NULL);
if (response_enabled) {
- itip_view_set_show_free_time_check (view, info->type == E_CAL_CLIENT_SOURCE_TYPE_EVENTS &&
(info->method == ICAL_METHOD_PUBLISH || info->method == ICAL_METHOD_REQUEST));
+ itip_view_set_show_free_time_check (view, view->priv->type == E_CAL_CLIENT_SOURCE_TYPE_EVENTS
&& (view->priv->method == ICAL_METHOD_PUBLISH || view->priv->method == ICAL_METHOD_REQUEST));
- if (info->calendar_uid) {
- start_calendar_server_by_uid (info, view, info->calendar_uid, info->type);
+ if (view->priv->calendar_uid) {
+ start_calendar_server_by_uid (view, view->priv->calendar_uid, view->priv->type);
} else {
- find_server (info, view, info->comp);
- set_buttons_sensitive (info, view);
+ find_server (view, view->priv->comp);
+ set_buttons_sensitive (view);
}
- } else if (view->priv->dom_document) {
+ } else if (view->priv->web_extension) {
/* The Open Calendar button can be shown, thus enable it */
- WebKitDOMElement *el;
-
- el = webkit_dom_document_get_element_by_id (
- view->priv->dom_document, BUTTON_OPEN_CALENDAR);
- webkit_dom_html_button_element_set_disabled (
- WEBKIT_DOM_HTML_BUTTON_ELEMENT (el), FALSE);
- g_object_unref (el);
+ enable_button (view, BUTTON_OPEN_CALENDAR, TRUE);
}
}
+
+void
+itip_view_set_web_view (ItipView *view,
+ EWebView *web_view)
+{
+ g_return_if_fail (ITIP_IS_VIEW (view));
+ if (web_view)
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+ g_weak_ref_set (view->priv->web_view_weakref, web_view);
+
+ itip_view_register_clicked_listener (view);
+}
+
+EWebView *
+itip_view_ref_web_view (ItipView *view)
+{
+ g_return_val_if_fail (ITIP_IS_VIEW (view), NULL);
+
+ return g_weak_ref_get (view->priv->web_view_weakref);
+}
diff --git a/modules/itip-formatter/itip-view.h b/modules/itip-formatter/itip-view.h
index 0ffd96f..7b220f8 100644
--- a/modules/itip-formatter/itip-view.h
+++ b/modules/itip-formatter/itip-view.h
@@ -27,7 +27,6 @@
#include <unistd.h>
#include <gtk/gtk.h>
-#include <webkit/webkitdom.h>
#include <libecal/libecal.h>
@@ -59,8 +58,6 @@ typedef struct _ItipView ItipView;
typedef struct _ItipViewClass ItipViewClass;
typedef struct _ItipViewPrivate ItipViewPrivate;
-struct _EMailPartItip;
-
typedef enum {
ITIP_VIEW_MODE_NONE,
ITIP_VIEW_MODE_PUBLISH,
@@ -109,17 +106,24 @@ struct _ItipViewClass {
};
GType itip_view_get_type (void);
-ItipView * itip_view_new (struct _EMailPartItip *puri,
- EClientCache *client_cache);
+ItipView * itip_view_new (guint64 page_id,
+ const gchar *part_id,
+ gpointer itip_part_ptr,
+ CamelFolder *folder,
+ const gchar *message_uid,
+ CamelMimeMessage *message,
+ CamelMimePart *itip_mime_part,
+ const gchar *vcalendar,
+ GCancellable *cancellable);
void itip_view_init_view (ItipView *view);
-void itip_view_write (EMailFormatter *formatter,
+void itip_view_set_web_view (ItipView *view,
+ EWebView *web_view);
+EWebView * itip_view_ref_web_view (ItipView *view);
+void itip_view_write (gpointer itip_part,
+ EMailFormatter *formatter,
GString *buffer);
void itip_view_write_for_printing (ItipView *view,
GString *buffer);
-void itip_view_create_dom_bindings (ItipView *view,
- WebKitDOMElement *element);
-struct _EMailPartItip *
- itip_view_get_mail_part (ItipView *view);
EClientCache * itip_view_get_client_cache (ItipView *view);
const gchar * itip_view_get_extension_name (ItipView *view);
void itip_view_set_extension_name (ItipView *view,
@@ -246,6 +250,8 @@ void itip_view_set_show_inherit_alarm_check
void itip_view_set_error (ItipView *view,
const gchar *error_html,
gboolean show_save_btn);
+GDBusProxy * itip_view_get_web_extension_proxy
+ (ItipView *view);
G_END_DECLS
diff --git a/modules/itip-formatter/web-extension/Makefile.am
b/modules/itip-formatter/web-extension/Makefile.am
new file mode 100644
index 0000000..a519744
--- /dev/null
+++ b/modules/itip-formatter/web-extension/Makefile.am
@@ -0,0 +1,26 @@
+webextensions_LTLIBRARIES = libmoduleitipformatterwebextension.la
+
+libmoduleitipformatterwebextension_la_SOURCES = \
+ module-itip-formatter-web-extension.c \
+ module-itip-formatter-web-extension.h \
+ module-itip-formatter-dom-utils.c \
+ module-itip-formatter-dom-utils.h
+
+libmoduleitipformatterwebextension_la_CPPFLAGS = \
+ $(AM_CPPFLAGS) \
+ -I$(top_srcdir) \
+ $(EVOLUTION_DATA_SERVER_CFLAGS) \
+ $(GNOME_PLATFORM_CFLAGS) \
+ $(WEB_EXTENSIONS_CFLAGS)
+
+libmoduleitipformatterwebextension_la_LIBADD = \
+ $(top_builddir)/e-util/libevolution-util.la \
+ $(top_builddir)/web-extensions/libedomutils.la \
+ $(EVOLUTION_DATA_SERVER_LIBS) \
+ $(GNOME_PLATFORM_LIBS) \
+ $(WEB_EXTENSIONS_LIBS)
+
+libmoduleitipformatterwebextension_la_LDFLAGS = \
+ -module -avoid-version -no-undefined
+
+-include $(top_srcdir)/git.mk
diff --git a/modules/itip-formatter/web-extension/module-itip-formatter-dom-utils.c
b/modules/itip-formatter/web-extension/module-itip-formatter-dom-utils.c
new file mode 100644
index 0000000..72809ee
--- /dev/null
+++ b/modules/itip-formatter/web-extension/module-itip-formatter-dom-utils.c
@@ -0,0 +1,642 @@
+/*
+ * module-itip-formatter-dom-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/>
+ *
+ */
+
+#include "module-itip-formatter-dom-utils.h"
+
+#define WEBKIT_DOM_USE_UNSTABLE_API
+#include <webkitdom/WebKitDOMHTMLElementUnstable.h>
+
+#include "module-itip-formatter-web-extension.h"
+#include "../itip-view-elements-defines.h"
+
+#include <e-util/e-util.h>
+
+#define ITIP_WEB_EXTENSION_PAGE_ID_KEY "itip-web-extension-page-id"
+#define ITIP_WEB_EXTENSION_PART_ID_KEY "itip-web-extension-part-id"
+
+static void
+recur_toggled_cb (WebKitDOMHTMLInputElement *input,
+ WebKitDOMEvent *event,
+ GDBusConnection *connection)
+{
+ guint64 *ppage_id;
+ const gchar *part_id;
+ GError *error = NULL;
+
+ ppage_id = g_object_get_data (G_OBJECT (input), ITIP_WEB_EXTENSION_PAGE_ID_KEY);
+ part_id = g_object_get_data (G_OBJECT (input), ITIP_WEB_EXTENSION_PART_ID_KEY);
+ if (!ppage_id || !part_id) {
+ g_warning ("%s: page_id/part_id not set on %p", G_STRFUNC, input);
+ return;
+ }
+
+ g_dbus_connection_emit_signal (
+ connection,
+ NULL,
+ MODULE_ITIP_FORMATTER_WEB_EXTENSION_OBJECT_PATH,
+ MODULE_ITIP_FORMATTER_WEB_EXTENSION_INTERFACE,
+ "RecurToggled",
+ g_variant_new ("(ts)", *ppage_id, part_id),
+ &error);
+
+ if (error) {
+ g_warning ("Error emitting signal RecurToggled: %s\n", error->message);
+ g_error_free (error);
+ }
+}
+
+static void
+source_changed_cb (WebKitDOMElement *element,
+ WebKitDOMEvent *event,
+ GDBusConnection *connection)
+{
+ guint64 *ppage_id;
+ const gchar *part_id;
+ GError *error = NULL;
+
+ ppage_id = g_object_get_data (G_OBJECT (element), ITIP_WEB_EXTENSION_PAGE_ID_KEY);
+ part_id = g_object_get_data (G_OBJECT (element), ITIP_WEB_EXTENSION_PART_ID_KEY);
+ if (!ppage_id || !part_id) {
+ g_warning ("%s: page_id/part_id not set on %p", G_STRFUNC, element);
+ return;
+ }
+
+ g_dbus_connection_emit_signal (
+ connection,
+ NULL,
+ MODULE_ITIP_FORMATTER_WEB_EXTENSION_OBJECT_PATH,
+ MODULE_ITIP_FORMATTER_WEB_EXTENSION_INTERFACE,
+ "SourceChanged",
+ g_variant_new ("(ts)", *ppage_id, part_id),
+ &error);
+
+ if (error) {
+ g_warning ("Error emitting signal SourceChanged: %s\n", error->message);
+ g_error_free (error);
+ }
+}
+
+static void
+rsvp_toggled_cb (WebKitDOMHTMLInputElement *input,
+ WebKitDOMEvent *event,
+ GDBusConnection *connection)
+{
+ WebKitDOMElement *el;
+ WebKitDOMDocument *document;
+ gboolean rsvp;
+
+ document = webkit_dom_node_get_owner_document (WEBKIT_DOM_NODE (input));
+ rsvp = webkit_dom_html_input_element_get_checked (input);
+ el = webkit_dom_document_get_element_by_id (
+ document, TEXTAREA_RSVP_COMMENT);
+ webkit_dom_html_text_area_element_set_disabled (
+ WEBKIT_DOM_HTML_TEXT_AREA_ELEMENT (el), !rsvp);
+}
+
+/**
+ alarm_check_toggled_cb
+ check1 was changed, so make the second available based on state of the first check.
+*/
+static void
+alarm_check_toggled_cb (WebKitDOMHTMLInputElement *check1,
+ WebKitDOMEvent *event,
+ GDBusConnection *connection)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *check2;
+ gchar *id;
+
+ document = webkit_dom_node_get_owner_document (WEBKIT_DOM_NODE (check1));
+#if WEBKIT_CHECK_VERSION(2,2,0) /* XXX should really be (2,1,something) */
+ id = webkit_dom_element_get_id (WEBKIT_DOM_ELEMENT (check1));
+#else
+ id = webkit_dom_html_element_get_id (WEBKIT_DOM_HTML_ELEMENT (check1));
+#endif
+
+ if (g_strcmp0 (id, CHECKBOX_INHERIT_ALARM)) {
+ check2 = webkit_dom_document_get_element_by_id (
+ document, CHECKBOX_KEEP_ALARM);
+ } else {
+ check2 = webkit_dom_document_get_element_by_id (
+ document, CHECKBOX_INHERIT_ALARM);
+ }
+
+ g_free (id);
+
+ webkit_dom_html_input_element_set_disabled (
+ WEBKIT_DOM_HTML_INPUT_ELEMENT (check2),
+ (webkit_dom_html_element_get_hidden (
+ WEBKIT_DOM_HTML_ELEMENT (check1)) &&
+ webkit_dom_html_input_element_get_checked (check1)));
+}
+
+void
+module_itip_formatter_dom_utils_create_dom_bindings (WebKitDOMDocument *document,
+ guint64 page_id,
+ const gchar *part_id,
+ GDBusConnection *connection)
+{
+ WebKitDOMElement *el;
+
+ g_return_if_fail (part_id && *part_id);
+
+ el = webkit_dom_document_get_element_by_id (document, CHECKBOX_RECUR);
+ if (el) {
+ guint64 *ppage_id;
+
+ ppage_id = g_new0 (guint64, 1);
+ *ppage_id = page_id;
+
+ g_object_set_data_full (G_OBJECT (el), ITIP_WEB_EXTENSION_PAGE_ID_KEY, ppage_id, g_free);
+ g_object_set_data_full (G_OBJECT (el), ITIP_WEB_EXTENSION_PART_ID_KEY, g_strdup (part_id),
g_free);
+
+ webkit_dom_event_target_add_event_listener (
+ WEBKIT_DOM_EVENT_TARGET (el), "click",
+ G_CALLBACK (recur_toggled_cb), FALSE, connection);
+ }
+
+ el = webkit_dom_document_get_element_by_id (document, SELECT_ESOURCE);
+ if (el) {
+ guint64 *ppage_id;
+
+ ppage_id = g_new0 (guint64, 1);
+ *ppage_id = page_id;
+
+ g_object_set_data_full (G_OBJECT (el), ITIP_WEB_EXTENSION_PAGE_ID_KEY, ppage_id, g_free);
+ g_object_set_data_full (G_OBJECT (el), ITIP_WEB_EXTENSION_PART_ID_KEY, g_strdup (part_id),
g_free);
+
+ webkit_dom_event_target_add_event_listener (
+ WEBKIT_DOM_EVENT_TARGET (el), "change",
+ G_CALLBACK (source_changed_cb), FALSE, connection);
+ }
+
+ el = webkit_dom_document_get_element_by_id (document, CHECKBOX_RSVP);
+ if (el) {
+ webkit_dom_event_target_add_event_listener (
+ WEBKIT_DOM_EVENT_TARGET (el), "click",
+ G_CALLBACK (rsvp_toggled_cb), FALSE, connection);
+ }
+
+ el = webkit_dom_document_get_element_by_id (document, CHECKBOX_INHERIT_ALARM);
+ if (el) {
+ webkit_dom_event_target_add_event_listener (
+ WEBKIT_DOM_EVENT_TARGET (el), "click",
+ G_CALLBACK (alarm_check_toggled_cb), FALSE, connection);
+ }
+
+ el = webkit_dom_document_get_element_by_id (document, CHECKBOX_KEEP_ALARM);
+ if (el) {
+ webkit_dom_event_target_add_event_listener (
+ WEBKIT_DOM_EVENT_TARGET (el), "click",
+ G_CALLBACK (alarm_check_toggled_cb), FALSE, connection);
+ }
+}
+
+void
+module_itip_formatter_dom_utils_show_button (WebKitDOMDocument *document,
+ const gchar *button_id)
+{
+ WebKitDOMElement *button;
+
+ button = webkit_dom_document_get_element_by_id (document, button_id);
+ webkit_dom_html_element_set_hidden (WEBKIT_DOM_HTML_ELEMENT (button), FALSE);
+}
+
+void
+module_itip_formatter_dom_utils_enable_button (WebKitDOMDocument *document,
+ const gchar *button_id,
+ gboolean enable)
+{
+ WebKitDOMElement *el;
+
+ el = webkit_dom_document_get_element_by_id (document, button_id);
+ webkit_dom_html_button_element_set_disabled (
+ WEBKIT_DOM_HTML_BUTTON_ELEMENT (el), !enable);
+}
+
+gboolean
+module_itip_formatter_dom_utils_input_is_checked (WebKitDOMDocument *document,
+ const gchar *input_id)
+{
+ WebKitDOMElement *element;
+
+ element = webkit_dom_document_get_element_by_id (document, input_id);
+
+ if (!element)
+ return FALSE;
+
+ return webkit_dom_html_input_element_get_checked (
+ WEBKIT_DOM_HTML_INPUT_ELEMENT (element));
+}
+
+void
+module_itip_formatter_dom_utils_input_set_checked (WebKitDOMDocument *document,
+ const gchar *input_id,
+ gboolean checked)
+{
+ WebKitDOMElement *element;
+
+ element = webkit_dom_document_get_element_by_id (document, input_id);
+
+ if (!element)
+ return;
+
+ webkit_dom_html_input_element_set_checked (
+ WEBKIT_DOM_HTML_INPUT_ELEMENT (element), checked);
+}
+
+void
+module_itip_formatter_dom_utils_show_checkbox (WebKitDOMDocument *document,
+ const gchar *id,
+ gboolean show,
+ gboolean update_second)
+{
+ WebKitDOMElement *label;
+ WebKitDOMElement *el;
+ gchar *row_id;
+
+ el = webkit_dom_document_get_element_by_id (document, id);
+ webkit_dom_html_element_set_hidden (WEBKIT_DOM_HTML_ELEMENT (el), !show);
+
+ label = webkit_dom_element_get_next_element_sibling (el);
+ webkit_dom_html_element_set_hidden (WEBKIT_DOM_HTML_ELEMENT (label), !show);
+
+ if (!show) {
+ webkit_dom_html_input_element_set_checked (
+ WEBKIT_DOM_HTML_INPUT_ELEMENT (el), FALSE);
+ }
+
+ if (update_second) {
+ /* and update state of the second check */
+ alarm_check_toggled_cb (
+ WEBKIT_DOM_HTML_INPUT_ELEMENT (el),
+ NULL, NULL);
+ }
+
+ row_id = g_strconcat ("table_row_", id, NULL);
+ el = webkit_dom_document_get_element_by_id (document, row_id);
+ webkit_dom_html_element_set_hidden (WEBKIT_DOM_HTML_ELEMENT (el), !show);
+ g_free (row_id);
+}
+
+void
+module_itip_formatter_dom_utils_set_buttons_sensitive (WebKitDOMDocument *document,
+ gboolean sensitive)
+{
+ WebKitDOMElement *el, *cell;
+
+ el = webkit_dom_document_get_element_by_id (
+ document, CHECKBOX_UPDATE);
+ webkit_dom_html_input_element_set_disabled (
+ WEBKIT_DOM_HTML_INPUT_ELEMENT (el), !sensitive);
+
+ el = webkit_dom_document_get_element_by_id (
+ document, CHECKBOX_RECUR);
+ webkit_dom_html_input_element_set_disabled (
+ WEBKIT_DOM_HTML_INPUT_ELEMENT (el), !sensitive);
+
+ el = webkit_dom_document_get_element_by_id (
+ document, CHECKBOX_FREE_TIME);
+ webkit_dom_html_input_element_set_disabled (
+ WEBKIT_DOM_HTML_INPUT_ELEMENT (el), !sensitive);
+
+ el = webkit_dom_document_get_element_by_id (
+ document, CHECKBOX_KEEP_ALARM);
+ webkit_dom_html_input_element_set_disabled (
+ WEBKIT_DOM_HTML_INPUT_ELEMENT (el), !sensitive);
+
+ el = webkit_dom_document_get_element_by_id (
+ document, CHECKBOX_INHERIT_ALARM);
+ webkit_dom_html_input_element_set_disabled (
+ WEBKIT_DOM_HTML_INPUT_ELEMENT (el), !sensitive);
+
+ el = webkit_dom_document_get_element_by_id (
+ document, CHECKBOX_RSVP);
+ webkit_dom_html_input_element_set_disabled (
+ WEBKIT_DOM_HTML_INPUT_ELEMENT (el), !sensitive);
+
+ el = webkit_dom_document_get_element_by_id (
+ document, TEXTAREA_RSVP_COMMENT);
+ webkit_dom_html_text_area_element_set_disabled (
+ WEBKIT_DOM_HTML_TEXT_AREA_ELEMENT (el), !sensitive);
+
+ el = webkit_dom_document_get_element_by_id (
+ document, TABLE_ROW_BUTTONS);
+ cell = webkit_dom_element_get_first_element_child (el);
+ do {
+ WebKitDOMElement *btn;
+ btn = webkit_dom_element_get_first_element_child (cell);
+ if (!webkit_dom_html_element_get_hidden (
+ WEBKIT_DOM_HTML_ELEMENT (btn))) {
+ webkit_dom_html_button_element_set_disabled (
+ WEBKIT_DOM_HTML_BUTTON_ELEMENT (btn), !sensitive);
+ }
+ } while ((cell = webkit_dom_element_get_next_element_sibling (cell)) != NULL);
+}
+
+void
+module_itip_formatter_dom_utils_set_area_text (WebKitDOMDocument *document,
+ const gchar *area_id,
+ const gchar *text)
+{
+ WebKitDOMElement *row, *col;
+
+ row = webkit_dom_document_get_element_by_id (document, area_id);
+ webkit_dom_html_element_set_hidden (
+ WEBKIT_DOM_HTML_ELEMENT (row), (g_strcmp0 (text, "") == 0));
+
+ col = webkit_dom_element_get_last_element_child (row);
+ webkit_dom_element_set_inner_html (col, text, NULL);
+}
+
+void
+module_itip_formatter_dom_utils_element_set_access_key (WebKitDOMDocument *document,
+ const gchar *element_id,
+ const gchar *access_key)
+{
+ WebKitDOMElement *element;
+
+ element = webkit_dom_document_get_element_by_id (document, element_id);
+
+ if (!element)
+ return;
+
+ webkit_dom_html_element_set_access_key (
+ WEBKIT_DOM_HTML_ELEMENT (element), access_key);
+}
+
+void
+module_itip_formatter_dom_utils_element_hide_child_nodes (WebKitDOMDocument *document,
+ const gchar *element_id)
+{
+ WebKitDOMElement *element, *cell, *button;
+
+ element = webkit_dom_document_get_element_by_id (document, element_id);
+
+ if (!element)
+ return;
+
+ element = webkit_dom_document_get_element_by_id (document, element_id);
+ cell = webkit_dom_element_get_first_element_child (element);
+ do {
+ button = webkit_dom_element_get_first_element_child (cell);
+ webkit_dom_html_element_set_hidden (
+ WEBKIT_DOM_HTML_ELEMENT (button), TRUE);
+ } while ((cell = webkit_dom_element_get_next_element_sibling (cell)) != NULL);
+}
+
+void
+module_itip_formatter_dom_utils_enable_select (WebKitDOMDocument *document,
+ const gchar *select_id,
+ gboolean enabled)
+{
+ WebKitDOMElement *element;
+
+ element = webkit_dom_document_get_element_by_id (document, select_id);
+
+ if (!element)
+ return;
+
+ webkit_dom_html_select_element_set_disabled (
+ WEBKIT_DOM_HTML_SELECT_ELEMENT (element), !enabled);
+}
+
+gboolean
+module_itip_formatter_dom_utils_select_is_enabled (WebKitDOMDocument *document,
+ const gchar *select_id)
+{
+ WebKitDOMElement *element;
+
+ element = webkit_dom_document_get_element_by_id (document, select_id);
+
+ if (!element)
+ return FALSE;
+
+ return !webkit_dom_html_select_element_get_disabled (
+ WEBKIT_DOM_HTML_SELECT_ELEMENT (element));
+}
+
+gchar *
+module_itip_formatter_dom_utils_select_get_value (WebKitDOMDocument *document,
+ const gchar *select_id)
+{
+ WebKitDOMElement *element;
+
+ element = webkit_dom_document_get_element_by_id (document, select_id);
+
+ if (!element)
+ return NULL;
+
+ return webkit_dom_html_select_element_get_value (
+ WEBKIT_DOM_HTML_SELECT_ELEMENT (element));
+}
+
+void
+module_itip_formatter_dom_utils_select_set_selected (WebKitDOMDocument *document,
+ const gchar *select_id,
+ const gchar *option)
+{
+ WebKitDOMElement *element;
+ gint length, ii;
+
+ element = webkit_dom_document_get_element_by_id (document, select_id);
+
+ if (!element)
+ return;
+
+ length = webkit_dom_html_select_element_get_length (
+ WEBKIT_DOM_HTML_SELECT_ELEMENT (element));
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMNode *node;
+ WebKitDOMHTMLOptionElement *option_element;
+ gchar *value;
+
+ node = webkit_dom_html_select_element_item (
+ WEBKIT_DOM_HTML_SELECT_ELEMENT (element), ii);
+ option_element = WEBKIT_DOM_HTML_OPTION_ELEMENT (node);
+
+ value = webkit_dom_html_option_element_get_value (option_element);
+ if (g_strcmp0 (value, option) == 0) {
+ webkit_dom_html_option_element_set_selected (
+ option_element, TRUE);
+
+ g_free (value);
+ break;
+ }
+
+ g_free (value);
+ }
+}
+
+void
+module_itip_formatter_dom_utils_update_times (WebKitDOMDocument *document,
+ const gchar *element_id,
+ const gchar *header,
+ const gchar *label)
+{
+ WebKitDOMElement *element, *col;
+
+ element = webkit_dom_document_get_element_by_id (document, element_id);
+
+ if (!element)
+ return;
+
+ webkit_dom_html_element_set_hidden (
+ WEBKIT_DOM_HTML_ELEMENT (element), FALSE);
+
+ col = webkit_dom_element_get_first_element_child (element);
+ webkit_dom_element_set_inner_html (col, header, NULL);
+
+ col = webkit_dom_element_get_last_element_child (element);
+ webkit_dom_element_set_inner_html (col, label, NULL);
+}
+
+void
+module_itip_formatter_dom_utils_append_info_item_row (WebKitDOMDocument *document,
+ const gchar *table_id,
+ const gchar *row_id,
+ const gchar *icon_name,
+ const gchar *message)
+{
+ WebKitDOMElement *table;
+ WebKitDOMHTMLElement *cell, *row;
+
+ table = webkit_dom_document_get_element_by_id (document, table_id);
+
+ if (!table)
+ return;
+
+ table = webkit_dom_document_get_element_by_id (document, table_id);
+ row = webkit_dom_html_table_element_insert_row (
+ WEBKIT_DOM_HTML_TABLE_ELEMENT (table), -1, NULL);
+
+ webkit_dom_element_set_id (WEBKIT_DOM_ELEMENT (row), row_id);
+
+ cell = webkit_dom_html_table_row_element_insert_cell (
+ WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (row), -1, NULL);
+
+ if (icon_name) {
+ WebKitDOMElement *image;
+ gchar *icon_uri;
+
+ image = webkit_dom_document_create_element (
+ document, "IMG", NULL);
+
+ icon_uri = g_strdup_printf ("gtk-stock://%s", icon_name);
+ webkit_dom_html_image_element_set_src (
+ WEBKIT_DOM_HTML_IMAGE_ELEMENT (image), icon_uri);
+ g_free (icon_uri);
+
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (cell),
+ WEBKIT_DOM_NODE (image),
+ NULL);
+ }
+
+ cell = webkit_dom_html_table_row_element_insert_cell (
+ WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (row), -1, NULL);
+
+ webkit_dom_element_set_inner_html (WEBKIT_DOM_ELEMENT (cell), message, NULL);
+}
+
+void
+module_itip_formatter_dom_utils_enable_text_area (WebKitDOMDocument *document,
+ const gchar *area_id,
+ gboolean enable)
+{
+ WebKitDOMElement *el;
+
+ el = webkit_dom_document_get_element_by_id (document, area_id);
+ webkit_dom_html_text_area_element_set_disabled (
+ WEBKIT_DOM_HTML_TEXT_AREA_ELEMENT (el), !enable);
+}
+
+void
+module_itip_formatter_dom_utils_text_area_set_value (WebKitDOMDocument *document,
+ const gchar *area_id,
+ const gchar *value)
+{
+ WebKitDOMElement *el;
+
+ el = webkit_dom_document_get_element_by_id (document, area_id);
+ webkit_dom_html_text_area_element_set_value (
+ WEBKIT_DOM_HTML_TEXT_AREA_ELEMENT (el), value);
+}
+
+gchar *
+module_itip_formatter_dom_utils_text_area_get_value (WebKitDOMDocument *document,
+ const gchar *area_id)
+{
+ WebKitDOMElement *el;
+
+ el = webkit_dom_document_get_element_by_id (document, area_id);
+ return webkit_dom_html_text_area_element_get_value (
+ WEBKIT_DOM_HTML_TEXT_AREA_ELEMENT (el));
+}
+
+void
+module_itip_formatter_dom_utils_rebuild_source_list (WebKitDOMDocument *document,
+ const gchar *optgroup_id,
+ const gchar *optgroup_label,
+ const gchar *option_id,
+ const gchar *option_label,
+ gboolean writable)
+{
+ WebKitDOMElement *option;
+ WebKitDOMElement *select;
+ WebKitDOMHTMLOptGroupElement *optgroup;
+
+ select = webkit_dom_document_get_element_by_id (document, SELECT_ESOURCE);
+
+ if (!select)
+ return;
+
+ optgroup = WEBKIT_DOM_HTML_OPT_GROUP_ELEMENT (
+ webkit_dom_document_get_element_by_id (
+ document, optgroup_id));
+
+ if (!optgroup) {
+ optgroup = WEBKIT_DOM_HTML_OPT_GROUP_ELEMENT (
+ webkit_dom_document_create_element (
+ document, "OPTGROUP", NULL));
+ webkit_dom_html_opt_group_element_set_label (
+ optgroup, optgroup_label);
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (select), WEBKIT_DOM_NODE (optgroup), NULL);
+ }
+
+ option = webkit_dom_document_create_element (document, "OPTION", NULL);
+ webkit_dom_html_option_element_set_value (
+ WEBKIT_DOM_HTML_OPTION_ELEMENT (option), option_id);
+ webkit_dom_html_option_element_set_label (
+ WEBKIT_DOM_HTML_OPTION_ELEMENT (option), option_label);
+ webkit_dom_element_set_inner_html (option, option_label, NULL);
+
+ webkit_dom_element_set_class_name (
+ WEBKIT_DOM_ELEMENT (option), "calendar");
+
+ if (!writable) {
+ webkit_dom_html_option_element_set_disabled (
+ WEBKIT_DOM_HTML_OPTION_ELEMENT (option), TRUE);
+ }
+
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (optgroup),
+ WEBKIT_DOM_NODE (option),
+ NULL);
+}
diff --git a/modules/itip-formatter/web-extension/module-itip-formatter-dom-utils.h
b/modules/itip-formatter/web-extension/module-itip-formatter-dom-utils.h
new file mode 100644
index 0000000..8fab80f
--- /dev/null
+++ b/modules/itip-formatter/web-extension/module-itip-formatter-dom-utils.h
@@ -0,0 +1,111 @@
+/*
+ * module-itip-formatter-dom-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/>
+ *
+ */
+
+#ifndef MODULE_ITIP_FORMATTER_DOM_UTILS_H
+#define MODULE_ITIP_FORMATTER_DOM_UTILS_H
+
+#include <webkitdom/webkitdom.h>
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+void module_itip_formatter_dom_utils_create_dom_bindings
+ (WebKitDOMDocument *document,
+ guint64 page_id,
+ const gchar *part_id,
+ GDBusConnection *connection);
+void module_itip_formatter_dom_utils_show_button
+ (WebKitDOMDocument *document,
+ const gchar *button_id);
+void module_itip_formatter_dom_utils_enable_button
+ (WebKitDOMDocument *document,
+ const gchar *button_id,
+ gboolean enable);
+void module_itip_formatter_dom_utils_input_set_checked
+ (WebKitDOMDocument *document,
+ const gchar *input_id,
+ gboolean checked);
+gboolean module_itip_formatter_dom_utils_input_is_checked
+ (WebKitDOMDocument *document,
+ const gchar *input_id);
+void module_itip_formatter_dom_utils_show_checkbox
+ (WebKitDOMDocument *document,
+ const gchar *id,
+ gboolean show,
+ gboolean update_second);
+void module_itip_formatter_dom_utils_set_buttons_sensitive
+ (WebKitDOMDocument *document,
+ gboolean sensitive);
+void module_itip_formatter_dom_utils_set_area_text
+ (WebKitDOMDocument *document,
+ const gchar *area_id,
+ const gchar *text);
+void module_itip_formatter_dom_utils_element_set_access_key
+ (WebKitDOMDocument *document,
+ const gchar *element_id,
+ const gchar *access_key);
+void module_itip_formatter_dom_utils_element_hide_child_nodes
+ (WebKitDOMDocument *document,
+ const gchar *element_id);
+void module_itip_formatter_dom_utils_enable_select
+ (WebKitDOMDocument *document,
+ const gchar *select_id,
+ gboolean enabled);
+gboolean module_itip_formatter_dom_utils_select_is_enabled
+ (WebKitDOMDocument *document,
+ const gchar *select_id);
+gchar * module_itip_formatter_dom_utils_select_get_value
+ (WebKitDOMDocument *document,
+ const gchar *select_id);
+void module_itip_formatter_dom_utils_select_set_selected
+ (WebKitDOMDocument *document,
+ const gchar *select_id,
+ const gchar *option);
+void module_itip_formatter_dom_utils_update_times
+ (WebKitDOMDocument *document,
+ const gchar *element_id,
+ const gchar *header,
+ const gchar *label);
+void module_itip_formatter_dom_utils_append_info_item_row
+ (WebKitDOMDocument *document,
+ const gchar *table_id,
+ const gchar *row_id,
+ const gchar *icon_name,
+ const gchar *message);
+void module_itip_formatter_dom_utils_enable_text_area
+ (WebKitDOMDocument *document,
+ const gchar *area_id,
+ gboolean enable);
+void module_itip_formatter_dom_utils_text_area_set_value
+ (WebKitDOMDocument *document,
+ const gchar *area_id,
+ const gchar *value);
+gchar * module_itip_formatter_dom_utils_text_area_get_value
+ (WebKitDOMDocument *document,
+ const gchar *area_id);
+void module_itip_formatter_dom_utils_rebuild_source_list
+ (WebKitDOMDocument *document,
+ const gchar *optgroup_id,
+ const gchar *optgroup_label,
+ const gchar *option_id,
+ const gchar *option_label,
+ gboolean writable);
+G_END_DECLS
+
+#endif /* MODULE_ITIP_FORMATTER_DOM_UTILS_H */
diff --git a/modules/itip-formatter/web-extension/module-itip-formatter-web-extension.c
b/modules/itip-formatter/web-extension/module-itip-formatter-web-extension.c
new file mode 100644
index 0000000..b83e590
--- /dev/null
+++ b/modules/itip-formatter/web-extension/module-itip-formatter-web-extension.c
@@ -0,0 +1,646 @@
+/*
+ * module-itip-formatter-web-extension.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/>
+ *
+ */
+
+#include "module-itip-formatter-web-extension.h"
+
+#include <gio/gio.h>
+#include <gtk/gtk.h>
+#include <webkit2/webkit-web-extension.h>
+
+#include <web-extensions/e-dom-utils.h>
+
+#include "module-itip-formatter-dom-utils.h"
+
+/* FIXME Clean it */
+static GDBusConnection *dbus_connection;
+
+static const char introspection_xml[] =
+"<node>"
+" <interface name='" MODULE_ITIP_FORMATTER_WEB_EXTENSION_INTERFACE "'>"
+" <signal name='RecurToggled'>"
+" <arg type='t' name='page_id' direction='out'/>"
+" <arg type='s' name='part_id' direction='out'/>"
+" </signal>"
+" <signal name='SourceChanged'>"
+" <arg type='t' name='page_id' direction='out'/>"
+" <arg type='s' name='part_id' direction='out'/>"
+" </signal>"
+" <method name='CreateDOMBindings'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='part_id' direction='in'/>"
+" </method>"
+" <method name='ShowButton'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='part_id' direction='in'/>"
+" <arg type='s' name='button_id' direction='in'/>"
+" </method>"
+" <method name='ElementSetInnerHTML'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='part_id' direction='in'/>"
+" <arg type='s' name='element_id' direction='in'/>"
+" <arg type='s' name='inner_html' direction='in'/>"
+" </method>"
+" <method name='RemoveElement'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='part_id' direction='in'/>"
+" <arg type='s' name='element_id' direction='in'/>"
+" </method>"
+" <method name='ElementRemoveChildNodes'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='part_id' direction='in'/>"
+" <arg type='s' name='element_id' direction='in'/>"
+" </method>"
+" <method name='EnableButton'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='part_id' direction='in'/>"
+" <arg type='s' name='button_id' direction='in'/>"
+" <arg type='b' name='enable' direction='in'/>"
+" </method>"
+" <method name='ElementIsHidden'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='part_id' direction='in'/>"
+" <arg type='s' name='element_id' direction='in'/>"
+" <arg type='b' name='is_hidden' direction='out'/>"
+" </method>"
+" <method name='HideElement'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='part_id' direction='in'/>"
+" <arg type='s' name='element_id' direction='in'/>"
+" <arg type='b' name='hide' direction='in'/>"
+" </method>"
+" <method name='InputSetChecked'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='part_id' direction='in'/>"
+" <arg type='s' name='input_id' direction='in'/>"
+" <arg type='b' name='checked' direction='in'/>"
+" </method>"
+" <method name='InputIsChecked'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='part_id' direction='in'/>"
+" <arg type='s' name='input_id' direction='in'/>"
+" <arg type='b' name='checked' direction='out'/>"
+" </method>"
+" <method name='ShowCheckbox'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='part_id' direction='in'/>"
+" <arg type='s' name='id' direction='in'/>"
+" <arg type='b' name='show' direction='in'/>"
+" <arg type='b' name='update_second' direction='in'/>"
+" </method>"
+" <method name='SetButtonsSensitive'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='part_id' direction='in'/>"
+" <arg type='b' name='sensitive' direction='in'/>"
+" </method>"
+" <method name='SetAreaText'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='part_id' direction='in'/>"
+" <arg type='s' name='id' direction='in'/>"
+" <arg type='s' name='text' direction='in'/>"
+" </method>"
+" <method name='ElementSetAccessKey'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='part_id' direction='in'/>"
+" <arg type='s' name='element_id' direction='in'/>"
+" <arg type='s' name='access_key' direction='in'/>"
+" </method>"
+" <method name='ElementHideChildNodes'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='part_id' direction='in'/>"
+" <arg type='s' name='element_id' direction='in'/>"
+" </method>"
+" <method name='EnableSelect'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='part_id' direction='in'/>"
+" <arg type='s' name='select_id' direction='in'/>"
+" <arg type='b' name='enable' direction='in'/>"
+" </method>"
+" <method name='SelectIsEnabled'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='part_id' direction='in'/>"
+" <arg type='s' name='select_id' direction='in'/>"
+" <arg type='b' name='enable' direction='out'/>"
+" </method>"
+" <method name='SelectGetValue'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='part_id' direction='in'/>"
+" <arg type='s' name='select_id' direction='in'/>"
+" <arg type='s' name='value' direction='out'/>"
+" </method>"
+" <method name='SelectSetSelected'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='part_id' direction='in'/>"
+" <arg type='s' name='select_id' direction='in'/>"
+" <arg type='s' name='option' direction='in'/>"
+" </method>"
+" <method name='UpdateTimes'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='part_id' direction='in'/>"
+" <arg type='s' name='element_id' direction='in'/>"
+" <arg type='s' name='header' direction='in'/>"
+" <arg type='s' name='label' direction='in'/>"
+" </method>"
+" <method name='AppendInfoItemRow'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='part_id' direction='in'/>"
+" <arg type='s' name='table_id' direction='in'/>"
+" <arg type='s' name='row_id' direction='in'/>"
+" <arg type='s' name='icon_name' direction='in'/>"
+" <arg type='s' name='message' direction='in'/>"
+" </method>"
+" <method name='EnableTextArea'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='part_id' direction='in'/>"
+" <arg type='s' name='area_id' direction='in'/>"
+" <arg type='b' name='enable' direction='in'/>"
+" </method>"
+" <method name='TextAreaSetValue'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='part_id' direction='in'/>"
+" <arg type='s' name='area_id' direction='in'/>"
+" <arg type='s' name='value' direction='in'/>"
+" </method>"
+" <method name='TextAreaGetValue'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='part_id' direction='in'/>"
+" <arg type='s' name='area_id' direction='in'/>"
+" <arg type='s' name='value' direction='out'/>"
+" </method>"
+" <method name='RebuildSourceList'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='part_id' direction='in'/>"
+" <arg type='s' name='optgroup_id' direction='in'/>"
+" <arg type='s' name='optgroup_label' direction='in'/>"
+" <arg type='s' name='option_id' direction='in'/>"
+" <arg type='s' name='option_label' direction='in'/>"
+" <arg type='b' name='writable' direction='in'/>"
+" </method>"
+" </interface>"
+"</node>";
+
+static WebKitDOMDocument *
+get_webkit_document_or_return_dbus_error (GDBusMethodInvocation *invocation,
+ WebKitWebExtension *web_extension,
+ guint64 page_id)
+{
+ WebKitDOMDocument *document;
+ WebKitWebPage *web_page;
+
+ web_page = webkit_web_extension_get_page (web_extension, page_id);
+ if (!web_page) {
+ g_dbus_method_invocation_return_error (
+ invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
+ "Invalid page ID: %" G_GUINT64_FORMAT, page_id);
+ return NULL;
+ }
+
+ document = webkit_web_page_get_dom_document (web_page);
+ if (!document) {
+ g_dbus_method_invocation_return_error (
+ invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
+ "No document for page ID: %" G_GUINT64_FORMAT, page_id);
+ return NULL;
+ }
+
+ return document;
+}
+
+static WebKitDOMDocument *
+find_webkit_document_for_partid_or_return_dbus_error (GDBusMethodInvocation *invocation,
+ WebKitDOMDocument *owner,
+ const gchar *part_id)
+{
+ WebKitDOMElement *element;
+
+ g_return_val_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation), NULL);
+ g_return_val_if_fail (WEBKIT_DOM_IS_DOCUMENT (owner), NULL);
+ g_return_val_if_fail (part_id && *part_id, NULL);
+
+ element = e_dom_utils_find_element_by_id (owner, part_id);
+ if (element && WEBKIT_DOM_IS_HTML_IFRAME_ELEMENT (element)) {
+ WebKitDOMDocument *document = webkit_dom_html_iframe_element_get_content_document
(WEBKIT_DOM_HTML_IFRAME_ELEMENT (element));
+ return document;
+ }
+
+ if (element)
+ g_dbus_method_invocation_return_error (
+ invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
+ "Part ID '%s' is not IFRAME, but %s", part_id, G_OBJECT_TYPE_NAME (element));
+ else
+ g_dbus_method_invocation_return_error (
+ invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
+ "Part ID '%s' not found", part_id);
+ return NULL;
+}
+
+static void
+handle_method_call (GDBusConnection *connection,
+ const char *sender,
+ const char *object_path,
+ const char *interface_name,
+ const char *method_name,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation,
+ gpointer user_data)
+{
+ WebKitWebExtension *web_extension = WEBKIT_WEB_EXTENSION (user_data);
+ WebKitDOMDocument *document;
+ const gchar *part_id = NULL;
+ guint64 page_id;
+
+ if (g_strcmp0 (interface_name, MODULE_ITIP_FORMATTER_WEB_EXTENSION_INTERFACE) != 0)
+ return;
+
+ if (g_strcmp0 (method_name, "CreateDOMBindings") == 0) {
+ g_variant_get (parameters, "(t&s)", &page_id, &part_id);
+
+ document = get_webkit_document_or_return_dbus_error (invocation, web_extension, page_id);
+ if (document)
+ document = find_webkit_document_for_partid_or_return_dbus_error (invocation,
document, part_id);
+ if (document) {
+ module_itip_formatter_dom_utils_create_dom_bindings (document, page_id, part_id,
connection);
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ }
+ } else if (g_strcmp0 (method_name, "ShowButton") == 0) {
+ const gchar *button_id;
+
+ g_variant_get (parameters, "(t&s&s)", &page_id, &part_id, &button_id);
+
+ document = get_webkit_document_or_return_dbus_error (invocation, web_extension, page_id);
+ if (document)
+ document = find_webkit_document_for_partid_or_return_dbus_error (invocation,
document, part_id);
+ if (document) {
+ module_itip_formatter_dom_utils_show_button (document, button_id);
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ }
+ } else if (g_strcmp0 (method_name, "EnableButton") == 0) {
+ const gchar *button_id;
+ gboolean enable;
+
+ g_variant_get (parameters, "(t&s&sb)", &page_id, &part_id, &button_id, &enable);
+
+ document = get_webkit_document_or_return_dbus_error (invocation, web_extension, page_id);
+ if (document)
+ document = find_webkit_document_for_partid_or_return_dbus_error (invocation,
document, part_id);
+ if (document) {
+ module_itip_formatter_dom_utils_enable_button (document, button_id, enable);
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ }
+ } else if (g_strcmp0 (method_name, "ElementSetInnerHTML") == 0) {
+ const gchar *element_id, *inner_html;
+
+ g_variant_get (parameters, "(t&s&s&s)", &page_id, &part_id, &element_id, &inner_html);
+
+ document = get_webkit_document_or_return_dbus_error (invocation, web_extension, page_id);
+ if (document)
+ document = find_webkit_document_for_partid_or_return_dbus_error (invocation,
document, part_id);
+ if (document) {
+ e_dom_utils_element_set_inner_html (document, element_id, inner_html);
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ }
+ } else if (g_strcmp0 (method_name, "RemoveElement") == 0) {
+ const gchar *element_id;
+
+ g_variant_get (parameters, "(t&s&s)", &page_id, &part_id, &element_id);
+
+ document = get_webkit_document_or_return_dbus_error (invocation, web_extension, page_id);
+ if (document)
+ document = find_webkit_document_for_partid_or_return_dbus_error (invocation,
document, part_id);
+ if (document) {
+ e_dom_utils_remove_element (document, element_id);
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ }
+ } else if (g_strcmp0 (method_name, "ElementRemoveChildNodes") == 0) {
+ const gchar *element_id;
+
+ g_variant_get (parameters, "(t&s&s)", &page_id, &part_id, &element_id);
+
+ document = get_webkit_document_or_return_dbus_error (invocation, web_extension, page_id);
+ if (document)
+ document = find_webkit_document_for_partid_or_return_dbus_error (invocation,
document, part_id);
+ if (document) {
+ e_dom_utils_element_remove_child_nodes (document, element_id);
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ }
+ } else if (g_strcmp0 (method_name, "HideElement") == 0) {
+ const gchar *element_id;
+ gboolean hide;
+
+ g_variant_get (parameters, "(t&s&sb)", &page_id, &part_id, &element_id, &hide);
+
+ document = get_webkit_document_or_return_dbus_error (invocation, web_extension, page_id);
+ if (document)
+ document = find_webkit_document_for_partid_or_return_dbus_error (invocation,
document, part_id);
+ if (document) {
+ e_dom_utils_hide_element (document, element_id, hide);
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ }
+ } else if (g_strcmp0 (method_name, "ElementIsHidden") == 0) {
+ const gchar *element_id;
+ gboolean hidden;
+
+ g_variant_get (parameters, "(t&s&s)", &page_id, &part_id, &element_id);
+
+ document = get_webkit_document_or_return_dbus_error (invocation, web_extension, page_id);
+ if (document)
+ document = find_webkit_document_for_partid_or_return_dbus_error (invocation,
document, part_id);
+ if (document) {
+ hidden = e_dom_utils_element_is_hidden (document, element_id);
+ g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", hidden));
+ }
+ } else if (g_strcmp0 (method_name, "InputSetChecked") == 0) {
+ const gchar *input_id;
+ gboolean checked;
+
+ g_variant_get (parameters, "(t&s&sb)", &page_id, &part_id, &input_id, &checked);
+
+ document = get_webkit_document_or_return_dbus_error (invocation, web_extension, page_id);
+ if (document)
+ document = find_webkit_document_for_partid_or_return_dbus_error (invocation,
document, part_id);
+ if (document) {
+ module_itip_formatter_dom_utils_input_set_checked (document, input_id, checked);
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ }
+ } else if (g_strcmp0 (method_name, "InputIsChecked") == 0) {
+ const gchar *input_id;
+ gboolean checked;
+
+ g_variant_get (parameters, "(t&s&s)", &page_id, &part_id, &input_id);
+
+ document = get_webkit_document_or_return_dbus_error (invocation, web_extension, page_id);
+ if (document)
+ document = find_webkit_document_for_partid_or_return_dbus_error (invocation,
document, part_id);
+ if (document) {
+ checked = module_itip_formatter_dom_utils_input_is_checked (document, input_id);
+ g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", checked));
+ }
+ } else if (g_strcmp0 (method_name, "ShowCheckbox") == 0) {
+ const gchar *id;
+ gboolean show, update_second;
+
+ g_variant_get (parameters, "(t&s&sbb)", &page_id, &part_id, &id, &show, &update_second);
+
+ document = get_webkit_document_or_return_dbus_error (invocation, web_extension, page_id);
+ if (document)
+ document = find_webkit_document_for_partid_or_return_dbus_error (invocation,
document, part_id);
+ if (document) {
+ module_itip_formatter_dom_utils_show_checkbox (document, id, show, update_second);
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ }
+ } else if (g_strcmp0 (method_name, "SetButtonsSensitive") == 0) {
+ gboolean sensitive;
+
+ g_variant_get (parameters, "(t&sb)", &page_id, &part_id, &sensitive);
+
+ document = get_webkit_document_or_return_dbus_error (invocation, web_extension, page_id);
+ if (document)
+ document = find_webkit_document_for_partid_or_return_dbus_error (invocation,
document, part_id);
+ if (document) {
+ module_itip_formatter_dom_utils_set_buttons_sensitive (document, sensitive);
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ }
+ } else if (g_strcmp0 (method_name, "SetAreaText") == 0) {
+ const gchar *id, *text;
+
+ g_variant_get (parameters, "(t&s&s&s)", &page_id, &part_id, &id, &text);
+
+ document = get_webkit_document_or_return_dbus_error (invocation, web_extension, page_id);
+ if (document)
+ document = find_webkit_document_for_partid_or_return_dbus_error (invocation,
document, part_id);
+ if (document) {
+ module_itip_formatter_dom_utils_set_area_text (document, id, text);
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ }
+ } else if (g_strcmp0 (method_name, "ElementSetAccessKey") == 0) {
+ const gchar *element_id, *access_key;
+
+ g_variant_get (parameters, "(t&s&s&s)", &page_id, &part_id, &element_id, &access_key);
+
+ document = get_webkit_document_or_return_dbus_error (invocation, web_extension, page_id);
+ if (document)
+ document = find_webkit_document_for_partid_or_return_dbus_error (invocation,
document, part_id);
+ if (document) {
+ module_itip_formatter_dom_utils_element_set_access_key (document, element_id,
access_key);
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ }
+ } else if (g_strcmp0 (method_name, "ElementHideChildNodes") == 0) {
+ const gchar *element_id;
+
+ g_variant_get (parameters, "(t&s&s)", &page_id, &part_id, &element_id);
+
+ document = get_webkit_document_or_return_dbus_error (invocation, web_extension, page_id);
+ if (document)
+ document = find_webkit_document_for_partid_or_return_dbus_error (invocation,
document, part_id);
+ if (document) {
+ module_itip_formatter_dom_utils_element_hide_child_nodes (document, element_id);
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ }
+ } else if (g_strcmp0 (method_name, "EnableSelect") == 0) {
+ const gchar *select_id;
+ gboolean enable;
+
+ g_variant_get (parameters, "(t&s&sb)", &page_id, &part_id, &select_id, &enable);
+
+ document = get_webkit_document_or_return_dbus_error (invocation, web_extension, page_id);
+ if (document)
+ document = find_webkit_document_for_partid_or_return_dbus_error (invocation,
document, part_id);
+ if (document) {
+ module_itip_formatter_dom_utils_enable_select (document, select_id, enable);
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ }
+ } else if (g_strcmp0 (method_name, "SelectIsEnabled") == 0) {
+ const gchar *select_id;
+ gboolean enabled;
+
+ g_variant_get (parameters, "(t&s&s)", &page_id, &part_id, &select_id);
+
+ document = get_webkit_document_or_return_dbus_error (invocation, web_extension, page_id);
+ if (document)
+ document = find_webkit_document_for_partid_or_return_dbus_error (invocation,
document, part_id);
+ if (document) {
+ enabled = module_itip_formatter_dom_utils_select_is_enabled (document, select_id);
+ g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", enabled));
+ }
+ } else if (g_strcmp0 (method_name, "SelectGetValue") == 0) {
+ const gchar *select_id;
+ gchar *value;
+
+ g_variant_get (parameters, "(t&s&s)", &page_id, &part_id, &select_id);
+
+ document = get_webkit_document_or_return_dbus_error (invocation, web_extension, page_id);
+ if (document)
+ document = find_webkit_document_for_partid_or_return_dbus_error (invocation,
document, part_id);
+ if (document) {
+ value = module_itip_formatter_dom_utils_select_get_value (document, select_id);
+ g_dbus_method_invocation_return_value (invocation,
+ g_variant_new (
+ "(@s)",
+ g_variant_new_take_string (value ? value : g_strdup (""))));
+ }
+ } else if (g_strcmp0 (method_name, "SelectSetSelected") == 0) {
+ const gchar *select_id, *option;
+
+ g_variant_get (parameters, "(t&s&s&s)", &page_id, &part_id, &select_id, &option);
+
+ document = get_webkit_document_or_return_dbus_error (invocation, web_extension, page_id);
+ if (document)
+ document = find_webkit_document_for_partid_or_return_dbus_error (invocation,
document, part_id);
+ if (document) {
+ module_itip_formatter_dom_utils_select_set_selected (document, select_id, option);
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ }
+ } else if (g_strcmp0 (method_name, "UpdateTimes") == 0) {
+ const gchar *element_id, *header, *label;
+
+ g_variant_get (parameters, "(t&s&s&s&s)", &page_id, &part_id, &element_id, &header, &label);
+
+ document = get_webkit_document_or_return_dbus_error (invocation, web_extension, page_id);
+ if (document)
+ document = find_webkit_document_for_partid_or_return_dbus_error (invocation,
document, part_id);
+ if (document) {
+ module_itip_formatter_dom_utils_update_times (document, element_id, header, label);
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ }
+ } else if (g_strcmp0 (method_name, "AppendInfoItemRow") == 0) {
+ const gchar *table_id, *row_id, *icon_name, *message;
+
+ g_variant_get (parameters, "(t&s&s&s&s&s)", &page_id, &part_id, &table_id, &row_id,
&icon_name, &message);
+
+ document = get_webkit_document_or_return_dbus_error (invocation, web_extension, page_id);
+ if (document)
+ document = find_webkit_document_for_partid_or_return_dbus_error (invocation,
document, part_id);
+ if (document) {
+ module_itip_formatter_dom_utils_append_info_item_row (document, table_id, row_id,
icon_name, message);
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ }
+ } else if (g_strcmp0 (method_name, "EnableTextArea") == 0) {
+ const gchar *area_id;
+ gboolean enable;
+
+ g_variant_get (parameters, "(t&s&sb)", &page_id, &part_id, &area_id, &enable);
+
+ document = get_webkit_document_or_return_dbus_error (invocation, web_extension, page_id);
+ if (document)
+ document = find_webkit_document_for_partid_or_return_dbus_error (invocation,
document, part_id);
+ if (document) {
+ module_itip_formatter_dom_utils_enable_text_area (document, area_id, enable);
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ }
+ } else if (g_strcmp0 (method_name, "TextAreaSetValue") == 0) {
+ const gchar *area_id, *value;
+
+ g_variant_get (parameters, "(t&s&s&s)", &page_id, &part_id, &area_id, &value);
+
+ document = get_webkit_document_or_return_dbus_error (invocation, web_extension, page_id);
+ if (document)
+ document = find_webkit_document_for_partid_or_return_dbus_error (invocation,
document, part_id);
+ if (document) {
+ module_itip_formatter_dom_utils_text_area_set_value (document, area_id, value);
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ }
+ } else if (g_strcmp0 (method_name, "TextAreaGetValue") == 0) {
+ const gchar *area_id;
+ gchar *value;
+
+ g_variant_get (parameters, "(t&s&s)", &page_id, &part_id, &area_id);
+
+ document = get_webkit_document_or_return_dbus_error (invocation, web_extension, page_id);
+ if (document)
+ document = find_webkit_document_for_partid_or_return_dbus_error (invocation,
document, part_id);
+ if (document) {
+ value = module_itip_formatter_dom_utils_text_area_get_value (document, area_id);
+ g_dbus_method_invocation_return_value (invocation,
+ g_variant_new (
+ "(@s)",
+ g_variant_new_take_string (value ? value : g_strdup (""))));
+ }
+ } else if (g_strcmp0 (method_name, "RebuildSourceList") == 0) {
+ const gchar *optgroup_id, *optgroup_label, *option_id, *option_label;
+ gboolean writable;
+
+ g_variant_get (parameters,"(t&s&s&s&s&sb)", &page_id, &part_id, &optgroup_id,
&optgroup_label, &option_id, &option_label, &writable);
+
+ document = get_webkit_document_or_return_dbus_error (invocation, web_extension, page_id);
+ if (document)
+ document = find_webkit_document_for_partid_or_return_dbus_error (invocation,
document, part_id);
+ if (document) {
+ module_itip_formatter_dom_utils_rebuild_source_list (
+ document,
+ optgroup_id,
+ optgroup_label,
+ option_id,
+ option_label,
+ writable);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ }
+ }
+}
+
+static const GDBusInterfaceVTable interface_vtable = {
+ handle_method_call,
+ NULL,
+ NULL
+};
+
+static void
+bus_acquired_cb (GDBusConnection *connection,
+ const char *name,
+ gpointer user_data)
+{
+ guint registration_id;
+ GError *error = NULL;
+ static GDBusNodeInfo *introspection_data = NULL;
+
+ if (!introspection_data)
+ introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL);
+
+ registration_id =
+ g_dbus_connection_register_object (
+ connection,
+ MODULE_ITIP_FORMATTER_WEB_EXTENSION_OBJECT_PATH,
+ introspection_data->interfaces[0],
+ &interface_vtable,
+ g_object_ref (user_data),
+ g_object_unref,
+ &error);
+
+ if (!registration_id) {
+ g_warning ("Failed to register object: %s\n", error->message);
+ g_error_free (error);
+ } else {
+ dbus_connection = connection;
+ g_object_add_weak_pointer (G_OBJECT (connection), (gpointer *)&dbus_connection);
+ }
+}
+
+/* Forward declaration */
+G_MODULE_EXPORT void webkit_web_extension_initialize (WebKitWebExtension *extension);
+
+G_MODULE_EXPORT void
+webkit_web_extension_initialize (WebKitWebExtension *extension)
+{
+ g_bus_own_name (
+ G_BUS_TYPE_SESSION,
+ MODULE_ITIP_FORMATTER_WEB_EXTENSION_SERVICE_NAME,
+ G_BUS_NAME_OWNER_FLAGS_NONE,
+ bus_acquired_cb,
+ NULL, NULL,
+ g_object_ref (extension),
+ g_object_unref);
+}
diff --git a/modules/itip-formatter/web-extension/module-itip-formatter-web-extension.h
b/modules/itip-formatter/web-extension/module-itip-formatter-web-extension.h
new file mode 100644
index 0000000..b9ffae0
--- /dev/null
+++ b/modules/itip-formatter/web-extension/module-itip-formatter-web-extension.h
@@ -0,0 +1,26 @@
+/*
+ * module-itip-formatter-web-extension.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/>
+ *
+ */
+
+#ifndef MODULE_ITIP_FORMATTER_WEB_EXTENSION_H
+#define MODULE_ITIP_FORMATTER_WEB_EXTENSION_H
+
+#define MODULE_ITIP_FORMATTER_WEB_EXTENSION_SERVICE_NAME
"org.gnome.Evolution.Module.ItipFormatter.WebExtension"
+#define MODULE_ITIP_FORMATTER_WEB_EXTENSION_OBJECT_PATH
"/org/gnome/Evolution/Module/ItipFormatter/WebExtension"
+#define MODULE_ITIP_FORMATTER_WEB_EXTENSION_INTERFACE
"org.gnome.Evolution.Module.ItipFormatter.WebExtension"
+
+#endif /* MODULE_ITIP_FORMATTER_WEB_EXTENSION_H */
diff --git a/modules/mail/e-mail-attachment-handler.c b/modules/mail/e-mail-attachment-handler.c
index 50d0c74..a5252b8 100644
--- a/modules/mail/e-mail-attachment-handler.c
+++ b/modules/mail/e-mail-attachment-handler.c
@@ -167,6 +167,65 @@ exit:
return message;
}
+typedef struct _CreateComposerData {
+ CamelMimeMessage *message;
+ CamelFolder *folder;
+ gboolean is_redirect;
+
+ gboolean is_reply;
+ EMailReplyType reply_type;
+
+ gboolean is_forward;
+ EMailForwardStyle forward_style;
+} CreateComposerData;
+
+static void
+create_composer_data_free (CreateComposerData *ccd)
+{
+ if (ccd) {
+ g_clear_object (&ccd->message);
+ g_clear_object (&ccd->folder);
+ g_free (ccd);
+ }
+}
+
+static void
+mail_attachment_handler_composer_created_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ CreateComposerData *ccd = user_data;
+ EMsgComposer *composer;
+ GError *error = NULL;
+
+ g_return_if_fail (ccd != NULL);
+
+ composer = e_msg_composer_new_finish (result, &error);
+ if (error) {
+ g_warning ("%s: Failed to create msg composer: %s", G_STRFUNC, error->message);
+ g_clear_error (&error);
+ } else {
+ if (ccd->is_redirect) {
+ em_utils_redirect_message (composer, ccd->message);
+ } else if (ccd->is_reply) {
+ GSettings *settings;
+ EMailReplyStyle style;
+
+ settings = e_util_ref_settings ("org.gnome.evolution.mail");
+ style = g_settings_get_enum (settings, "reply-style-name");
+ g_object_unref (settings);
+
+ em_utils_reply_to_message (composer, ccd->message, NULL, NULL, ccd->reply_type,
style, NULL, NULL);
+ } else if (ccd->is_forward) {
+ em_utils_forward_message (composer, ccd->message, ccd->forward_style, ccd->folder,
NULL);
+ } else {
+ em_utils_edit_message (composer, ccd->folder, ccd->message, NULL, TRUE);
+ }
+ }
+
+ create_composer_data_free (ccd);
+}
+
static void
mail_attachment_handler_forward_with_style (EAttachmentHandler *handler,
EMailForwardStyle style)
@@ -174,6 +233,8 @@ mail_attachment_handler_forward_with_style (EAttachmentHandler *handler,
EMailAttachmentHandlerPrivate *priv;
CamelMimeMessage *message;
CamelFolder *folder;
+ CreateComposerData *ccd;
+ EShell *shell;
priv = E_MAIL_ATTACHMENT_HANDLER_GET_PRIVATE (handler);
@@ -181,11 +242,15 @@ mail_attachment_handler_forward_with_style (EAttachmentHandler *handler,
g_return_if_fail (message != NULL);
folder = mail_attachment_handler_guess_folder_ref (handler);
+ shell = e_shell_backend_get_shell (E_SHELL_BACKEND (priv->backend));
- em_utils_forward_message (priv->backend, message, style, folder, NULL);
+ ccd = g_new0 (CreateComposerData, 1);
+ ccd->message = message;
+ ccd->folder = folder;
+ ccd->is_forward = TRUE;
+ ccd->forward_style = style;
- g_clear_object (&folder);
- g_object_unref (message);
+ e_msg_composer_new (shell, mail_attachment_handler_composer_created_cb, ccd);
}
static void
@@ -207,9 +272,8 @@ mail_attachment_handler_reply (EAttachmentHandler *handler,
EMailReplyType reply_type)
{
EMailAttachmentHandlerPrivate *priv;
- GSettings *settings;
- EMailReplyStyle style;
CamelMimeMessage *message;
+ CreateComposerData *ccd;
EShellBackend *shell_backend;
EShell *shell;
@@ -218,17 +282,15 @@ mail_attachment_handler_reply (EAttachmentHandler *handler,
message = mail_attachment_handler_get_selected_message (handler);
g_return_if_fail (message != NULL);
- settings = e_util_ref_settings ("org.gnome.evolution.mail");
- style = g_settings_get_enum (settings, "reply-style-name");
- g_object_unref (settings);
-
shell_backend = E_SHELL_BACKEND (priv->backend);
shell = e_shell_backend_get_shell (shell_backend);
- em_utils_reply_to_message (
- shell, message, NULL, NULL, reply_type, style, NULL, NULL);
+ ccd = g_new0 (CreateComposerData, 1);
+ ccd->message = message;
+ ccd->reply_type = reply_type;
+ ccd->is_reply = TRUE;
- g_object_unref (message);
+ e_msg_composer_new (shell, mail_attachment_handler_composer_created_cb, ccd);
}
static void
@@ -259,6 +321,7 @@ mail_attachment_handler_message_edit (GtkAction *action,
EMailAttachmentHandlerPrivate *priv;
CamelMimeMessage *message;
CamelFolder *folder;
+ CreateComposerData *ccd;
EShell *shell;
priv = E_MAIL_ATTACHMENT_HANDLER_GET_PRIVATE (handler);
@@ -269,10 +332,11 @@ mail_attachment_handler_message_edit (GtkAction *action,
shell = e_shell_backend_get_shell (E_SHELL_BACKEND (priv->backend));
folder = mail_attachment_handler_guess_folder_ref (handler);
- em_utils_edit_message (shell, folder, message, NULL, TRUE);
+ ccd = g_new0 (CreateComposerData, 1);
+ ccd->message = message;
+ ccd->folder = folder;
- g_clear_object (&folder);
- g_object_unref (message);
+ e_msg_composer_new (shell, mail_attachment_handler_composer_created_cb, ccd);
}
static void
@@ -301,6 +365,7 @@ mail_attachment_handler_redirect (GtkAction *action,
{
EMailAttachmentHandlerPrivate *priv;
CamelMimeMessage *message;
+ CreateComposerData *ccd;
EShell *shell;
priv = E_MAIL_ATTACHMENT_HANDLER_GET_PRIVATE (handler);
@@ -310,9 +375,12 @@ mail_attachment_handler_redirect (GtkAction *action,
shell = e_shell_backend_get_shell (E_SHELL_BACKEND (priv->backend));
- em_utils_redirect_message (shell, message);
+ ccd = g_new0 (CreateComposerData, 1);
+ ccd->message = message;
+ ccd->folder = NULL;
+ ccd->is_redirect = TRUE;
- g_object_unref (message);
+ e_msg_composer_new (shell, mail_attachment_handler_composer_created_cb, ccd);
}
static GtkActionEntry standard_entries[] = {
diff --git a/modules/mail/e-mail-shell-backend.c b/modules/mail/e-mail-shell-backend.c
index d748f31..506b0d7 100644
--- a/modules/mail/e-mail-shell-backend.c
+++ b/modules/mail/e-mail-shell-backend.c
@@ -293,6 +293,29 @@ action_mail_account_new_cb (GtkAction *action,
}
static void
+action_mail_message_new_composer_created_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ CamelFolder *folder = user_data;
+ EMsgComposer *composer;
+ GError *error = NULL;
+
+ if (folder)
+ g_return_if_fail (CAMEL_IS_FOLDER (folder));
+
+ composer = e_msg_composer_new_finish (result, &error);
+ if (error) {
+ g_warning ("%s: Failed to create msg composer: %s", G_STRFUNC, error->message);
+ g_clear_error (&error);
+ } else {
+ em_utils_compose_new_message (composer, folder);
+ }
+
+ g_clear_object (&folder);
+}
+
+static void
action_mail_message_new_cb (GtkAction *action,
EShellWindow *shell_window)
{
@@ -342,8 +365,9 @@ action_mail_message_new_cb (GtkAction *action,
g_free (folder_name);
}
-exit:
- em_utils_compose_new_message (shell, folder);
+ exit:
+ e_msg_composer_new (shell, action_mail_message_new_composer_created_cb,
+ folder ? g_object_ref (folder) : NULL);
}
static GtkActionEntry item_entries[] = {
@@ -495,11 +519,11 @@ mail_shell_backend_window_added_cb (GtkApplication *application,
/* This applies to both the composer and signature editor. */
if (editor != NULL) {
- EHTMLEditorView *view;
+ EContentEditor *cnt_editor;
GSettings *settings;
gboolean active = TRUE;
- view = e_html_editor_get_view (editor);
+ cnt_editor = e_html_editor_get_content_editor (editor);
settings = e_util_ref_settings ("org.gnome.evolution.mail");
@@ -508,7 +532,7 @@ mail_shell_backend_window_added_cb (GtkApplication *application,
g_object_unref (settings);
- e_html_editor_view_set_html_mode (view, active);
+ e_content_editor_set_html_mode (cnt_editor, active);
}
if (E_IS_MSG_COMPOSER (window)) {
diff --git a/modules/mail/e-mail-shell-content.c b/modules/mail/e-mail-shell-content.c
index 66a79c1..917c6cf 100644
--- a/modules/mail/e-mail-shell-content.c
+++ b/modules/mail/e-mail-shell-content.c
@@ -67,6 +67,27 @@ G_DEFINE_DYNAMIC_TYPE_EXTENDED (
E_TYPE_MAIL_READER,
e_mail_shell_content_reader_init))
+static gboolean
+mail_shell_content_transform_num_attachments_to_visible_boolean_with_settings (GBinding *binding,
+ const GValue *from_value,
+ GValue *to_value,
+ gpointer user_data)
+{
+ GSettings *settings;
+ gboolean res = TRUE;
+
+ settings = e_util_ref_settings ("org.gnome.evolution.mail");
+
+ if (g_settings_get_boolean (settings, "show-attachment-bar"))
+ res = e_attachment_store_transform_num_attachments_to_visible_boolean (binding, from_value,
to_value, user_data);
+ else
+ g_value_set_boolean (to_value, FALSE);
+
+ g_clear_object (&settings);
+
+ return res;
+}
+
static void
reconnect_changed_event (EMailReader *child,
EMailReader *parent)
@@ -179,9 +200,11 @@ mail_shell_content_constructed (GObject *object)
EMailShellContentPrivate *priv;
EShellContent *shell_content;
EShellView *shell_view;
+ EAttachmentStore *attachment_store;
+ EMailDisplay *display;
GtkWindow *window;
- GtkWidget *container;
GtkWidget *widget;
+ GtkBox *vbox;
priv = E_MAIL_SHELL_CONTENT_GET_PRIVATE (object);
@@ -193,11 +216,15 @@ mail_shell_content_constructed (GObject *object)
/* Build content widgets. */
- container = GTK_WIDGET (object);
+ widget = gtk_box_new (GTK_ORIENTATION_VERTICAL, 4);
+ gtk_container_add (GTK_CONTAINER (shell_content), widget);
+ gtk_widget_show (widget);
+
+ vbox = GTK_BOX (widget);
widget = e_mail_paned_view_new (shell_view);
+ gtk_box_pack_start (vbox, widget, TRUE, TRUE, 0);
- gtk_container_add (GTK_CONTAINER (container), widget);
priv->mail_view = g_object_ref (widget);
gtk_widget_show (widget);
@@ -208,6 +235,17 @@ mail_shell_content_constructed (GObject *object)
widget, "folder-loaded",
G_CALLBACK (reconnect_folder_loaded_event), object);
+ display = e_mail_reader_get_mail_display (E_MAIL_READER (object));
+ attachment_store = e_mail_display_get_attachment_store (display);
+ widget = GTK_WIDGET (e_mail_display_get_attachment_view (display));
+
+ e_binding_bind_property_full (
+ attachment_store, "num-attachments",
+ widget, "visible",
+ G_BINDING_SYNC_CREATE,
+ mail_shell_content_transform_num_attachments_to_visible_boolean_with_settings,
+ NULL, NULL, NULL);
+
window = e_mail_reader_get_window (E_MAIL_READER (object));
widget = e_mail_reader_get_message_list (E_MAIL_READER (object));
diff --git a/modules/mail/e-mail-shell-view-actions.c b/modules/mail/e-mail-shell-view-actions.c
index fc6cebf..d843671 100644
--- a/modules/mail/e-mail-shell-view-actions.c
+++ b/modules/mail/e-mail-shell-view-actions.c
@@ -256,6 +256,29 @@ action_mail_create_search_folder_cb (GtkAction *action,
}
static void
+action_mail_attachment_bar_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ EMailDisplay *mail_display;
+ EAttachmentView *attachment_view;
+
+ g_return_if_fail (E_IS_MAIL_SHELL_VIEW (mail_shell_view));
+
+ mail_display = e_mail_reader_get_mail_display (E_MAIL_READER
(mail_shell_view->priv->mail_shell_content));
+ attachment_view = e_mail_display_get_attachment_view (mail_display);
+ if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) {
+ EAttachmentStore *store;
+ guint num_attachments;
+
+ store = e_attachment_bar_get_store (E_ATTACHMENT_BAR (attachment_view));
+ num_attachments = e_attachment_store_get_num_attachments (store);
+ gtk_widget_set_visible (GTK_WIDGET (attachment_view), num_attachments > 0);
+ } else {
+ gtk_widget_hide (GTK_WIDGET (attachment_view));
+ }
+}
+
+static void
action_mail_download_finished_cb (CamelStore *store,
GAsyncResult *result,
EActivity *activity)
@@ -2025,6 +2048,14 @@ static GtkToggleActionEntry mail_toggle_entries[] = {
NULL, /* Handled by property bindings */
TRUE },
+ { "mail-attachment-bar",
+ NULL,
+ N_("Show _Attachment Bar"),
+ NULL,
+ N_("Show Attachment Bar below the message preview pane when the message has attachments"),
+ G_CALLBACK (action_mail_attachment_bar_cb),
+ TRUE },
+
{ "mail-show-deleted",
NULL,
N_("Show _Deleted Messages"),
@@ -2334,6 +2365,11 @@ e_mail_shell_view_actions_init (EMailShellView *mail_shell_view)
ACTION (MAIL_VFOLDER_UNMATCHED_ENABLE), "active",
G_SETTINGS_BIND_DEFAULT);
+ g_settings_bind (
+ settings, "show-attachment-bar",
+ ACTION (MAIL_ATTACHMENT_BAR), "active",
+ G_SETTINGS_BIND_DEFAULT);
+
g_object_unref (settings);
/* Fine tuning. */
diff --git a/modules/mail/e-mail-shell-view-actions.h b/modules/mail/e-mail-shell-view-actions.h
index 866cc98..5459f73 100644
--- a/modules/mail/e-mail-shell-view-actions.h
+++ b/modules/mail/e-mail-shell-view-actions.h
@@ -34,6 +34,8 @@
E_SHELL_WINDOW_ACTION ((window), "mail-account-refresh")
#define E_SHELL_WINDOW_ACTION_MAIL_ADD_SENDER(window) \
E_SHELL_WINDOW_ACTION ((window), "mail-add-sender")
+#define E_SHELL_WINDOW_ACTION_MAIL_ATTACHMENT_BAR(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-attachment-bar")
#define E_SHELL_WINDOW_ACTION_MAIL_CARET_MODE(window) \
E_SHELL_WINDOW_ACTION ((window), "mail-caret-mode")
#define E_SHELL_WINDOW_ACTION_MAIL_CHECK_FOR_JUNK(window) \
diff --git a/modules/mail/e-mail-shell-view-private.c b/modules/mail/e-mail-shell-view-private.c
index caf2392..e3c5ec1 100644
--- a/modules/mail/e-mail-shell-view-private.c
+++ b/modules/mail/e-mail-shell-view-private.c
@@ -250,6 +250,33 @@ mail_shell_view_folder_tree_popup_event_cb (EShellView *shell_view,
}
static gboolean
+mail_shell_view_mail_display_needs_key (EMailShellView *mail_shell_view,
+ EMailDisplay *mail_display)
+{
+ if (gtk_widget_has_focus (GTK_WIDGET (mail_display))) {
+ GDBusProxy *web_extension;
+
+ /* Intentionally use Evolution Web Extension */
+ web_extension = e_web_view_get_web_extension_proxy (E_WEB_VIEW (mail_display));
+ if (web_extension) {
+ GVariant *result;
+
+ result = g_dbus_proxy_get_cached_property (web_extension, "NeedInput");
+ if (result) {
+ gboolean need_input;
+
+ need_input = g_variant_get_boolean (result);
+ g_variant_unref (result);
+
+ return need_input;
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+static gboolean
mail_shell_view_key_press_event_cb (EMailShellView *mail_shell_view,
GdkEventKey *event)
{
@@ -281,42 +308,11 @@ mail_shell_view_key_press_event_cb (EMailShellView *mail_shell_view,
action = ACTION (MAIL_SMART_BACKWARD);
break;
- case GDK_KEY_Home:
- case GDK_KEY_Left:
- case GDK_KEY_Up:
- case GDK_KEY_Right:
- case GDK_KEY_Down:
- case GDK_KEY_Next:
- case GDK_KEY_End:
- case GDK_KEY_Begin:
- /* If Caret mode is enabled don't try to process these keys */
- if (e_web_view_get_caret_mode (E_WEB_VIEW (mail_display)))
- return FALSE;
- case GDK_KEY_Prior:
- if (!e_mail_display_needs_key (mail_display, FALSE) &&
- webkit_web_view_get_main_frame (WEBKIT_WEB_VIEW (mail_display)) !=
- webkit_web_view_get_focused_frame (WEBKIT_WEB_VIEW (mail_display))) {
- WebKitDOMDocument *document;
- WebKitDOMDOMWindow *window;
-
- document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (mail_display));
- window = webkit_dom_document_get_default_view (document);
-
- /* Workaround WebKit bug for key navigation, when inner IFRAME is focused.
- * EMailView's inner IFRAMEs have disabled scrolling, but WebKit doesn't post
- * key navigation events to parent's frame, thus the view doesn't scroll.
- * This is a poor workaround for this issue, the main frame is focused,
- * which has scrolling enabled.
- */
- webkit_dom_dom_window_focus (window);
- }
-
- return FALSE;
default:
return FALSE;
}
- if (e_mail_display_needs_key (mail_display, TRUE))
+ if (mail_shell_view_mail_display_needs_key (mail_shell_view, mail_display))
return FALSE;
gtk_action_activate (action);
diff --git a/modules/mail/e-mail-shell-view-private.h b/modules/mail/e-mail-shell-view-private.h
index 4300742..c2eb113 100644
--- a/modules/mail/e-mail-shell-view-private.h
+++ b/modules/mail/e-mail-shell-view-private.h
@@ -167,6 +167,8 @@ void e_mail_shell_view_update_sidebar
(EMailShellView *mail_shell_view);
void e_mail_shell_view_update_send_receive_menus
(EMailShellView *mail_shell_view);
+GDBusProxy * e_mail_shell_view_get_web_extension_proxy
+ (EMailShellView *mail_shell_view);
G_END_DECLS
diff --git a/modules/mail/em-composer-prefs.c b/modules/mail/em-composer-prefs.c
index 11d9172..ecdcf40 100644
--- a/modules/mail/em-composer-prefs.c
+++ b/modules/mail/em-composer-prefs.c
@@ -141,11 +141,10 @@ spell_language_save (EMComposerPrefs *prefs)
static void
spell_setup (EMComposerPrefs *prefs)
{
- GList *list, *link;
+ GList *list = NULL, *link;
GtkListStore *store;
store = GTK_LIST_STORE (prefs->language_model);
-
list = e_spell_checker_list_available_dicts (prefs->spell_checker);
/* Populate the GtkListStore. */
diff --git a/modules/prefer-plain/e-mail-display-popup-prefer-plain.c
b/modules/prefer-plain/e-mail-display-popup-prefer-plain.c
index c23e5d2..21fc1ce 100644
--- a/modules/prefer-plain/e-mail-display-popup-prefer-plain.c
+++ b/modules/prefer-plain/e-mail-display-popup-prefer-plain.c
@@ -35,12 +35,11 @@ typedef struct _EMailDisplayPopupPreferPlainClass EMailDisplayPopupPreferPlainCl
struct _EMailDisplayPopupPreferPlain {
EExtension parent;
- WebKitDOMDocument *document;
gchar *text_plain_id;
gchar *text_html_id;
+ gchar *document_uri;
GtkActionGroup *action_group;
-
};
struct _EMailDisplayPopupPreferPlainClass {
@@ -94,16 +93,20 @@ toggle_part (GtkAction *action,
EMailDisplayPopupExtension *extension)
{
EMailDisplayPopupPreferPlain *pp_extension = (EMailDisplayPopupPreferPlain *) extension;
- WebKitDOMDocument *doc = pp_extension->document;
- WebKitDOMDOMWindow *window;
- WebKitDOMElement *frame_element;
SoupURI *soup_uri;
GHashTable *query;
gchar *uri;
- uri = webkit_dom_document_get_document_uri (doc);
- soup_uri = soup_uri_new (uri);
- g_free (uri);
+ if (!pp_extension->document_uri)
+ return;
+
+ soup_uri = soup_uri_new (pp_extension->document_uri);
+
+ if (!soup_uri || !soup_uri->query) {
+ if (soup_uri)
+ soup_uri_free (soup_uri);
+ return;
+ }
query = soup_form_decode (soup_uri->query);
g_hash_table_replace (
@@ -123,11 +126,8 @@ toggle_part (GtkAction *action,
uri = soup_uri_to_string (soup_uri, FALSE);
soup_uri_free (soup_uri);
- /* Get frame's window and from the window the actual <iframe> element */
- window = webkit_dom_document_get_default_view (doc);
- frame_element = webkit_dom_dom_window_get_frame_element (window);
- webkit_dom_html_iframe_element_set_src (
- WEBKIT_DOM_HTML_IFRAME_ELEMENT (frame_element), uri);
+ e_web_view_set_document_iframe_src (E_WEB_VIEW (e_extension_get_extensible (E_EXTENSION (extension))),
+ pp_extension->document_uri, uri);
g_free (uri);
}
@@ -169,6 +169,17 @@ set_text_html_id (EMailDisplayPopupPreferPlain *extension,
extension->text_html_id = g_strdup (id);
}
+static void
+set_document_uri (EMailDisplayPopupPreferPlain *extension,
+ const gchar *document_uri)
+{
+ if (extension->document_uri == document_uri)
+ return;
+
+ g_free (extension->document_uri);
+ extension->document_uri = g_strdup (document_uri);
+}
+
static GtkActionGroup *
create_group (EMailDisplayPopupExtension *extension)
{
@@ -218,18 +229,17 @@ create_group (EMailDisplayPopupExtension *extension)
static void
mail_display_popup_prefer_plain_update_actions (EMailDisplayPopupExtension *extension,
- WebKitHitTestResult *context)
+ const gchar *popup_document_uri)
{
EMailDisplay *display;
+ EMailDisplayPopupPreferPlain *pp_extension;
GtkAction *action;
- WebKitDOMNode *node;
- gchar *uri, *part_id, *pos, *prefix;
+ gchar *part_id, *pos, *prefix;
SoupURI *soup_uri;
GHashTable *query;
EMailPartList *part_list;
gboolean is_text_plain;
const gchar *action_name;
- EMailDisplayPopupPreferPlain *pp_extension;
GQueue queue = G_QUEUE_INIT;
GList *head, *link;
@@ -241,22 +251,17 @@ mail_display_popup_prefer_plain_update_actions (EMailDisplayPopupExtension *exte
if (!pp_extension->action_group)
pp_extension->action_group = create_group (extension);
- g_object_get (context, "inner-node", &node, NULL);
+ set_document_uri (pp_extension, popup_document_uri);
- if (!node) {
- gtk_action_group_set_visible (pp_extension->action_group, FALSE);
- return;
- }
+ if (pp_extension->document_uri)
+ soup_uri = soup_uri_new (pp_extension->document_uri);
+ else
+ soup_uri = NULL;
- pp_extension->document = webkit_dom_node_get_owner_document (node);
- uri = webkit_dom_document_get_document_uri (pp_extension->document);
-
- soup_uri = soup_uri_new (uri);
if (!soup_uri || !soup_uri->query) {
gtk_action_group_set_visible (pp_extension->action_group, FALSE);
if (soup_uri)
soup_uri_free (soup_uri);
- g_free (uri);
return;
}
@@ -264,28 +269,19 @@ mail_display_popup_prefer_plain_update_actions (EMailDisplayPopupExtension *exte
part_id = g_hash_table_lookup (query, "part_id");
if (part_id == NULL) {
gtk_action_group_set_visible (pp_extension->action_group, FALSE);
- g_hash_table_destroy (query);
- soup_uri_free (soup_uri);
- g_free (uri);
- return;
+ goto out;
}
pos = strstr (part_id, ".alternative-prefer-plain.");
if (!pos) {
gtk_action_group_set_visible (pp_extension->action_group, FALSE);
- g_hash_table_destroy (query);
- soup_uri_free (soup_uri);
- g_free (uri);
- return;
+ goto out;
}
/* Don't display the actions on any other than text/plain or text/html parts */
if (!strstr (pos, "plain_text") && !strstr (pos, "text_html")) {
gtk_action_group_set_visible (pp_extension->action_group, FALSE);
- g_hash_table_destroy (query);
- soup_uri_free (soup_uri);
- g_free (uri);
- return;
+ goto out;
}
/* Check whether the displayed part is text_plain */
@@ -353,9 +349,9 @@ mail_display_popup_prefer_plain_update_actions (EMailDisplayPopupExtension *exte
}
g_free (prefix);
+ out:
g_hash_table_destroy (query);
soup_uri_free (soup_uri);
- g_free (uri);
}
void
@@ -377,8 +373,7 @@ e_mail_display_popup_prefer_plain_dispose (GObject *object)
}
/* Chain up to parent's dispose() method. */
- G_OBJECT_CLASS (e_mail_display_popup_prefer_plain_parent_class)->
- dispose (object);
+ G_OBJECT_CLASS (e_mail_display_popup_prefer_plain_parent_class)->dispose (object);
}
static void
@@ -390,10 +385,10 @@ e_mail_display_popup_prefer_plain_finalize (GObject *object)
g_free (extension->text_html_id);
g_free (extension->text_plain_id);
+ g_free (extension->document_uri);
/* Chain up to parent's finalize() method. */
- G_OBJECT_CLASS (e_mail_display_popup_prefer_plain_parent_class)->
- finalize (object);
+ G_OBJECT_CLASS (e_mail_display_popup_prefer_plain_parent_class)->finalize (object);
}
static void
@@ -419,7 +414,6 @@ e_mail_display_popup_extension_interface_init (EMailDisplayPopupExtensionInterfa
void
e_mail_display_popup_prefer_plain_class_finalize (EMailDisplayPopupPreferPlainClass *class)
{
-
}
static void
@@ -428,5 +422,5 @@ e_mail_display_popup_prefer_plain_init (EMailDisplayPopupPreferPlain *extension)
extension->action_group = NULL;
extension->text_html_id = NULL;
extension->text_plain_id = NULL;
- extension->document = NULL;
+ extension->document_uri = NULL;
}
diff --git a/modules/settings/Makefile.am b/modules/settings/Makefile.am
index e137bea..45db4e8 100644
--- a/modules/settings/Makefile.am
+++ b/modules/settings/Makefile.am
@@ -25,8 +25,8 @@ module_settings_la_SOURCES = \
e-settings-date-edit.h \
e-settings-deprecated.c \
e-settings-deprecated.h \
- e-settings-html-editor-view.c \
- e-settings-html-editor-view.h \
+ e-settings-content-editor.c \
+ e-settings-content-editor.h \
e-settings-mail-browser.c \
e-settings-mail-browser.h \
e-settings-mail-formatter.c \
diff --git a/modules/settings/e-settings-content-editor.c b/modules/settings/e-settings-content-editor.c
new file mode 100644
index 0000000..3bc438c
--- /dev/null
+++ b/modules/settings/e-settings-content-editor.c
@@ -0,0 +1,224 @@
+/*
+ * e-settings-content-editor.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.
+ *
+ * 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 General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#include "e-settings-content-editor.h"
+
+#include <e-util/e-util.h>
+
+#define E_SETTINGS_CONTENT_EDITOR_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_SETTINGS_CONTENT_EDITOR, ESettingsContentEditorPrivate))
+
+struct _ESettingsContentEditorPrivate {
+ GSettings *settings;
+
+ GHashTable *old_settings;
+};
+
+G_DEFINE_DYNAMIC_TYPE (
+ ESettingsContentEditor,
+ e_settings_content_editor,
+ E_TYPE_EXTENSION)
+
+static void
+settings_content_editor_inline_spelling_changed (ESettingsContentEditor *extension,
+ gboolean spell_check_enabled)
+{
+ EExtensible *extensible;
+ EContentEditor *cnt_editor;
+
+ extensible = e_extension_get_extensible (E_EXTENSION (extension));
+ cnt_editor = e_html_editor_get_content_editor (E_HTML_EDITOR (extensible));
+
+ e_content_editor_set_spell_check_enabled (cnt_editor, spell_check_enabled);
+}
+
+static void
+settings_content_editor_load_style (ESettingsContentEditor *extension)
+{
+ EExtensible *extensible;
+ EContentEditor *cnt_editor;
+
+ extensible = e_extension_get_extensible (E_EXTENSION (extension));
+ cnt_editor = e_html_editor_get_content_editor (E_HTML_EDITOR (extensible));
+ e_content_editor_update_styles (cnt_editor);
+}
+
+static void
+settings_content_editor_changed_cb (GSettings *settings,
+ const gchar *key,
+ ESettingsContentEditor *extension)
+{
+ GVariant *new_value, *old_value;
+
+ new_value = g_settings_get_value (settings, key);
+ old_value = g_hash_table_lookup (extension->priv->old_settings, key);
+
+ if (!new_value || !old_value || !g_variant_equal (new_value, old_value)) {
+ if (new_value)
+ g_hash_table_insert (extension->priv->old_settings, g_strdup (key), new_value);
+ else
+ g_hash_table_remove (extension->priv->old_settings, key);
+
+ if (g_strcmp0 (key, "composer-inline-spelling") == 0)
+ settings_content_editor_inline_spelling_changed (extension, g_settings_get_boolean
(settings, key));
+ else
+ settings_content_editor_load_style (extension);
+ } else if (new_value) {
+ g_variant_unref (new_value);
+ }
+}
+
+static void
+settings_content_editor_html_editor_realize_cb (GtkWidget *html_editor,
+ ESettingsContentEditor *extension)
+{
+ GSettings *settings;
+
+ settings = extension->priv->settings;
+
+ settings_content_editor_inline_spelling_changed (extension, g_settings_get_boolean (settings,
"composer-inline-spelling"));
+ settings_content_editor_load_style (extension);
+
+ /* Reload the web view when certain settings change. */
+
+ g_signal_connect (
+ settings, "changed::use-custom-font",
+ G_CALLBACK (settings_content_editor_changed_cb), extension);
+
+ g_signal_connect (
+ settings, "changed::monospace-font",
+ G_CALLBACK (settings_content_editor_changed_cb), extension);
+
+ g_signal_connect (
+ settings, "changed::variable-width-font",
+ G_CALLBACK (settings_content_editor_changed_cb), extension);
+
+ g_signal_connect (
+ settings, "changed::mark-citations",
+ G_CALLBACK (settings_content_editor_changed_cb), extension);
+
+ g_signal_connect (
+ settings, "changed::citation-color",
+ G_CALLBACK (settings_content_editor_changed_cb), extension);
+
+ g_signal_connect (
+ settings, "changed::composer-inline-spelling",
+ G_CALLBACK (settings_content_editor_changed_cb), extension);
+}
+
+static void
+settings_content_editor_dispose (GObject *object)
+{
+ ESettingsContentEditorPrivate *priv;
+
+ priv = E_SETTINGS_CONTENT_EDITOR_GET_PRIVATE (object);
+
+ if (priv->settings != NULL) {
+ g_signal_handlers_disconnect_by_func (
+ priv->settings,
+ settings_content_editor_changed_cb, object);
+ }
+
+ g_clear_object (&priv->settings);
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (e_settings_content_editor_parent_class)->dispose (object);
+}
+
+static void
+settings_content_editor_finalize (GObject *object)
+{
+ ESettingsContentEditorPrivate *priv;
+
+ priv = E_SETTINGS_CONTENT_EDITOR_GET_PRIVATE (object);
+
+ if (priv->old_settings) {
+ g_hash_table_destroy (priv->old_settings);
+ priv->old_settings = NULL;
+ }
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (e_settings_content_editor_parent_class)->finalize (object);
+}
+
+static void
+settings_content_editor_constructed (GObject *object)
+{
+ EExtensible *extensible;
+
+ /* Chain up to parent's method. */
+ G_OBJECT_CLASS (e_settings_content_editor_parent_class)->constructed (object);
+
+ extensible = e_extension_get_extensible (E_EXTENSION (object));
+
+ g_signal_connect (
+ extensible, "realize",
+ G_CALLBACK (settings_content_editor_html_editor_realize_cb), object);
+}
+
+static void
+e_settings_content_editor_class_init (ESettingsContentEditorClass *class)
+{
+ GObjectClass *object_class;
+ EExtensionClass *extension_class;
+
+ g_type_class_add_private (class, sizeof (ESettingsContentEditorPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->dispose = settings_content_editor_dispose;
+ object_class->finalize = settings_content_editor_finalize;
+ object_class->constructed = settings_content_editor_constructed;
+
+ extension_class = E_EXTENSION_CLASS (class);
+ extension_class->extensible_type = E_TYPE_HTML_EDITOR;
+}
+
+static void
+e_settings_content_editor_class_finalize (ESettingsContentEditorClass *class)
+{
+}
+
+static void
+e_settings_content_editor_init (ESettingsContentEditor *extension)
+{
+ GSettings *settings;
+
+ extension->priv = E_SETTINGS_CONTENT_EDITOR_GET_PRIVATE (extension);
+
+ settings = e_util_ref_settings ("org.gnome.evolution.mail");
+ extension->priv->settings = settings;
+
+ extension->priv->old_settings = g_hash_table_new_full (
+ g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_variant_unref);
+}
+
+void
+e_settings_content_editor_type_register (GTypeModule *type_module)
+{
+ /* XXX G_DEFINE_DYNAMIC_TYPE declares a static type registration
+ * function, so we have to wrap it with a public function in
+ * order to register types from a separate compilation unit. */
+ e_settings_content_editor_register_type (type_module);
+}
diff --git a/modules/settings/e-settings-content-editor.h b/modules/settings/e-settings-content-editor.h
new file mode 100644
index 0000000..2b5dc90
--- /dev/null
+++ b/modules/settings/e-settings-content-editor.h
@@ -0,0 +1,64 @@
+/*
+ * e-settings-content-editor.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.
+ *
+ * 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 General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef E_SETTINGS_CONTENT_EDITOR_H
+#define E_SETTINGS_CONTENT_EDITOR_H
+
+#include <libebackend/libebackend.h>
+
+/* Standard GObject macros */
+#define E_TYPE_SETTINGS_CONTENT_EDITOR \
+ (e_settings_content_editor_get_type ())
+#define E_SETTINGS_CONTENT_EDITOR(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_SETTINGS_CONTENT_EDITOR, ESettingsContentEditor))
+#define E_SETTINGS_CONTENT_EDITOR_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_SETTINGS_CONTENT_EDITOR, ESettingsContentEditorClass))
+#define E_IS_SETTINGS_CONTENT_EDITOR(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_SETTINGS_CONTENT_EDITOR))
+#define E_IS_SETTINGS_CONTENT_EDITOR_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_SETTINGS_CONTENT_EDITOR))
+#define E_SETTINGS_CONTENT_EDITOR_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_SETTINGS_CONTENT_EDITOR, ESettingsContentEditorClass))
+
+G_BEGIN_DECLS
+
+typedef struct _ESettingsContentEditor ESettingsContentEditor;
+typedef struct _ESettingsContentEditorClass ESettingsContentEditorClass;
+typedef struct _ESettingsContentEditorPrivate ESettingsContentEditorPrivate;
+
+struct _ESettingsContentEditor {
+ EExtension parent;
+ ESettingsContentEditorPrivate *priv;
+};
+
+struct _ESettingsContentEditorClass {
+ EExtensionClass parent_class;
+};
+
+GType e_settings_content_editor_get_type
+ (void) G_GNUC_CONST;
+void e_settings_content_editor_type_register
+ (GTypeModule *type_module);
+
+G_END_DECLS
+
+#endif /* E_SETTINGS_CONTENT_EDITOR_H */
diff --git a/modules/settings/e-settings-spell-checker.c b/modules/settings/e-settings-spell-checker.c
index 8192766..812e3b0 100644
--- a/modules/settings/e-settings-spell-checker.c
+++ b/modules/settings/e-settings-spell-checker.c
@@ -62,8 +62,7 @@ settings_spell_checker_constructed (GObject *object)
E_SETTINGS_SPELL_CHECKER (object));
/* Make sure there are no active languages at this point. */
- g_warn_if_fail (
- e_spell_checker_count_active_languages (spell_checker) == 0);
+ g_warn_if_fail (e_spell_checker_count_active_languages (spell_checker) == 0);
settings = e_util_ref_settings ("org.gnome.evolution.mail");
strv = g_settings_get_strv (settings, "composer-spell-languages");
diff --git a/modules/settings/evolution-module-settings.c b/modules/settings/evolution-module-settings.c
index 5b81a94..8ade039 100644
--- a/modules/settings/evolution-module-settings.c
+++ b/modules/settings/evolution-module-settings.c
@@ -19,9 +19,10 @@
#include "e-settings-calendar-item.h"
#include "e-settings-calendar-view.h"
#include "e-settings-client-cache.h"
+#include "e-settings-content-editor.h"
#include "e-settings-date-edit.h"
#include "e-settings-deprecated.h"
-#include "e-settings-html-editor-view.h"
+#include "e-settings-content-editor.h"
#include "e-settings-mail-browser.h"
#include "e-settings-mail-formatter.h"
#include "e-settings-mail-part-headers.h"
@@ -46,9 +47,10 @@ e_module_load (GTypeModule *type_module)
e_settings_calendar_item_type_register (type_module);
e_settings_calendar_view_type_register (type_module);
e_settings_client_cache_type_register (type_module);
+ e_settings_content_editor_type_register (type_module);
e_settings_date_edit_type_register (type_module);
e_settings_deprecated_type_register (type_module);
- e_settings_html_editor_view_type_register (type_module);
+ e_settings_content_editor_type_register (type_module);
e_settings_mail_browser_type_register (type_module);
e_settings_mail_formatter_type_register (type_module);
e_settings_mail_part_headers_type_register (type_module);
diff --git a/modules/text-highlight/e-mail-display-popup-text-highlight.c
b/modules/text-highlight/e-mail-display-popup-text-highlight.c
index eb072a0..a28932e 100644
--- a/modules/text-highlight/e-mail-display-popup-text-highlight.c
+++ b/modules/text-highlight/e-mail-display-popup-text-highlight.c
@@ -36,7 +36,8 @@ typedef struct _EMailDisplayPopupTextHighlight {
GtkActionGroup *action_group;
- WebKitDOMDocument *document;
+ volatile gint updating;
+ gchar *document_uri;
} EMailDisplayPopupTextHighlight;
typedef struct _EMailDisplayPopupTextHighlightClass {
@@ -107,33 +108,42 @@ static GtkActionEntry entries[] = {
};
static void
+set_document_uri (EMailDisplayPopupTextHighlight *extension,
+ const gchar *document_uri)
+{
+ if (extension->document_uri == document_uri)
+ return;
+
+ g_free (extension->document_uri);
+ extension->document_uri = g_strdup (document_uri);
+}
+
+static void
reformat (GtkAction *old,
GtkAction *action,
gpointer user_data)
{
EMailDisplayPopupTextHighlight *th_extension;
- WebKitDOMDocument *doc;
- WebKitDOMDOMWindow *window;
- WebKitDOMElement *frame_element;
SoupURI *soup_uri;
GHashTable *query;
gchar *uri;
th_extension = E_MAIL_DISPLAY_POPUP_TEXT_HIGHLIGHT (user_data);
- doc = th_extension->document;
- if (!doc)
+
+ if (g_atomic_int_get (&th_extension->updating))
return;
- uri = webkit_dom_document_get_document_uri (doc);
- soup_uri = soup_uri_new (uri);
- g_free (uri);
+ if (th_extension->document_uri)
+ soup_uri = soup_uri_new (th_extension->document_uri);
+ else
+ soup_uri = NULL;
if (!soup_uri)
- goto exit;
+ return;
if (!soup_uri->query) {
soup_uri_free (soup_uri);
- goto exit;
+ return;
}
query = soup_form_decode (soup_uri->query);
@@ -148,17 +158,10 @@ reformat (GtkAction *old,
uri = soup_uri_to_string (soup_uri, FALSE);
soup_uri_free (soup_uri);
- /* Get frame's window and from the window the actual <iframe> element */
- window = webkit_dom_document_get_default_view (doc);
- frame_element = webkit_dom_dom_window_get_frame_element (window);
- webkit_dom_html_iframe_element_set_src (
- WEBKIT_DOM_HTML_IFRAME_ELEMENT (frame_element), uri);
+ e_web_view_set_document_iframe_src (E_WEB_VIEW (e_extension_get_extensible (E_EXTENSION
(th_extension))),
+ th_extension->document_uri, uri);
g_free (uri);
-
- /* The frame has been reloaded, the document pointer is invalid now */
-exit:
- th_extension->document = NULL;
}
static GtkActionGroup *
@@ -215,10 +218,12 @@ create_group (EMailDisplayPopupExtension *extension)
NULL, NULL, action_index);
action_index++;
gtk_action_group_add_action (group, GTK_ACTION (action));
- g_signal_connect (
- action, "changed",
- G_CALLBACK (reformat), extension);
- gtk_radio_action_set_group (action, radio_group);
+ if (radio_group)
+ gtk_radio_action_set_group (action, radio_group);
+ else
+ g_signal_connect (
+ action, "changed",
+ G_CALLBACK (reformat), extension);
radio_group = gtk_radio_action_get_group (action);
g_object_unref (action);
@@ -246,11 +251,13 @@ create_group (EMailDisplayPopupExtension *extension)
NULL, NULL, action_index);
action_index++;
gtk_action_group_add_action (group, GTK_ACTION (action));
- g_signal_connect (
- action, "changed",
- G_CALLBACK (reformat), extension);
- gtk_radio_action_set_group (action, radio_group);
+ if (radio_group)
+ gtk_radio_action_set_group (action, radio_group);
+ else
+ g_signal_connect (
+ action, "changed",
+ G_CALLBACK (reformat), extension);
radio_group = gtk_radio_action_get_group (action);
g_object_unref (action);
@@ -273,33 +280,26 @@ create_group (EMailDisplayPopupExtension *extension)
static void
update_actions (EMailDisplayPopupExtension *extension,
- WebKitHitTestResult *context)
+ const gchar *popup_document_uri)
{
EMailDisplayPopupTextHighlight *th_extension;
- WebKitDOMNode *node;
- WebKitDOMDocument *document;
- gchar *uri;
th_extension = E_MAIL_DISPLAY_POPUP_TEXT_HIGHLIGHT (extension);
- if (th_extension->action_group == NULL) {
+ if (!th_extension->action_group)
th_extension->action_group = create_group (extension);
- }
- th_extension->document = NULL;
- g_object_get (G_OBJECT (context), "inner-node", &node, NULL);
- document = webkit_dom_node_get_owner_document (node);
- uri = webkit_dom_document_get_document_uri (document);
+ set_document_uri (th_extension, popup_document_uri);
/* If the part below context menu was made by text-highlight formatter,
* then try to check what formatter it's using at the moment and set
* it as active in the popup menu */
- if (uri && strstr (uri, ".text-highlight") != NULL) {
+ if (th_extension->document_uri && strstr (th_extension->document_uri, ".text-highlight") != NULL) {
SoupURI *soup_uri;
gtk_action_group_set_visible (
th_extension->action_group, TRUE);
- soup_uri = soup_uri_new (uri);
+ soup_uri = soup_uri_new (th_extension->document_uri);
if (soup_uri && soup_uri->query) {
GHashTable *query = soup_form_decode (soup_uri->query);
gchar *highlighter;
@@ -310,31 +310,23 @@ update_actions (EMailDisplayPopupExtension *extension,
th_extension->action_group, highlighter);
if (action) {
gint value;
+ g_atomic_int_add (&th_extension->updating, 1);
g_object_get (
G_OBJECT (action), "value",
&value, NULL);
gtk_radio_action_set_current_value (
GTK_RADIO_ACTION (action), value);
+ g_atomic_int_add (&th_extension->updating, -1);
}
}
g_hash_table_destroy (query);
}
- if (soup_uri) {
+ if (soup_uri)
soup_uri_free (soup_uri);
- }
-
} else {
- gtk_action_group_set_visible (
- th_extension->action_group, FALSE);
+ gtk_action_group_set_visible (th_extension->action_group, FALSE);
}
-
- /* Set the th_extension->document AFTER changing the active action to
- * prevent the reformat() from doing some crazy reformatting
- * (reformat() returns immediatelly when th_extension->document is NULL) */
- th_extension->document = document;
-
- g_free (uri);
}
void
@@ -363,11 +355,11 @@ e_mail_display_popup_extension_interface_init (EMailDisplayPopupExtensionInterfa
void
e_mail_display_popup_text_highlight_class_finalize (EMailDisplayPopupTextHighlightClass *klass)
{
-
}
static void
e_mail_display_popup_text_highlight_init (EMailDisplayPopupTextHighlight *extension)
{
extension->action_group = NULL;
+ extension->document_uri = NULL;
}
diff --git a/modules/vcard-inline/e-mail-formatter-vcard.c b/modules/vcard-inline/e-mail-formatter-vcard.c
index f13d677..40e573c 100644
--- a/modules/vcard-inline/e-mail-formatter-vcard.c
+++ b/modules/vcard-inline/e-mail-formatter-vcard.c
@@ -146,9 +146,12 @@ mail_formatter_vcard_format (EMailFormatterExtension *extension,
str = g_strdup_printf (
"<button type=\"button\" "
"name=\"set-display-mode\" "
+ "id=\"%s\" "
"class=\"org-gnome-vcard-display-mode-button\" "
"value=\"%d\" "
+ "style=\"margin-left: 0px\""
"accesskey=\"%s\">%s</button>",
+ e_mail_part_get_id (part),
mode, access_key, html_label);
g_output_stream_write_all (
stream, str, strlen (str), NULL, cancellable, NULL);
@@ -166,8 +169,10 @@ mail_formatter_vcard_format (EMailFormatterExtension *extension,
"class=\"org-gnome-vcard-save-button\" "
"value=\"%s\" "
"accesskey=\"%s\">%s</button><br>"
- "<iframe width=\"100%%\" height=\"auto\" frameborder=\"0\""
- "src=\"%s\" name=\"%s\"></iframe>"
+ "<iframe width=\"100%%\" height=\"auto\" "
+ " class=\"-e-mail-formatter-frame-color -e-web-view-background-color\" "
+ " style=\"border: 1px solid;\""
+ " src=\"%s\" name=\"%s\"></iframe>"
"</div>",
e_mail_part_get_id (part),
access_key, html_label, uri,
diff --git a/modules/vcard-inline/e-mail-part-vcard.c b/modules/vcard-inline/e-mail-part-vcard.c
index f164ab6..f5729a6 100644
--- a/modules/vcard-inline/e-mail-part-vcard.c
+++ b/modules/vcard-inline/e-mail-part-vcard.c
@@ -32,6 +32,12 @@
struct _EMailPartVCardPrivate {
gint placeholder;
+
+ guint display_mode_toggled_signal_id;
+ guint save_vcard_button_pressed_signal_id;
+
+ GDBusProxy *web_extension;
+ guint64 page_id;
};
G_DEFINE_DYNAMIC_TYPE (
@@ -85,8 +91,12 @@ client_connect_cb (GObject *source_object,
}
static void
-save_vcard_cb (WebKitDOMEventTarget *button,
- WebKitDOMEvent *event,
+save_vcard_cb (GDBusConnection *connection,
+ const gchar *sender_name,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *signal_name,
+ GVariant *parameters,
EMailPartVCard *vcard_part)
{
EShell *shell;
@@ -94,9 +104,19 @@ save_vcard_cb (WebKitDOMEventTarget *button,
ESourceRegistry *registry;
ESourceSelector *selector;
GSList *contact_list;
- const gchar *extension_name;
+ const gchar *extension_name, *button_value, *part_id;
GtkWidget *dialog;
+ if (g_strcmp0 (signal_name, "VCardInlineSaveButtonPressed") != 0)
+ return;
+
+ g_variant_get (parameters, "(&s)", &button_value);
+
+ part_id = e_mail_part_get_id (E_MAIL_PART (vcard_part));
+
+ if (!strstr (part_id, button_value))
+ return;
+
shell = e_shell_get_default ();
registry = e_shell_get_registry (shell);
extension_name = E_SOURCE_EXTENSION_ADDRESS_BOOK;
@@ -131,8 +151,12 @@ save_vcard_cb (WebKitDOMEventTarget *button,
}
static void
-display_mode_toggle_cb (WebKitDOMEventTarget *button,
- WebKitDOMEvent *event,
+display_mode_toggle_cb (GDBusConnection *connection,
+ const gchar *sender_name,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *signal_name,
+ GVariant *parameters,
EMailPartVCard *vcard_part)
{
EABContactDisplayMode mode;
@@ -140,47 +164,54 @@ display_mode_toggle_cb (WebKitDOMEventTarget *button,
gchar *html_label;
gchar *access_key;
const gchar *part_id;
+ const gchar *button_id;
+
+ if (g_strcmp0 (signal_name, "VCardInlineDisplayModeToggled") != 0)
+ return;
+
+ if (!vcard_part->priv->web_extension)
+ return;
+
+ g_variant_get (parameters, "(&s)", &button_id);
part_id = e_mail_part_get_id (E_MAIL_PART (vcard_part));
+ if (!strstr (part_id, button_id))
+ return;
+
mode = eab_contact_formatter_get_display_mode (vcard_part->formatter);
if (mode == EAB_CONTACT_DISPLAY_RENDER_NORMAL) {
mode = EAB_CONTACT_DISPLAY_RENDER_COMPACT;
html_label = e_mail_formatter_parse_html_mnemonics (
_("Show F_ull vCard"), &access_key);
-
- webkit_dom_html_element_set_inner_html (
- WEBKIT_DOM_HTML_ELEMENT (button),
- html_label, NULL);
- if (access_key) {
- webkit_dom_html_element_set_access_key (
- WEBKIT_DOM_HTML_ELEMENT (button),
- access_key);
- g_free (access_key);
- }
-
- g_free (html_label);
-
} else {
mode = EAB_CONTACT_DISPLAY_RENDER_NORMAL;
html_label = e_mail_formatter_parse_html_mnemonics (
_("Show Com_pact vCard"), &access_key);
-
- webkit_dom_html_element_set_inner_html (
- WEBKIT_DOM_HTML_ELEMENT (button),
- html_label, NULL);
- if (access_key) {
- webkit_dom_html_element_set_access_key (
- WEBKIT_DOM_HTML_ELEMENT (button),
- access_key);
- g_free (access_key);
- }
-
- g_free (html_label);
}
+ g_dbus_proxy_call (
+ vcard_part->priv->web_extension,
+ "VCardInlineUpdateButton",
+ g_variant_new (
+ "(tsss)",
+ vcard_part->priv->page_id,
+ button_id,
+ html_label,
+ access_key),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+
+ if (access_key)
+ g_free (access_key);
+
+ g_free (html_label);
+
eab_contact_formatter_set_display_mode (vcard_part->formatter, mode);
uri = e_mail_part_build_uri (
@@ -188,8 +219,19 @@ display_mode_toggle_cb (WebKitDOMEventTarget *button,
"part_id", G_TYPE_STRING, part_id,
"mode", G_TYPE_INT, E_MAIL_FORMATTER_MODE_RAW, NULL);
- webkit_dom_html_iframe_element_set_src (
- WEBKIT_DOM_HTML_IFRAME_ELEMENT (vcard_part->iframe), uri);
+ g_dbus_proxy_call (
+ vcard_part->priv->web_extension,
+ "VCardInlineSetIFrameSrc",
+ g_variant_new (
+ "(tss)",
+ vcard_part->priv->page_id,
+ button_id,
+ uri),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
g_free (uri);
}
@@ -202,11 +244,22 @@ mail_part_vcard_dispose (GObject *object)
g_clear_object (&part->contact_display);
g_clear_object (&part->message_label);
g_clear_object (&part->formatter);
- g_clear_object (&part->iframe);
- g_clear_object (&part->save_button);
- g_clear_object (&part->toggle_button);
g_clear_object (&part->folder);
+ if (part->priv->display_mode_toggled_signal_id > 0) {
+ g_dbus_connection_signal_unsubscribe (
+ g_dbus_proxy_get_connection (part->priv->web_extension),
+ part->priv->display_mode_toggled_signal_id);
+ part->priv->display_mode_toggled_signal_id = 0;
+ }
+
+ if (part->priv->save_vcard_button_pressed_signal_id > 0) {
+ g_dbus_connection_signal_unsubscribe (
+ g_dbus_proxy_get_connection (part->priv->web_extension),
+ part->priv->save_vcard_button_pressed_signal_id);
+ part->priv->save_vcard_button_pressed_signal_id = 0;
+ }
+
/* Chain up to parent's dispose() method. */
G_OBJECT_CLASS (e_mail_part_vcard_parent_class)->dispose (object);
}
@@ -249,66 +302,55 @@ mail_part_vcard_constructed (GObject *object)
static void
mail_part_vcard_bind_dom_element (EMailPart *part,
- WebKitDOMElement *element)
+ GDBusProxy *evolution_web_extension,
+ guint64 page_id,
+ const gchar *element_id)
{
EMailPartVCard *vcard_part;
- WebKitDOMNodeList *list;
- WebKitDOMElement *iframe;
- WebKitDOMElement *toggle_button;
- WebKitDOMElement *save_button;
vcard_part = E_MAIL_PART_VCARD (part);
- /* IFRAME */
- list = webkit_dom_element_get_elements_by_tag_name (
- element, "iframe");
- if (webkit_dom_node_list_get_length (list) != 1) {
- g_object_unref (list);
- return;
- }
- iframe = WEBKIT_DOM_ELEMENT (webkit_dom_node_list_item (list, 0));
- g_clear_object (&vcard_part->iframe);
- vcard_part->iframe = iframe;
- g_object_unref (list);
-
- /* TOGGLE DISPLAY MODE BUTTON */
- list = webkit_dom_element_get_elements_by_class_name (
- element, "org-gnome-vcard-display-mode-button");
- if (webkit_dom_node_list_get_length (list) != 1) {
- g_object_unref (list);
- return;
- }
- toggle_button = WEBKIT_DOM_ELEMENT (webkit_dom_node_list_item (list, 0));
- g_clear_object (&vcard_part->toggle_button);
- vcard_part->toggle_button = toggle_button;
- g_object_unref (list);
-
- /* SAVE TO ADDRESSBOOK BUTTON */
- list = webkit_dom_element_get_elements_by_class_name (
- element, "org-gnome-vcard-save-button");
- if (webkit_dom_node_list_get_length (list) != 1) {
- g_object_unref (list);
- return;
- }
- save_button = WEBKIT_DOM_ELEMENT (webkit_dom_node_list_item (list, 0));
- g_clear_object (&vcard_part->save_button);
- vcard_part->save_button = save_button;
- g_object_unref (list);
-
- webkit_dom_event_target_add_event_listener (
- WEBKIT_DOM_EVENT_TARGET (toggle_button),
- "click", G_CALLBACK (display_mode_toggle_cb),
- FALSE, vcard_part);
-
- webkit_dom_event_target_add_event_listener (
- WEBKIT_DOM_EVENT_TARGET (save_button),
- "click", G_CALLBACK (save_vcard_cb),
- FALSE, vcard_part);
-
- /* Bind collapse buttons for contact lists. */
- eab_contact_formatter_bind_dom (
- webkit_dom_html_iframe_element_get_content_document (
- WEBKIT_DOM_HTML_IFRAME_ELEMENT (iframe)));
+ vcard_part->priv->web_extension = evolution_web_extension;
+ vcard_part->priv->page_id = page_id;
+
+ vcard_part->priv->display_mode_toggled_signal_id =
+ g_dbus_connection_signal_subscribe (
+ g_dbus_proxy_get_connection (evolution_web_extension),
+ g_dbus_proxy_get_name (evolution_web_extension),
+ g_dbus_proxy_get_interface_name (evolution_web_extension),
+ "VCardInlineDisplayModeToggled",
+ g_dbus_proxy_get_object_path (evolution_web_extension),
+ NULL,
+ G_DBUS_SIGNAL_FLAGS_NONE,
+ (GDBusSignalCallback) display_mode_toggle_cb,
+ vcard_part,
+ NULL);
+
+ vcard_part->priv->save_vcard_button_pressed_signal_id =
+ g_dbus_connection_signal_subscribe (
+ g_dbus_proxy_get_connection (evolution_web_extension),
+ g_dbus_proxy_get_name (evolution_web_extension),
+ g_dbus_proxy_get_interface_name (evolution_web_extension),
+ "VCardInlineSaveButtonPressed",
+ g_dbus_proxy_get_object_path (evolution_web_extension),
+ NULL,
+ G_DBUS_SIGNAL_FLAGS_NONE,
+ (GDBusSignalCallback) save_vcard_cb,
+ vcard_part,
+ NULL);
+
+ g_dbus_proxy_call (
+ vcard_part->priv->web_extension,
+ "VCardInlineBindDOM",
+ g_variant_new (
+ "(ts)",
+ vcard_part->priv->page_id,
+ element_id),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
}
static void
diff --git a/modules/vcard-inline/e-mail-part-vcard.h b/modules/vcard-inline/e-mail-part-vcard.h
index d9409c5..9aeb595 100644
--- a/modules/vcard-inline/e-mail-part-vcard.h
+++ b/modules/vcard-inline/e-mail-part-vcard.h
@@ -21,7 +21,6 @@
#include <em-format/e-mail-part.h>
#include <addressbook/gui/widgets/eab-contact-formatter.h>
-#include <webkit/webkitdom.h>
/* Standard GObject macros */
#define E_TYPE_MAIL_PART_VCARD \
@@ -57,9 +56,6 @@ struct _EMailPartVCard {
GtkWidget *message_label;
EABContactFormatter *formatter;
- WebKitDOMElement *iframe;
- WebKitDOMElement *toggle_button;
- WebKitDOMElement *save_button;
CamelFolder *folder;
gchar *message_uid;
diff --git a/modules/webkit-editor/Makefile.am b/modules/webkit-editor/Makefile.am
new file mode 100644
index 0000000..1844797
--- /dev/null
+++ b/modules/webkit-editor/Makefile.am
@@ -0,0 +1,31 @@
+SUBDIRS = . web-extension
+
+module_LTLIBRARIES = module-webkit-editor.la
+
+module_webkit_editor_la_CPPFLAGS = \
+ $(AM_CPPFLAGS) \
+ -I$(top_srcdir) \
+ -DEVOLUTION_WEB_EXTENSIONS_WEBKIT_EDITOR_DIR=\""$(webextensionswebkiteditordir)"\" \
+ -DG_LOG_DOMAIN=\"webkit-editor\" \
+ $(EVOLUTION_DATA_SERVER_CFLAGS) \
+ $(GNOME_PLATFORM_CFLAGS) \
+ $(CODE_COVERAGE_CFLAGS) \
+ $(NULL)
+
+module_webkit_editor_la_SOURCES = \
+ evolution-module-webkit-editor.c \
+ e-webkit-editor-extension.c \
+ e-webkit-editor-extension.h \
+ e-webkit-editor.c \
+ e-webkit-editor.h
+
+module_webkit_editor_la_LIBADD = \
+ $(top_builddir)/e-util/libevolution-util.la \
+ $(EVOLUTION_DATA_SERVER_LIBS) \
+ $(GNOME_PLATFORM_LIBS) \
+ $(NULL)
+
+module_webkit_editor_la_LDFLAGS = \
+ -module -avoid-version $(NO_UNDEFINED) $(CODE_COVERAGE_LDFLAGS)
+
+-include $(top_srcdir)/git.mk
diff --git a/modules/webkit-editor/e-webkit-editor-extension.c
b/modules/webkit-editor/e-webkit-editor-extension.c
new file mode 100644
index 0000000..e05ee20
--- /dev/null
+++ b/modules/webkit-editor/e-webkit-editor-extension.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2016 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library 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.
+ *
+ * This library 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 this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-webkit-editor-extension.h"
+#include "e-webkit-editor.h"
+
+#include <e-util/e-util.h>
+
+#define E_WEBKIT_EDITOR_EXTENSION_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_WEBKIT_EDITOR_EXTENSION, EWebKitEditorExtensionPrivate))
+
+struct _EWebKitEditorExtensionPrivate {
+ EWebKitEditor *wk_editor;
+};
+
+G_DEFINE_DYNAMIC_TYPE (
+ EWebKitEditorExtension,
+ e_webkit_editor_extension,
+ E_TYPE_EXTENSION)
+
+static void
+e_webkit_editor_extension_init (EWebKitEditorExtension *editor_extension)
+{
+ editor_extension->priv = E_WEBKIT_EDITOR_EXTENSION_GET_PRIVATE (editor_extension);
+
+ editor_extension->priv->wk_editor = g_object_ref_sink (e_webkit_editor_new ());
+}
+
+static void
+webkit_editor_extension_constructed (GObject *object)
+{
+ EWebKitEditorExtensionPrivate *priv;
+ EExtensible *extensible;
+
+ /* Chain up to parent's constructed() method. */
+ G_OBJECT_CLASS (e_webkit_editor_extension_parent_class)->constructed (object);
+
+ priv = E_WEBKIT_EDITOR_EXTENSION_GET_PRIVATE (object);
+ extensible = e_extension_get_extensible (E_EXTENSION (object));
+
+ e_html_editor_register_content_editor (E_HTML_EDITOR (extensible),
+ DEFAULT_CONTENT_EDITOR_NAME, E_CONTENT_EDITOR (priv->wk_editor));
+}
+
+static void
+webkit_editor_extension_dispose (GObject *object)
+{
+ EWebKitEditorExtensionPrivate *priv;
+
+ priv = E_WEBKIT_EDITOR_EXTENSION_GET_PRIVATE (object);
+
+ g_clear_object (&priv->wk_editor);
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (e_webkit_editor_extension_parent_class)->dispose (object);
+}
+
+static void
+e_webkit_editor_extension_class_init (EWebKitEditorExtensionClass *class)
+{
+ EExtensionClass *extension_class;
+ GObjectClass *object_class;
+
+ g_type_class_add_private (class, sizeof (EWebKitEditorExtensionPrivate));
+
+ extension_class = E_EXTENSION_CLASS (class);
+ extension_class->extensible_type = E_TYPE_HTML_EDITOR;
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->dispose = webkit_editor_extension_dispose;
+ object_class->constructed = webkit_editor_extension_constructed;
+}
+
+static void
+e_webkit_editor_extension_class_finalize (EWebKitEditorExtensionClass *class)
+{
+}
+
+void
+e_webkit_editor_extension_type_register (GTypeModule *type_module)
+{
+ e_webkit_editor_extension_register_type (type_module);
+}
diff --git a/modules/webkit-editor/e-webkit-editor-extension.h
b/modules/webkit-editor/e-webkit-editor-extension.h
new file mode 100644
index 0000000..ff5d781
--- /dev/null
+++ b/modules/webkit-editor/e-webkit-editor-extension.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2016 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library 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.
+ *
+ * This library 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 this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef E_WEBKIT_EDITOR_EXTENSION_H
+#define E_WEBKIT_EDITOR_EXTENSION_H
+
+#include <libebackend/libebackend.h>
+
+/* Standard GObject macros */
+#define E_TYPE_WEBKIT_EDITOR_EXTENSION \
+ (e_webkit_editor_extension_get_type ())
+#define E_WEBKIT_EDITOR_EXTENSION(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_WEBKIT_EDITOR_EXTENSION, EWebKitEditorExtension))
+#define E_WEBKIT_EDITOR_EXTENSION_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_WEBKIT_EDITOR_EXTENSION, EWebKitEditorExtensionClass))
+#define E_IS_WEBKIT_EDITOR_EXTENSION(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_WEBKIT_EDITOR_EXTENSION))
+#define E_IS_WEBKIT_EDITOR_EXTENSION_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_WEBKIT_EDITOR_EXTENSION))
+#define E_WEBKIT_EDITOR_EXTENSION_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_WEBKIT_EDITOR_EXTENSION, EWebKitEditorExtensionClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EWebKitEditorExtension EWebKitEditorExtension;
+typedef struct _EWebKitEditorExtensionClass EWebKitEditorExtensionClass;
+typedef struct _EWebKitEditorExtensionPrivate EWebKitEditorExtensionPrivate;
+
+struct _EWebKitEditorExtension {
+ EExtension parent;
+
+ EWebKitEditorExtensionPrivate *priv;
+};
+
+struct _EWebKitEditorExtensionClass {
+ EExtensionClass parent_class;
+};
+
+GType e_webkit_editor_extension_get_type (void) G_GNUC_CONST;
+void e_webkit_editor_extension_type_register (GTypeModule *type_module);
+
+G_END_DECLS
+
+#endif /* E_WEBKIT_EDITOR_EXTENSION_H */
diff --git a/modules/webkit-editor/e-webkit-editor.c b/modules/webkit-editor/e-webkit-editor.c
new file mode 100644
index 0000000..c984a57
--- /dev/null
+++ b/modules/webkit-editor/e-webkit-editor.c
@@ -0,0 +1,6291 @@
+/*
+ * Copyright (C) 2016 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library 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.
+ *
+ * This library 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 this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-webkit-editor.h"
+
+#include "web-extension/e-editor-web-extension-names.h"
+
+#include <e-util/e-util.h>
+#include <string.h>
+
+#define E_WEBKIT_EDITOR_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_WEBKIT_EDITOR, EWebKitEditorPrivate))
+
+/* FIXME WK2 Move to e-content-editor? */
+#define UNICODE_NBSP "\xc2\xa0"
+#define SPACES_PER_LIST_LEVEL 3
+#define SPACES_ORDERED_LIST_FIRST_LEVEL 6
+
+enum {
+ PROP_0,
+ PROP_WEB_EXTENSION, /* for test purposes */
+ PROP_CAN_COPY,
+ PROP_CAN_CUT,
+ PROP_CAN_PASTE,
+ PROP_CAN_REDO,
+ PROP_CAN_UNDO,
+ PROP_CHANGED,
+ PROP_EDITABLE,
+ PROP_HTML_MODE,
+ PROP_SPELL_CHECK_ENABLED,
+ PROP_SPELL_CHECKER,
+
+ PROP_ALIGNMENT,
+ PROP_BACKGROUND_COLOR,
+ PROP_BLOCK_FORMAT,
+ PROP_BOLD,
+ PROP_FONT_COLOR,
+ PROP_FONT_NAME,
+ PROP_FONT_SIZE,
+ PROP_INDENTED,
+ PROP_ITALIC,
+ PROP_MONOSPACED,
+ PROP_STRIKETHROUGH,
+ PROP_SUBSCRIPT,
+ PROP_SUPERSCRIPT,
+ PROP_UNDERLINE
+};
+
+struct _EWebKitEditorPrivate {
+ EContentEditorInitializedCallback initialized_callback;
+ gpointer initialized_user_data;
+
+ GDBusProxy *web_extension;
+ guint web_extension_watch_name_id;
+ guint web_extension_selection_changed_cb_id;
+ guint web_extension_content_changed_cb_id;
+ guint web_extension_undo_redo_state_changed_cb_id;
+
+ gboolean html_mode;
+ gboolean changed;
+ gboolean can_copy;
+ gboolean can_cut;
+ gboolean can_paste;
+ gboolean can_undo;
+ gboolean can_redo;
+
+ gboolean emit_load_finished_when_extension_is_ready;
+ gboolean reload_in_progress;
+ gboolean copy_paste_clipboard_in_view;
+ gboolean copy_paste_primary_in_view;
+ gboolean copy_cut_actions_triggered;
+ gboolean pasting_primary_clipboard;
+ gboolean pasting_from_itself_extension_value;
+
+ guint32 style_flags;
+ gboolean is_indented;
+
+ GdkRGBA *background_color;
+ GdkRGBA *font_color;
+
+ gchar *font_name;
+
+ guint font_size;
+
+ EContentEditorBlockFormat block_format;
+ EContentEditorAlignment alignment;
+
+ gchar *current_user_stylesheet;
+
+ WebKitLoadEvent webkit_load_event;
+
+ GQueue *post_reload_operations;
+
+ GSettings *mail_settings;
+ GSettings *font_settings;
+ GSettings *aliasing_settings;
+
+ GHashTable *old_settings;
+
+ ESpellChecker *spell_checker;
+ gboolean spell_check_enabled;
+
+ gulong owner_change_primary_clipboard_cb_id;
+ gulong owner_change_clipboard_cb_id;
+
+ WebKitFindController *find_controller; /* not referenced; set to non-NULL only if the search is in
progress */
+ gboolean performing_replace_all;
+ guint replaced_count;
+ gchar *replace_with;
+ gulong found_text_handler_id;
+ gulong failed_to_find_text_handler_id;
+};
+
+static const GdkRGBA black = { 0, 0, 0, 1 };
+static const GdkRGBA white = { 1, 1, 1, 1 };
+static const GdkRGBA transparent = { 0, 0, 0, 0 };
+
+typedef void (*PostReloadOperationFunc) (EWebKitEditor *wk_editor, gpointer data,
EContentEditorInsertContentFlags flags);
+
+typedef struct {
+ PostReloadOperationFunc func;
+ EContentEditorInsertContentFlags flags;
+ gpointer data;
+ GDestroyNotify data_free_func;
+} PostReloadOperation;
+
+static void e_webkit_editor_content_editor_init (EContentEditorInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (
+ EWebKitEditor,
+ e_webkit_editor,
+ WEBKIT_TYPE_WEB_VIEW,
+ G_IMPLEMENT_INTERFACE (
+ E_TYPE_CONTENT_EDITOR,
+ e_webkit_editor_content_editor_init));
+
+EWebKitEditor *
+e_webkit_editor_new (void)
+{
+ return g_object_new (E_TYPE_WEBKIT_EDITOR, NULL);
+}
+
+static void
+webkit_editor_can_paste_cb (WebKitWebView *view,
+ GAsyncResult *result,
+ EWebKitEditor *wk_editor)
+{
+ gboolean value;
+
+ value = webkit_web_view_can_execute_editing_command_finish (view, result, NULL);
+
+ if (wk_editor->priv->can_paste != value) {
+ wk_editor->priv->can_paste = value;
+ g_object_notify (G_OBJECT (wk_editor), "can-paste");
+ }
+}
+
+static gboolean
+webkit_editor_can_paste (EWebKitEditor *wk_editor)
+{
+ g_return_val_if_fail (E_IS_WEBKIT_EDITOR (wk_editor), FALSE);
+
+ return wk_editor->priv->can_paste;
+}
+
+static void
+webkit_editor_can_cut_cb (WebKitWebView *view,
+ GAsyncResult *result,
+ EWebKitEditor *wk_editor)
+{
+ gboolean value;
+
+ value = webkit_web_view_can_execute_editing_command_finish (view, result, NULL);
+
+ if (wk_editor->priv->can_cut != value) {
+ wk_editor->priv->can_cut = value;
+ g_object_notify (G_OBJECT (wk_editor), "can-cut");
+ }
+}
+
+static gboolean
+webkit_editor_can_cut (EWebKitEditor *wk_editor)
+{
+ g_return_val_if_fail (E_IS_WEBKIT_EDITOR (wk_editor), FALSE);
+
+ return wk_editor->priv->can_cut;
+}
+
+static void
+webkit_editor_can_copy_cb (WebKitWebView *view,
+ GAsyncResult *result,
+ EWebKitEditor *wk_editor)
+{
+ gboolean value;
+
+ value = webkit_web_view_can_execute_editing_command_finish (view, result, NULL);
+
+ if (wk_editor->priv->can_copy != value) {
+ wk_editor->priv->can_copy = value;
+ /* This means that we have an active selection thus the primary
+ * clipboard content is from composer. */
+ if (value)
+ wk_editor->priv->copy_paste_primary_in_view = TRUE;
+ /* FIXME notify web extension about pasting content from itself */
+ g_object_notify (G_OBJECT (wk_editor), "can-copy");
+ }
+}
+
+static gboolean
+webkit_editor_can_copy (EWebKitEditor *wk_editor)
+{
+ g_return_val_if_fail (E_IS_WEBKIT_EDITOR (wk_editor), FALSE);
+
+ return wk_editor->priv->can_copy;
+}
+
+static gboolean
+webkit_editor_get_changed (EWebKitEditor *wk_editor)
+{
+ g_return_val_if_fail (E_IS_WEBKIT_EDITOR (wk_editor), FALSE);
+
+ return wk_editor->priv->changed;
+}
+
+static void
+webkit_editor_set_changed (EWebKitEditor *wk_editor,
+ gboolean changed)
+{
+ g_return_if_fail (E_IS_WEBKIT_EDITOR (wk_editor));
+
+ if (wk_editor->priv->changed == changed)
+ return;
+
+ wk_editor->priv->changed = changed;
+
+ g_object_notify (G_OBJECT (wk_editor), "changed");
+}
+
+static void
+webkit_editor_set_can_undo (EWebKitEditor *wk_editor,
+ gboolean can_undo)
+{
+ g_return_if_fail (E_IS_WEBKIT_EDITOR (wk_editor));
+
+ if ((wk_editor->priv->can_undo ? 1 : 0) == (can_undo ? 1 : 0))
+ return;
+
+ wk_editor->priv->can_undo = can_undo;
+
+ g_object_notify (G_OBJECT (wk_editor), "can-undo");
+}
+
+static void
+webkit_editor_set_can_redo (EWebKitEditor *wk_editor,
+ gboolean can_redo)
+{
+ g_return_if_fail (E_IS_WEBKIT_EDITOR (wk_editor));
+
+ if ((wk_editor->priv->can_redo ? 1 : 0) == (can_redo ? 1 : 0))
+ return;
+
+ wk_editor->priv->can_redo = can_redo;
+
+ g_object_notify (G_OBJECT (wk_editor), "can-redo");
+}
+
+static void
+web_extension_content_changed_cb (GDBusConnection *connection,
+ const gchar *sender_name,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *signal_name,
+ GVariant *parameters,
+ EWebKitEditor *wk_editor)
+{
+ if (g_strcmp0 (signal_name, "ContentChanged") != 0)
+ return;
+
+ if (parameters) {
+ guint64 page_id = 0;
+
+ g_variant_get (parameters, "(t)", &page_id);
+
+ if (page_id == webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (wk_editor)))
+ webkit_editor_set_changed (wk_editor, TRUE);
+ }
+}
+
+static void
+web_extension_selection_changed_cb (GDBusConnection *connection,
+ const gchar *sender_name,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *signal_name,
+ GVariant *parameters,
+ EWebKitEditor *wk_editor)
+{
+ guint64 page_id = 0;
+ gchar *font_color = NULL;
+ guint32 alignment, block_format, style_flags, font_size;
+ gboolean is_indented;
+
+ if (g_strcmp0 (signal_name, "SelectionChanged") != 0)
+ return;
+
+ if (!parameters)
+ return;
+
+ g_variant_get (
+ parameters,
+ "(tiibiis)",
+ &page_id,
+ &alignment,
+ &block_format,
+ &is_indented,
+ &style_flags,
+ &font_size,
+ &font_color);
+
+ if (page_id != webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (wk_editor))) {
+ g_free (font_color);
+ return;
+ }
+
+ webkit_web_view_can_execute_editing_command (
+ WEBKIT_WEB_VIEW (wk_editor),
+ WEBKIT_EDITING_COMMAND_COPY,
+ NULL, /* cancellable */
+ (GAsyncReadyCallback) webkit_editor_can_copy_cb,
+ wk_editor);
+
+ webkit_web_view_can_execute_editing_command (
+ WEBKIT_WEB_VIEW (wk_editor),
+ WEBKIT_EDITING_COMMAND_CUT,
+ NULL, /* cancellable */
+ (GAsyncReadyCallback) webkit_editor_can_cut_cb,
+ wk_editor);
+
+ webkit_web_view_can_execute_editing_command (
+ WEBKIT_WEB_VIEW (wk_editor),
+ WEBKIT_EDITING_COMMAND_PASTE,
+ NULL, /* cancellable */
+ (GAsyncReadyCallback) webkit_editor_can_paste_cb,
+ wk_editor);
+
+ g_object_freeze_notify (G_OBJECT (wk_editor));
+
+ wk_editor->priv->alignment = alignment;
+ wk_editor->priv->block_format = block_format;
+ wk_editor->priv->is_indented = is_indented;
+ wk_editor->priv->style_flags = style_flags;
+ wk_editor->priv->font_size = font_size;
+
+ if (wk_editor->priv->html_mode) {
+ GdkRGBA color;
+
+ if (font_color && *font_color && gdk_rgba_parse (&color, font_color)) {
+ if (wk_editor->priv->font_color)
+ gdk_rgba_free (wk_editor->priv->font_color);
+ wk_editor->priv->font_color = gdk_rgba_copy (&color);
+ }
+ }
+ g_free (font_color);
+
+ g_object_notify (G_OBJECT (wk_editor), "alignment");
+ g_object_notify (G_OBJECT (wk_editor), "block-format");
+ g_object_notify (G_OBJECT (wk_editor), "indented");
+
+ if (wk_editor->priv->html_mode) {
+ /* g_object_notify (G_OBJECT (wk_editor), "background-color"); */
+ g_object_notify (G_OBJECT (wk_editor), "bold");
+ /* g_object_notify (G_OBJECT (wk_editor), "font-name"); */
+ g_object_notify (G_OBJECT (wk_editor), "font-size");
+ g_object_notify (G_OBJECT (wk_editor), "font-color");
+ g_object_notify (G_OBJECT (wk_editor), "italic");
+ g_object_notify (G_OBJECT (wk_editor), "monospaced");
+ g_object_notify (G_OBJECT (wk_editor), "strikethrough");
+ g_object_notify (G_OBJECT (wk_editor), "subscript");
+ g_object_notify (G_OBJECT (wk_editor), "superscript");
+ g_object_notify (G_OBJECT (wk_editor), "underline");
+ }
+
+ g_object_thaw_notify (G_OBJECT (wk_editor));
+}
+
+static void
+web_extension_undo_redo_state_changed_cb (GDBusConnection *connection,
+ const gchar *sender_name,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *signal_name,
+ GVariant *parameters,
+ EWebKitEditor *wk_editor)
+{
+ guint64 page_id = 0;
+ gboolean can_undo = FALSE, can_redo = FALSE;
+
+ if (g_strcmp0 (signal_name, "UndoRedoStateChanged") != 0)
+ return;
+
+ g_variant_get (parameters, "(tbb)", &page_id, &can_undo, &can_redo);
+
+ if (page_id == webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (wk_editor))) {
+ webkit_editor_set_can_undo (wk_editor, can_undo);
+ webkit_editor_set_can_redo (wk_editor, can_redo);
+ }
+}
+
+static void
+dispatch_pending_operations (EWebKitEditor *wk_editor)
+{
+ if (wk_editor->priv->webkit_load_event != WEBKIT_LOAD_FINISHED ||
+ !wk_editor->priv->web_extension)
+ return;
+
+ /* Dispatch queued operations - as we are using this just for load
+ * operations load just the latest request and throw away the rest. */
+ if (wk_editor->priv->post_reload_operations &&
+ !g_queue_is_empty (wk_editor->priv->post_reload_operations)) {
+
+ PostReloadOperation *op;
+
+ op = g_queue_pop_head (wk_editor->priv->post_reload_operations);
+
+ op->func (wk_editor, op->data, op->flags);
+
+ if (op->data_free_func)
+ op->data_free_func (op->data);
+ g_free (op);
+
+ while ((op = g_queue_pop_head (wk_editor->priv->post_reload_operations))) {
+ if (op->data_free_func)
+ op->data_free_func (op->data);
+ g_free (op);
+ }
+
+ g_queue_clear (wk_editor->priv->post_reload_operations);
+ }
+}
+
+static void
+web_extension_proxy_created_cb (GDBusProxy *proxy,
+ GAsyncResult *result,
+ EWebKitEditor *wk_editor)
+{
+ GError *error = NULL;
+
+ wk_editor->priv->web_extension = g_dbus_proxy_new_finish (result, &error);
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("Error creating web extension proxy: %s\n", error->message);
+ g_error_free (error);
+
+ if (wk_editor->priv->initialized_callback) {
+ wk_editor->priv->initialized_callback (E_CONTENT_EDITOR (wk_editor),
wk_editor->priv->initialized_user_data);
+
+ wk_editor->priv->initialized_callback = NULL;
+ wk_editor->priv->initialized_user_data = NULL;
+ }
+
+ return;
+ }
+
+ if (wk_editor->priv->web_extension_selection_changed_cb_id == 0) {
+ wk_editor->priv->web_extension_selection_changed_cb_id =
+ g_dbus_connection_signal_subscribe (
+ g_dbus_proxy_get_connection (wk_editor->priv->web_extension),
+ g_dbus_proxy_get_name (wk_editor->priv->web_extension),
+ E_WEBKIT_EDITOR_WEB_EXTENSION_INTERFACE,
+ "SelectionChanged",
+ E_WEBKIT_EDITOR_WEB_EXTENSION_OBJECT_PATH,
+ NULL,
+ G_DBUS_SIGNAL_FLAGS_NONE,
+ (GDBusSignalCallback) web_extension_selection_changed_cb,
+ wk_editor,
+ NULL);
+ }
+
+ if (wk_editor->priv->web_extension_content_changed_cb_id == 0) {
+ wk_editor->priv->web_extension_content_changed_cb_id =
+ g_dbus_connection_signal_subscribe (
+ g_dbus_proxy_get_connection (wk_editor->priv->web_extension),
+ g_dbus_proxy_get_name (wk_editor->priv->web_extension),
+ E_WEBKIT_EDITOR_WEB_EXTENSION_INTERFACE,
+ "ContentChanged",
+ E_WEBKIT_EDITOR_WEB_EXTENSION_OBJECT_PATH,
+ NULL,
+ G_DBUS_SIGNAL_FLAGS_NONE,
+ (GDBusSignalCallback) web_extension_content_changed_cb,
+ wk_editor,
+ NULL);
+ }
+
+ if (wk_editor->priv->web_extension_undo_redo_state_changed_cb_id == 0) {
+ wk_editor->priv->web_extension_undo_redo_state_changed_cb_id =
+ g_dbus_connection_signal_subscribe (
+ g_dbus_proxy_get_connection (wk_editor->priv->web_extension),
+ g_dbus_proxy_get_name (wk_editor->priv->web_extension),
+ E_WEBKIT_EDITOR_WEB_EXTENSION_INTERFACE,
+ "UndoRedoStateChanged",
+ E_WEBKIT_EDITOR_WEB_EXTENSION_OBJECT_PATH,
+ NULL,
+ G_DBUS_SIGNAL_FLAGS_NONE,
+ (GDBusSignalCallback) web_extension_undo_redo_state_changed_cb,
+ wk_editor,
+ NULL);
+ }
+
+ dispatch_pending_operations (wk_editor);
+
+ if (wk_editor->priv->emit_load_finished_when_extension_is_ready) {
+ e_content_editor_emit_load_finished (E_CONTENT_EDITOR (wk_editor));
+
+ wk_editor->priv->emit_load_finished_when_extension_is_ready = FALSE;
+ }
+
+ g_object_notify (G_OBJECT (wk_editor), "web-extension");
+
+ if (wk_editor->priv->initialized_callback) {
+ wk_editor->priv->initialized_callback (E_CONTENT_EDITOR (wk_editor),
wk_editor->priv->initialized_user_data);
+
+ wk_editor->priv->initialized_callback = NULL;
+ wk_editor->priv->initialized_user_data = NULL;
+ }
+}
+
+static void
+web_extension_appeared_cb (GDBusConnection *connection,
+ const gchar *name,
+ const gchar *name_owner,
+ EWebKitEditor *wk_editor)
+{
+ g_dbus_proxy_new (
+ connection,
+ G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START |
+ G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
+ NULL,
+ name,
+ E_WEBKIT_EDITOR_WEB_EXTENSION_OBJECT_PATH,
+ E_WEBKIT_EDITOR_WEB_EXTENSION_INTERFACE,
+ NULL,
+ (GAsyncReadyCallback) web_extension_proxy_created_cb,
+ wk_editor);
+}
+
+static void
+web_extension_vanished_cb (GDBusConnection *connection,
+ const gchar *name,
+ EWebKitEditor *wk_editor)
+{
+ g_clear_object (&wk_editor->priv->web_extension);
+}
+
+static void
+webkit_editor_watch_web_extension (EWebKitEditor *wk_editor)
+{
+ wk_editor->priv->web_extension_watch_name_id =
+ g_bus_watch_name (
+ G_BUS_TYPE_SESSION,
+ E_WEBKIT_EDITOR_WEB_EXTENSION_SERVICE_NAME,
+ G_BUS_NAME_WATCHER_FLAGS_NONE,
+ (GBusNameAppearedCallback) web_extension_appeared_cb,
+ (GBusNameVanishedCallback) web_extension_vanished_cb,
+ wk_editor,
+ NULL);
+}
+
+static guint64
+current_page_id (EWebKitEditor *wk_editor)
+{
+ return webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (wk_editor));
+}
+
+static void
+sync_wrapper_result_callback (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GAsyncResult **out_async_result = user_data;
+
+ g_return_if_fail (out_async_result != NULL);
+ g_return_if_fail (*out_async_result == NULL);
+
+ *out_async_result = g_object_ref (result);
+}
+
+/* Wraps GDBusProxy synchronous call into an asynchronous without blocking
+ the main context, thus there is no freeze when this is called in the UI
+ process and the WebProcess also does its own IPC call. */
+static GVariant *
+g_dbus_proxy_call_sync_wrapper (GDBusProxy *proxy,
+ const gchar *method_name,
+ GVariant *parameters,
+ GDBusCallFlags flags,
+ gint timeout_msec,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GAsyncResult *async_result = NULL;
+ GVariant *var_result;
+
+ g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), NULL);
+ g_return_val_if_fail (method_name != NULL, NULL);
+
+ g_dbus_proxy_call (
+ proxy, method_name, parameters, flags, timeout_msec, cancellable,
+ sync_wrapper_result_callback, &async_result);
+
+ while (!async_result) {
+ g_main_context_iteration (NULL, TRUE);
+ }
+
+ var_result = g_dbus_proxy_call_finish (proxy, async_result, error);
+
+ g_clear_object (&async_result);
+
+ return var_result;
+}
+
+static void
+webkit_editor_call_simple_extension_function_sync (EWebKitEditor *wk_editor,
+ const gchar *function)
+{
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+ return;
+ }
+
+ g_dbus_proxy_call_sync_wrapper (
+ wk_editor->priv->web_extension,
+ function,
+ g_variant_new ("(t)", current_page_id (wk_editor)),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL);
+}
+
+static void
+webkit_editor_call_simple_extension_function (EWebKitEditor *wk_editor,
+ const gchar *function)
+{
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+ return;
+ }
+
+ g_dbus_proxy_call (
+ wk_editor->priv->web_extension,
+ function,
+ g_variant_new ("(t)", current_page_id (wk_editor)),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+}
+
+static GVariant *
+webkit_editor_get_element_attribute (EWebKitEditor *wk_editor,
+ const gchar *selector,
+ const gchar *attribute)
+{
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+ return NULL;
+ }
+
+ return g_dbus_proxy_call_sync_wrapper (
+ wk_editor->priv->web_extension,
+ "ElementGetAttributeBySelector",
+ g_variant_new ("(tss)", current_page_id (wk_editor), selector, attribute),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL);
+}
+
+static void
+webkit_editor_set_element_attribute (EWebKitEditor *wk_editor,
+ const gchar *selector,
+ const gchar *attribute,
+ const gchar *value)
+{
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+ return;
+ }
+
+ g_dbus_proxy_call (
+ wk_editor->priv->web_extension,
+ "ElementSetAttributeBySelector",
+ g_variant_new (
+ "(tsss)", current_page_id (wk_editor), selector, attribute, value),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+}
+
+static void
+webkit_editor_remove_element_attribute (EWebKitEditor *wk_editor,
+ const gchar *selector,
+ const gchar *attribute)
+{
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+ return;
+ }
+
+ g_dbus_proxy_call (
+ wk_editor->priv->web_extension,
+ "ElementRemoveAttributeBySelector",
+ g_variant_new ("(tss)", current_page_id (wk_editor), selector, attribute),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+}
+
+static void
+webkit_editor_set_format_boolean (EWebKitEditor *wk_editor,
+ const gchar *format_dom_function,
+ gboolean format_value)
+{
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+ return;
+ }
+
+ g_dbus_proxy_call (
+ wk_editor->priv->web_extension,
+ format_dom_function,
+ g_variant_new ("(tb)", current_page_id (wk_editor), format_value),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+}
+
+static void
+webkit_editor_set_format_int (EWebKitEditor *wk_editor,
+ const gchar *format_dom_function,
+ gint32 format_value)
+{
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+ return;
+ }
+
+ g_dbus_proxy_call (
+ wk_editor->priv->web_extension,
+ format_dom_function,
+ g_variant_new ("(ti)", current_page_id (wk_editor), format_value),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+}
+
+static void
+webkit_editor_set_format_string (EWebKitEditor *wk_editor,
+ const gchar *format_name,
+ const gchar *format_dom_function,
+ const gchar *format_value)
+{
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+ return;
+ }
+
+ if (!wk_editor->priv->html_mode)
+ return;
+
+ webkit_editor_set_changed (wk_editor, TRUE);
+
+ g_dbus_proxy_call (
+ wk_editor->priv->web_extension,
+ format_dom_function,
+ g_variant_new ("(ts)", current_page_id (wk_editor), format_value),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+
+ g_object_notify (G_OBJECT (wk_editor), format_name);
+}
+
+static void
+webkit_editor_queue_post_reload_operation (EWebKitEditor *wk_editor,
+ PostReloadOperationFunc func,
+ gpointer data,
+ GDestroyNotify data_free_func,
+ EContentEditorInsertContentFlags flags)
+{
+ PostReloadOperation *op;
+
+ g_return_if_fail (func != NULL);
+
+ if (wk_editor->priv->post_reload_operations == NULL)
+ wk_editor->priv->post_reload_operations = g_queue_new ();
+
+ op = g_new0 (PostReloadOperation, 1);
+ op->func = func;
+ op->flags = flags;
+ op->data = data;
+ op->data_free_func = data_free_func;
+
+ g_queue_push_head (wk_editor->priv->post_reload_operations, op);
+}
+
+static void
+webkit_editor_show_inspector (EWebKitEditor *wk_editor)
+{
+ WebKitWebInspector *inspector;
+
+ g_return_if_fail (E_IS_WEBKIT_EDITOR (wk_editor));
+
+ inspector = webkit_web_view_get_inspector (WEBKIT_WEB_VIEW (wk_editor));
+
+ webkit_web_inspector_show (inspector);
+}
+
+static void
+webkit_editor_initialize (EContentEditor *content_editor,
+ EContentEditorInitializedCallback callback,
+ gpointer user_data)
+{
+ EWebKitEditor *wk_editor;
+
+ g_return_if_fail (E_IS_WEBKIT_EDITOR (content_editor));
+ g_return_if_fail (callback != NULL);
+
+ wk_editor = E_WEBKIT_EDITOR (content_editor);
+
+ if (wk_editor->priv->web_extension) {
+ callback (content_editor, user_data);
+ } else {
+ g_return_if_fail (wk_editor->priv->initialized_callback == NULL);
+
+ wk_editor->priv->initialized_callback = callback;
+ wk_editor->priv->initialized_user_data = user_data;
+ }
+}
+
+static void
+webkit_editor_update_styles (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+ gboolean mark_citations, use_custom_font;
+ gchar *font, *aa = NULL, *citation_color;
+ const gchar *styles[] = { "normal", "oblique", "italic" };
+ const gchar *smoothing = NULL;
+ GString *stylesheet;
+ PangoFontDescription *min_size, *ms, *vw;
+ WebKitSettings *settings;
+ WebKitUserContentManager *manager;
+ WebKitUserStyleSheet *style_sheet;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ use_custom_font = g_settings_get_boolean (
+ wk_editor->priv->mail_settings, "use-custom-font");
+
+ if (use_custom_font) {
+ font = g_settings_get_string (
+ wk_editor->priv->mail_settings, "monospace-font");
+ ms = pango_font_description_from_string (font ? font : "monospace 10");
+ g_free (font);
+ } else {
+ font = g_settings_get_string (
+ wk_editor->priv->font_settings, "monospace-font-name");
+ ms = pango_font_description_from_string (font ? font : "monospace 10");
+ g_free (font);
+ }
+
+ if (wk_editor->priv->html_mode) {
+ if (use_custom_font) {
+ font = g_settings_get_string (
+ wk_editor->priv->mail_settings, "variable-width-font");
+ vw = pango_font_description_from_string (font ? font : "serif 10");
+ g_free (font);
+ } else {
+ font = g_settings_get_string (
+ wk_editor->priv->font_settings, "font-name");
+ vw = pango_font_description_from_string (font ? font : "serif 10");
+ g_free (font);
+ }
+ } else {
+ /* When in plain text mode, force monospace font */
+ vw = pango_font_description_copy (ms);
+ }
+
+ stylesheet = g_string_new ("");
+ g_string_append_printf (
+ stylesheet,
+ "body {\n"
+ " font-family: '%s';\n"
+ " font-size: %dpt;\n"
+ " font-weight: %d;\n"
+ " font-style: %s;\n"
+ " -webkit-line-break: after-white-space;\n",
+ pango_font_description_get_family (vw),
+ pango_font_description_get_size (vw) / PANGO_SCALE,
+ pango_font_description_get_weight (vw),
+ styles[pango_font_description_get_style (vw)]);
+
+ if (wk_editor->priv->aliasing_settings != NULL)
+ aa = g_settings_get_string (
+ wk_editor->priv->aliasing_settings, "antialiasing");
+
+ if (g_strcmp0 (aa, "none") == 0)
+ smoothing = "none";
+ else if (g_strcmp0 (aa, "grayscale") == 0)
+ smoothing = "antialiased";
+ else if (g_strcmp0 (aa, "rgba") == 0)
+ smoothing = "subpixel-antialiased";
+
+ if (smoothing != NULL)
+ g_string_append_printf (
+ stylesheet,
+ " -webkit-font-smoothing: %s;\n",
+ smoothing);
+
+ g_free (aa);
+
+ g_string_append (stylesheet, "}\n");
+
+ g_string_append_printf (
+ stylesheet,
+ "pre,code,.pre {\n"
+ " font-family: '%s';\n"
+ " font-size: %dpt;\n"
+ " font-weight: %d;\n"
+ " font-style: %s;\n"
+ "}",
+ pango_font_description_get_family (ms),
+ pango_font_description_get_size (ms) / PANGO_SCALE,
+ pango_font_description_get_weight (ms),
+ styles[pango_font_description_get_style (ms)]);
+
+ /* See bug #689777 for details */
+ g_string_append (
+ stylesheet,
+ "p,pre,code,address {\n"
+ " margin: 0;\n"
+ "}\n"
+ "h1,h2,h3,h4,h5,h6 {\n"
+ " margin-top: 0.2em;\n"
+ " margin-bottom: 0.2em;\n"
+ "}\n");
+
+ /* When inserting a table into contenteditable element the width of the
+ * cells is nearly zero and the td { min-height } doesn't work so put
+ * unicode zero width space before each cell. */
+ g_string_append (
+ stylesheet,
+ "td:before {\n"
+ " content: \"\xe2\x80\x8b\";"
+ "}\n");
+
+ g_string_append (
+ stylesheet,
+ "img "
+ "{\n"
+ " height: inherit; \n"
+ " width: inherit; \n"
+ "}\n");
+
+ g_string_append (
+ stylesheet,
+ "span.-x-evo-resizable-wrapper:hover "
+ "{\n"
+ " outline: 1px dashed red; \n"
+ " resize: both; \n"
+ " overflow: hidden; \n"
+ " display: inline-block; \n"
+ "}\n");
+
+ g_string_append (
+ stylesheet,
+ "td:hover "
+ "{\n"
+ " outline: 1px dotted red;\n"
+ "}\n");
+
+ g_string_append (
+ stylesheet,
+ "body[data-evo-plain-text] img.-x-evo-smiley-img, "
+ "body:not([data-evo-plain-text]) span.-x-evo-smiley-text "
+ "{\n"
+ " display: none \n"
+ "}\n");
+
+ g_string_append (
+ stylesheet,
+ "body[data-evo-plain-text] [data-evo-paragraph] "
+ "{\n"
+ " word-wrap: break-word; \n"
+ " word-break: break-word; \n"
+ "}\n");
+
+ g_string_append_printf (
+ stylesheet,
+ ".-x-evo-plaintext-table "
+ "{\n"
+ " border-collapse: collapse;\n"
+ " width: %dch;\n"
+ "}\n",
+ g_settings_get_int (wk_editor->priv->mail_settings, "composer-word-wrap-length"));
+
+ g_string_append (
+ stylesheet,
+ ".-x-evo-plaintext-table td "
+ "{\n"
+ " vertical-align: top;\n"
+ "}\n");
+
+ g_string_append (
+ stylesheet,
+ "td > * "
+ "{\n"
+ " display : inline-block;\n"
+ "}\n");
+
+ g_string_append_printf (
+ stylesheet,
+ "body[data-evo-plain-text] ul "
+ "{\n"
+ " list-style: outside none;\n"
+ " -webkit-padding-start: %dch; \n"
+ "}\n", SPACES_PER_LIST_LEVEL);
+
+ g_string_append_printf (
+ stylesheet,
+ "body[data-evo-plain-text] ul > li "
+ "{\n"
+ " list-style-position: outside;\n"
+ " text-indent: -%dch;\n"
+ "}\n", SPACES_PER_LIST_LEVEL - 1);
+
+ g_string_append (
+ stylesheet,
+ "body[data-evo-plain-text] ul > li::before "
+ "{\n"
+ " content: \"*"UNICODE_NBSP"\";\n"
+ "}\n");
+
+ g_string_append_printf (
+ stylesheet,
+ "body[data-evo-plain-text] ul.-x-evo-indented "
+ "{\n"
+ " -webkit-padding-start: %dch; \n"
+ "}\n", SPACES_PER_LIST_LEVEL);
+
+ g_string_append (
+ stylesheet,
+ "body:not([data-evo-plain-text]) ul > li.-x-evo-align-center,ol > li.-x-evo-align-center "
+ "{\n"
+ " list-style-position: inside;\n"
+ "}\n");
+
+ g_string_append (
+ stylesheet,
+ "body:not([data-evo-plain-text]) ul > li.-x-evo-align-right, ol > li.-x-evo-align-right "
+ "{\n"
+ " list-style-position: inside;\n"
+ "}\n");
+
+ g_string_append_printf (
+ stylesheet,
+ "ol "
+ "{\n"
+ " -webkit-padding-start: %dch; \n"
+ "}\n", SPACES_ORDERED_LIST_FIRST_LEVEL);
+
+ g_string_append_printf (
+ stylesheet,
+ "ol.-x-evo-indented "
+ "{\n"
+ " -webkit-padding-start: %dch; \n"
+ "}\n", SPACES_PER_LIST_LEVEL);
+
+ g_string_append (
+ stylesheet,
+ ".-x-evo-align-left "
+ "{\n"
+ " text-align: left; \n"
+ "}\n");
+
+ g_string_append (
+ stylesheet,
+ ".-x-evo-align-center "
+ "{\n"
+ " text-align: center; \n"
+ "}\n");
+
+ g_string_append (
+ stylesheet,
+ ".-x-evo-align-right "
+ "{\n"
+ " text-align: right; \n"
+ "}\n");
+
+ g_string_append (
+ stylesheet,
+ "ol,ul "
+ "{\n"
+ " -webkit-margin-before: 0em; \n"
+ " -webkit-margin-after: 0em; \n"
+ "}\n");
+
+ g_string_append (
+ stylesheet,
+ "blockquote "
+ "{\n"
+ " -webkit-margin-before: 0em; \n"
+ " -webkit-margin-after: 0em; \n"
+ "}\n");
+
+ g_string_append (
+ stylesheet,
+ "a "
+ "{\n"
+ " word-wrap: break-word; \n"
+ " word-break: break-all; \n"
+ "}\n");
+
+ citation_color = g_settings_get_string (
+ wk_editor->priv->mail_settings, "citation-color");
+ mark_citations = g_settings_get_boolean (
+ wk_editor->priv->mail_settings, "mark-citations");
+
+ g_string_append (
+ stylesheet,
+ "blockquote[type=cite] "
+ "{\n"
+ " padding: 0.0ex 0ex;\n"
+ " margin: 0ex;\n"
+ " -webkit-margin-start: 0em; \n"
+ " -webkit-margin-end : 0em; \n");
+
+ if (mark_citations && citation_color)
+ g_string_append_printf (
+ stylesheet,
+ " color: %s !important; \n",
+ citation_color);
+
+ g_free (citation_color);
+ citation_color = NULL;
+
+ g_string_append (stylesheet, "}\n");
+
+ g_string_append_printf (
+ stylesheet,
+ ".-x-evo-quote-character "
+ "{\n"
+ " color: %s;\n"
+ "}\n",
+ e_web_view_get_citation_color_for_level (1));
+
+ g_string_append_printf (
+ stylesheet,
+ ".-x-evo-quote-character+"
+ ".-x-evo-quote-character"
+ "{\n"
+ " color: %s;\n"
+ "}\n",
+ e_web_view_get_citation_color_for_level (2));
+
+ g_string_append_printf (
+ stylesheet,
+ ".-x-evo-quote-character+"
+ ".-x-evo-quote-character+"
+ ".-x-evo-quote-character"
+ "{\n"
+ " color: %s;\n"
+ "}\n",
+ e_web_view_get_citation_color_for_level (3));
+
+ g_string_append_printf (
+ stylesheet,
+ ".-x-evo-quote-character+"
+ ".-x-evo-quote-character+"
+ ".-x-evo-quote-character+"
+ ".-x-evo-quote-character"
+ "{\n"
+ " color: %s;\n"
+ "}\n",
+ e_web_view_get_citation_color_for_level (4));
+
+ g_string_append_printf (
+ stylesheet,
+ ".-x-evo-quote-character+"
+ ".-x-evo-quote-character+"
+ ".-x-evo-quote-character+"
+ ".-x-evo-quote-character+"
+ ".-x-evo-quote-character"
+ "{\n"
+ " color: %s;\n"
+ "}\n",
+ e_web_view_get_citation_color_for_level (5));
+
+ g_string_append (
+ stylesheet,
+ "body:not([data-evo-plain-text]) "
+ "blockquote[type=cite] "
+ "{\n"
+ " padding: 0ch 1ch 0ch 1ch;\n"
+ " margin: 0ch;\n"
+ " border-width: 0px 2px 0px 2px;\n"
+ " border-style: none solid none solid;\n"
+ " border-radius: 2px;\n"
+ "}\n");
+
+ g_string_append_printf (
+ stylesheet,
+ "body:not([data-evo-plain-text]) "
+ "blockquote[type=cite] "
+ "{\n"
+ " border-color: %s;\n"
+ "}\n",
+ e_web_view_get_citation_color_for_level (1));
+
+ g_string_append_printf (
+ stylesheet,
+ "body:not([data-evo-plain-text]) "
+ "blockquote[type=cite] "
+ "blockquote[type=cite] "
+ "{\n"
+ " border-color: %s;\n"
+ "}\n",
+ e_web_view_get_citation_color_for_level (2));
+
+ g_string_append_printf (
+ stylesheet,
+ "body:not([data-evo-plain-text]) "
+ "blockquote[type=cite] "
+ "blockquote[type=cite] "
+ "blockquote[type=cite] "
+ "{\n"
+ " border-color: %s;\n"
+ "}\n",
+ e_web_view_get_citation_color_for_level (3));
+
+ g_string_append_printf (
+ stylesheet,
+ "body:not([data-evo-plain-text]) "
+ "blockquote[type=cite] "
+ "blockquote[type=cite] "
+ "blockquote[type=cite] "
+ "blockquote[type=cite] "
+ "{\n"
+ " border-color: %s;\n"
+ "}\n",
+ e_web_view_get_citation_color_for_level (4));
+
+ g_string_append_printf (
+ stylesheet,
+ "body:not([data-evo-plain-text]) "
+ "blockquote[type=cite] "
+ "blockquote[type=cite] "
+ "blockquote[type=cite] "
+ "blockquote[type=cite] "
+ "blockquote[type=cite] "
+ "{\n"
+ " border-color: %s;\n"
+ "}\n",
+ e_web_view_get_citation_color_for_level (5));
+
+ if (pango_font_description_get_size (ms) < pango_font_description_get_size (vw) ||
!wk_editor->priv->html_mode)
+ min_size = ms;
+ else
+ min_size = vw;
+
+ settings = webkit_web_view_get_settings (WEBKIT_WEB_VIEW (wk_editor));
+ g_object_set (
+ G_OBJECT (settings),
+ "default-font-size",
+ e_util_normalize_font_size (
+ GTK_WIDGET (wk_editor), pango_font_description_get_size (vw) / PANGO_SCALE),
+ "default-font-family",
+ pango_font_description_get_family (vw),
+ "monospace-font-family",
+ pango_font_description_get_family (ms),
+ "default-monospace-font-size", pango_font_description_get_size (ms) / PANGO_SCALE,
+ "minimum-font-size", pango_font_description_get_size (min_size) / PANGO_SCALE,
+ NULL);
+
+ manager = webkit_web_view_get_user_content_manager (WEBKIT_WEB_VIEW (wk_editor));
+ webkit_user_content_manager_remove_all_style_sheets (manager);
+
+ style_sheet = webkit_user_style_sheet_new (
+ stylesheet->str,
+ WEBKIT_USER_CONTENT_INJECT_ALL_FRAMES,
+ WEBKIT_USER_STYLE_LEVEL_USER,
+ NULL,
+ NULL);
+
+ webkit_user_content_manager_add_style_sheet (manager, style_sheet);
+
+ g_free (wk_editor->priv->current_user_stylesheet);
+ wk_editor->priv->current_user_stylesheet = g_string_free (stylesheet, FALSE);
+
+ webkit_user_style_sheet_unref (style_sheet);
+
+ pango_font_description_free (ms);
+ pango_font_description_free (vw);
+}
+
+static gboolean
+webkit_editor_get_html_mode (EWebKitEditor *wk_editor)
+{
+ return wk_editor->priv->html_mode;
+}
+
+static gboolean
+show_lose_formatting_dialog (EWebKitEditor *wk_editor)
+{
+ gboolean lose;
+ GtkWidget *toplevel;
+ GtkWindow *parent = NULL;
+
+ toplevel = gtk_widget_get_toplevel (GTK_WIDGET (wk_editor));
+
+ if (GTK_IS_WINDOW (toplevel))
+ parent = GTK_WINDOW (toplevel);
+
+ lose = e_util_prompt_user (
+ parent, "org.gnome.evolution.mail", "prompt-on-composer-mode-switch",
+ "mail-composer:prompt-composer-mode-switch", NULL);
+
+ if (!lose) {
+ /* Nothing has changed, but notify anyway */
+ g_object_notify (G_OBJECT (wk_editor), "html-mode");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+webkit_editor_set_html_mode (EWebKitEditor *wk_editor,
+ gboolean html_mode)
+{
+ gboolean convert = FALSE;
+ GVariant *result;
+
+ g_return_if_fail (E_IS_WEBKIT_EDITOR (wk_editor));
+
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+ return;
+ }
+
+ if (html_mode == wk_editor->priv->html_mode)
+ return;
+
+ result = g_dbus_proxy_call_sync_wrapper (
+ wk_editor->priv->web_extension,
+ "DOMCheckIfConversionNeeded",
+ g_variant_new ("(t)", current_page_id (wk_editor)),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL);
+
+ if (result) {
+ g_variant_get (result, "(b)", &convert);
+ g_variant_unref (result);
+ }
+
+ /* If toggling from HTML to the plain text mode, ask the user first if
+ * he wants to convert the content. */
+ if (convert) {
+ if (!show_lose_formatting_dialog (wk_editor))
+ return;
+
+ webkit_editor_set_changed (wk_editor, TRUE);
+ }
+
+ wk_editor->priv->html_mode = html_mode;
+
+ g_dbus_proxy_call (
+ wk_editor->priv->web_extension,
+ "SetEditorHTMLMode",
+ g_variant_new ("(tbb)", current_page_id (wk_editor), html_mode, convert),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+
+ /* Update fonts - in plain text we only want monospaced */
+ webkit_editor_update_styles (E_CONTENT_EDITOR (wk_editor));
+
+ g_object_notify (G_OBJECT (wk_editor), "html-mode");
+}
+
+static void
+set_convert_in_situ (EWebKitEditor *wk_editor,
+ gboolean value)
+{
+ g_dbus_proxy_call (
+ wk_editor->priv->web_extension,
+ "SetConvertInSitu",
+ g_variant_new ("(tb)", current_page_id (wk_editor), value),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+
+}
+
+static void
+webkit_editor_insert_content (EContentEditor *editor,
+ const gchar *content,
+ EContentEditorInsertContentFlags flags)
+{
+ EWebKitEditor *wk_editor;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ /* It can happen that the view is not ready yet (it is in the middle of
+ * another load operation) so we have to queue the current operation and
+ * redo it again when the view is ready. This was happening when loading
+ * the stuff in EMailSignatureEditor. */
+ if (wk_editor->priv->webkit_load_event != WEBKIT_LOAD_FINISHED ||
+ wk_editor->priv->reload_in_progress) {
+ webkit_editor_queue_post_reload_operation (
+ wk_editor,
+ (PostReloadOperationFunc) webkit_editor_insert_content,
+ g_strdup (content),
+ g_free,
+ flags);
+ return;
+ }
+
+ if (!wk_editor->priv->web_extension) {
+ /* If the operation needs a web extension and it is not ready yet
+ * we need to schedule the current operation again a dispatch it
+ * when the extension is ready */
+ if (!((flags & E_CONTENT_EDITOR_INSERT_REPLACE_ALL) &&
+ (flags & E_CONTENT_EDITOR_INSERT_TEXT_HTML) &&
+ (strstr (content, "data-evo-draft") ||
+ strstr (content, "data-evo-signature-plain-text-mode")))) {
+ webkit_editor_queue_post_reload_operation (
+ wk_editor,
+ (PostReloadOperationFunc) webkit_editor_insert_content,
+ g_strdup (content),
+ g_free,
+ flags);
+ return;
+ }
+ }
+
+ if ((flags & E_CONTENT_EDITOR_INSERT_CONVERT) &&
+ !(flags & E_CONTENT_EDITOR_INSERT_REPLACE_ALL)) {
+ /* e_html_editor_view_convert_and_insert_plain_text
+ e_html_editor_view_convert_and_insert_html_to_plain_text
+ e_html_editor_view_insert_text */
+ g_dbus_proxy_call (
+ wk_editor->priv->web_extension,
+ "DOMConvertAndInsertHTMLIntoSelection",
+ g_variant_new (
+ "(tsb)",
+ current_page_id (wk_editor),
+ content,
+ (flags & E_CONTENT_EDITOR_INSERT_TEXT_HTML)),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+ } else if ((flags & E_CONTENT_EDITOR_INSERT_REPLACE_ALL) &&
+ (flags & E_CONTENT_EDITOR_INSERT_TEXT_HTML)) {
+ if ((strstr (content, "data-evo-draft") ||
+ strstr (content, "data-evo-signature-plain-text-mode"))) {
+ wk_editor->priv->reload_in_progress = TRUE;
+ webkit_web_view_load_html (WEBKIT_WEB_VIEW (wk_editor), content, "file://");
+ return;
+ }
+
+ if (strstr (content, "data-evo-draft") && !(wk_editor->priv->html_mode)) {
+ if (content && *content)
+ set_convert_in_situ (wk_editor, TRUE);
+ wk_editor->priv->reload_in_progress = TRUE;
+ webkit_web_view_load_html (WEBKIT_WEB_VIEW (wk_editor), content, "file://");
+ return;
+ }
+
+ /* Only convert messages that are in HTML */
+ if (!(wk_editor->priv->html_mode)) {
+ if (strstr (content, "<!-- text/html -->")) {
+ if (!show_lose_formatting_dialog (wk_editor)) {
+ wk_editor->priv->reload_in_progress = TRUE;
+ webkit_editor_set_html_mode (wk_editor, TRUE);
+ webkit_web_view_load_html (
+ WEBKIT_WEB_VIEW (wk_editor), content, "file://");
+ return;
+ }
+ }
+ if (content && *content)
+ set_convert_in_situ (wk_editor, TRUE);
+ }
+
+ wk_editor->priv->reload_in_progress = TRUE;
+ webkit_web_view_load_html (WEBKIT_WEB_VIEW (wk_editor), content, "file://");
+ } else if ((flags & E_CONTENT_EDITOR_INSERT_REPLACE_ALL) &&
+ (flags & E_CONTENT_EDITOR_INSERT_TEXT_PLAIN)) {
+ g_dbus_proxy_call (
+ wk_editor->priv->web_extension,
+ "DOMConvertContent",
+ g_variant_new ("(ts)", current_page_id (wk_editor), content),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+ } else if ((flags & E_CONTENT_EDITOR_INSERT_CONVERT) &&
+ !(flags & E_CONTENT_EDITOR_INSERT_REPLACE_ALL) &&
+ !(flags & E_CONTENT_EDITOR_INSERT_QUOTE_CONTENT)) {
+ /* e_html_editor_view_paste_as_text */
+ g_dbus_proxy_call (
+ wk_editor->priv->web_extension,
+ "DOMConvertAndInsertHTMLIntoSelection",
+ g_variant_new (
+ "(tsb)", current_page_id (wk_editor), content, TRUE),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+ } else if ((flags & E_CONTENT_EDITOR_INSERT_QUOTE_CONTENT) &&
+ !(flags & E_CONTENT_EDITOR_INSERT_REPLACE_ALL)) {
+ /* e_html_editor_view_paste_clipboard_quoted */
+ g_dbus_proxy_call (
+ wk_editor->priv->web_extension,
+ "DOMQuoteAndInsertTextIntoSelection",
+ g_variant_new (
+ "(tsb)", current_page_id (wk_editor), content, (flags &
E_CONTENT_EDITOR_INSERT_TEXT_HTML) != 0),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+ } else if (!(flags & E_CONTENT_EDITOR_INSERT_CONVERT) &&
+ !(flags & E_CONTENT_EDITOR_INSERT_REPLACE_ALL)) {
+ /* e_html_editor_view_insert_html */
+ g_dbus_proxy_call (
+ wk_editor->priv->web_extension,
+ "DOMInsertHTML",
+ g_variant_new (
+ "(ts)", current_page_id (wk_editor), content),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+ } else
+ g_warning ("Unsupported flags combination (%d) in (%s)", flags, G_STRFUNC);
+}
+
+static CamelMimePart *
+create_part_for_inline_image_from_element_data (const gchar *element_src,
+ const gchar *name,
+ const gchar *id)
+{
+ CamelStream *stream;
+ CamelDataWrapper *wrapper;
+ CamelMimePart *part = NULL;
+ gsize decoded_size;
+ gssize size;
+ gchar *mime_type = NULL;
+ const gchar *base64_encoded_data;
+ guchar *base64_decoded_data = NULL;
+
+ base64_encoded_data = strstr (element_src, ";base64,");
+ if (!base64_encoded_data)
+ goto out;
+
+ mime_type = g_strndup (
+ element_src + 5,
+ base64_encoded_data - (strstr (element_src, "data:") + 5));
+
+ /* Move to actual data */
+ base64_encoded_data += 8;
+
+ base64_decoded_data = g_base64_decode (base64_encoded_data, &decoded_size);
+
+ stream = camel_stream_mem_new ();
+ size = camel_stream_write (
+ stream, (gchar *) base64_decoded_data, decoded_size, NULL, NULL);
+
+ if (size == -1)
+ goto out;
+
+ wrapper = camel_data_wrapper_new ();
+ camel_data_wrapper_construct_from_stream_sync (
+ wrapper, stream, NULL, NULL);
+ g_object_unref (stream);
+
+ camel_data_wrapper_set_mime_type (wrapper, mime_type);
+
+ part = camel_mime_part_new ();
+ camel_medium_set_content (CAMEL_MEDIUM (part), wrapper);
+ g_object_unref (wrapper);
+
+ camel_mime_part_set_content_id (part, id);
+ camel_mime_part_set_filename (part, name);
+ camel_mime_part_set_disposition (part, "inline");
+ camel_mime_part_set_encoding (part, CAMEL_TRANSFER_ENCODING_BASE64);
+out:
+ g_free (mime_type);
+ g_free (base64_decoded_data);
+
+ return part;
+}
+
+static GSList *
+webkit_editor_get_parts_for_inline_images (GVariant *images)
+{
+ const gchar *element_src, *name, *id;
+ GVariantIter *iter;
+ GSList *parts = NULL;
+
+ if (g_variant_check_format_string (images, "a(sss)", FALSE)) {
+ g_variant_get (images, "a(sss)", &iter);
+ while (g_variant_iter_loop (iter, "(&s&s&s)", &element_src, &name, &id)) {
+ CamelMimePart *part;
+
+ part = create_part_for_inline_image_from_element_data (
+ element_src, name, id);
+ parts = g_slist_prepend (parts, part);
+ }
+ g_variant_iter_free (iter);
+ }
+
+ return parts ? g_slist_reverse (parts) : NULL;
+}
+
+static gchar *
+webkit_editor_get_content (EContentEditor *editor,
+ EContentEditorGetContentFlags flags,
+ const gchar *inline_images_from_domain,
+ GSList **inline_images_parts)
+{
+ EWebKitEditor *wk_editor;
+ GVariant *result;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+ if (!wk_editor->priv->web_extension)
+ return g_strdup ("");
+
+ if ((flags & E_CONTENT_EDITOR_GET_TEXT_HTML) &&
+ !(flags & E_CONTENT_EDITOR_GET_PROCESSED) &&
+ !(flags & E_CONTENT_EDITOR_GET_BODY))
+ g_dbus_proxy_call (
+ wk_editor->priv->web_extension,
+ "DOMEmbedStyleSheet",
+ g_variant_new (
+ "(ts)",
+ current_page_id (wk_editor),
+ wk_editor->priv->current_user_stylesheet),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+
+ result = g_dbus_proxy_call_sync_wrapper (
+ wk_editor->priv->web_extension,
+ "DOMGetContent",
+ g_variant_new (
+ "(tsi)",
+ current_page_id (wk_editor),
+ inline_images_from_domain ? inline_images_from_domain : "",
+ (gint32) flags),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL);
+
+ if ((flags & E_CONTENT_EDITOR_GET_TEXT_HTML) &&
+ !(flags & E_CONTENT_EDITOR_GET_PROCESSED) &&
+ !(flags & E_CONTENT_EDITOR_GET_BODY))
+ webkit_editor_call_simple_extension_function (
+ wk_editor, "DOMRemoveEmbeddedStyleSheet");
+
+ if (result) {
+ GVariant *images = NULL;
+ gchar *value = NULL;
+
+ g_variant_get (result, "(sv)", &value, &images);
+ if (inline_images_parts)
+ *inline_images_parts = webkit_editor_get_parts_for_inline_images (images);
+
+ if (images)
+ g_variant_unref (images);
+
+ g_variant_unref (result);
+
+ return value;
+ }
+
+ return g_strdup ("");
+}
+
+static gboolean
+webkit_editor_can_undo (EWebKitEditor *wk_editor)
+{
+ g_return_val_if_fail (E_IS_WEBKIT_EDITOR (wk_editor), FALSE);
+
+ return wk_editor->priv->can_undo;
+}
+
+static void
+webkit_editor_undo (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ webkit_editor_call_simple_extension_function (wk_editor, "DOMUndo");
+}
+
+static gboolean
+webkit_editor_can_redo (EWebKitEditor *wk_editor)
+{
+ g_return_val_if_fail (E_IS_WEBKIT_EDITOR (wk_editor), FALSE);
+
+ return wk_editor->priv->can_redo;
+}
+
+static void
+webkit_editor_redo (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+
+ g_return_if_fail (E_IS_WEBKIT_EDITOR (editor));
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ webkit_editor_call_simple_extension_function (wk_editor, "DOMRedo");
+}
+
+static void
+webkit_editor_move_caret_on_coordinates (EContentEditor *editor,
+ gint x,
+ gint y,
+ gboolean cancel_if_not_collapsed)
+{
+ EWebKitEditor *wk_editor;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+ return;
+ }
+
+ g_dbus_proxy_call_sync_wrapper (
+ wk_editor->priv->web_extension,
+ "DOMMoveSelectionOnPoint",
+ g_variant_new (
+ "(tiib)", current_page_id (wk_editor), x, y, cancel_if_not_collapsed),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL);
+}
+
+static void
+webkit_editor_insert_emoticon (EContentEditor *editor,
+ EEmoticon *emoticon)
+{
+ EWebKitEditor *wk_editor;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+ return;
+ }
+
+ g_dbus_proxy_call (
+ wk_editor->priv->web_extension,
+ "DOMInsertSmiley",
+ g_variant_new (
+ "(ts)", current_page_id (wk_editor), e_emoticon_get_name (emoticon)),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+}
+
+static void
+webkit_editor_insert_image_from_mime_part (EContentEditor *editor,
+ CamelMimePart *part)
+{
+ CamelDataWrapper *dw;
+ CamelStream *stream;
+ EWebKitEditor *wk_editor;
+ GByteArray *byte_array;
+ gchar *src, *base64_encoded, *mime_type, *cid_uri;
+ const gchar *cid, *name;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+ return;
+ }
+
+ stream = camel_stream_mem_new ();
+ dw = camel_medium_get_content (CAMEL_MEDIUM (part));
+ g_return_if_fail (dw);
+
+ mime_type = camel_data_wrapper_get_mime_type (dw);
+ camel_data_wrapper_decode_to_stream_sync (dw, stream, NULL, NULL);
+ camel_stream_close (stream, NULL, NULL);
+
+ byte_array = camel_stream_mem_get_byte_array (CAMEL_STREAM_MEM (stream));
+
+ if (!byte_array->data)
+ return;
+
+ base64_encoded = g_base64_encode ((const guchar *) byte_array->data, byte_array->len);
+
+ name = camel_mime_part_get_filename (part);
+ /* Insert file name before new src */
+ src = g_strconcat (name, ";data:", mime_type, ";base64,", base64_encoded, NULL);
+
+ cid = camel_mime_part_get_content_id (part);
+ if (!cid) {
+ camel_mime_part_set_content_id (part, NULL);
+ cid = camel_mime_part_get_content_id (part);
+ }
+ cid_uri = g_strdup_printf ("cid:%s", cid);
+
+ g_dbus_proxy_call (
+ wk_editor->priv->web_extension,
+ "DOMAddNewInlineImageIntoList",
+ g_variant_new ("(tsss)", current_page_id (wk_editor), name, cid_uri, src),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+
+ g_free (base64_encoded);
+ g_free (mime_type);
+ g_object_unref (stream);
+}
+
+static void
+webkit_editor_select_all (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ webkit_web_view_execute_editing_command (
+ WEBKIT_WEB_VIEW (wk_editor), WEBKIT_EDITING_COMMAND_SELECT_ALL);
+}
+
+static void
+webkit_editor_selection_wrap (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ webkit_editor_call_simple_extension_function (wk_editor, "DOMSelectionWrap");
+}
+
+static gboolean
+webkit_editor_selection_is_indented (EWebKitEditor *wk_editor)
+{
+ g_return_val_if_fail (E_IS_WEBKIT_EDITOR (wk_editor), FALSE);
+
+ return wk_editor->priv->is_indented;
+}
+
+static void
+webkit_editor_selection_indent (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ webkit_editor_call_simple_extension_function (
+ wk_editor, "DOMSelectionIndent");
+}
+
+static void
+webkit_editor_selection_unindent (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ webkit_editor_call_simple_extension_function (
+ wk_editor, "DOMSelectionUnindent");
+}
+
+static void
+webkit_editor_cut (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ wk_editor->priv->copy_cut_actions_triggered = TRUE;
+
+ webkit_editor_call_simple_extension_function_sync (
+ wk_editor, "EEditorActionsSaveHistoryForCut");
+
+ webkit_web_view_execute_editing_command (
+ WEBKIT_WEB_VIEW (wk_editor), WEBKIT_EDITING_COMMAND_CUT);
+}
+
+static void
+webkit_editor_copy (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ wk_editor->priv->copy_cut_actions_triggered = TRUE;
+
+ webkit_web_view_execute_editing_command (
+ WEBKIT_WEB_VIEW (wk_editor), WEBKIT_EDITING_COMMAND_COPY);
+}
+
+static ESpellChecker *
+webkit_editor_get_spell_checker (EWebKitEditor *wk_editor)
+{
+ g_return_val_if_fail (E_IS_WEBKIT_EDITOR (wk_editor), NULL);
+
+ return wk_editor->priv->spell_checker;
+}
+
+static gchar *
+webkit_editor_get_caret_word (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+ gchar *ret_val = NULL;
+ GVariant *result;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+ return NULL;
+ }
+
+ result = g_dbus_proxy_call_sync_wrapper (
+ wk_editor->priv->web_extension,
+ "DOMGetCaretWord",
+ g_variant_new ("(t)", current_page_id (wk_editor)),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL);
+
+ if (result) {
+ g_variant_get (result, "(s)", &ret_val);
+ g_variant_unref (result);
+ }
+
+ return ret_val;
+}
+
+static void
+webkit_editor_set_spell_checking_languages (EContentEditor *editor,
+ const gchar **languages)
+{
+ EWebKitEditor *wk_editor;
+ WebKitWebContext *web_context;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+ web_context = webkit_web_view_get_context (WEBKIT_WEB_VIEW (wk_editor));
+ webkit_web_context_set_spell_checking_languages (web_context, (const gchar * const *) languages);
+}
+
+static void
+webkit_editor_set_spell_check_enabled (EWebKitEditor *wk_editor,
+ gboolean enable)
+{
+ g_return_if_fail (E_IS_WEBKIT_EDITOR (wk_editor));
+
+ if ((wk_editor->priv->spell_check_enabled ? 1 : 0) == (enable ? 1 : 0))
+ return;
+
+ wk_editor->priv->spell_check_enabled = enable;
+
+ webkit_editor_call_simple_extension_function (
+ wk_editor, enable ? "DOMForceSpellCheck" : "DOMTurnSpellCheckOff");
+
+ g_object_notify (G_OBJECT (wk_editor), "spell-check-enabled");
+}
+
+static gboolean
+webkit_editor_get_spell_check_enabled (EWebKitEditor *wk_editor)
+{
+ g_return_val_if_fail (E_IS_WEBKIT_EDITOR (wk_editor), FALSE);
+
+ return wk_editor->priv->spell_check_enabled;
+}
+
+static gboolean
+webkit_editor_is_editable (EWebKitEditor *wk_editor)
+{
+ g_return_val_if_fail (E_IS_WEBKIT_EDITOR (wk_editor), FALSE);
+
+ return webkit_web_view_is_editable (WEBKIT_WEB_VIEW (wk_editor));
+}
+
+static void
+webkit_editor_set_editable (EWebKitEditor *wk_editor,
+ gboolean editable)
+{
+ g_return_if_fail (E_IS_WEBKIT_EDITOR (wk_editor));
+
+ return webkit_web_view_set_editable (WEBKIT_WEB_VIEW (wk_editor), editable);
+}
+
+static gchar *
+webkit_editor_get_current_signature_uid (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+ gchar *ret_val= NULL;
+ GVariant *result;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+ return NULL;
+ }
+
+ result = g_dbus_proxy_call_sync_wrapper (
+ wk_editor->priv->web_extension,
+ "DOMGetActiveSignatureUid",
+ g_variant_new ("(t)", current_page_id (wk_editor)),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL);
+
+ if (result) {
+ g_variant_get (result, "(s)", &ret_val);
+ g_variant_unref (result);
+ }
+
+ return ret_val;
+}
+
+static gboolean
+webkit_editor_is_ready (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ return !webkit_web_view_is_loading (WEBKIT_WEB_VIEW (wk_editor)) && wk_editor->priv->web_extension;
+}
+
+static char *
+webkit_editor_insert_signature (EContentEditor *editor,
+ const gchar *content,
+ gboolean is_html,
+ const gchar *signature_id,
+ gboolean *set_signature_from_message,
+ gboolean *check_if_signature_is_changed,
+ gboolean *ignore_next_signature_change)
+{
+ EWebKitEditor *wk_editor;
+ gchar *ret_val = NULL;
+ GVariant *result;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+ return NULL;
+ }
+
+ result = g_dbus_proxy_call_sync_wrapper (
+ wk_editor->priv->web_extension,
+ "DOMInsertSignature",
+ g_variant_new (
+ "(tsbsbbb)",
+ current_page_id (wk_editor),
+ content ? content : "",
+ is_html,
+ signature_id,
+ *set_signature_from_message,
+ *check_if_signature_is_changed,
+ *ignore_next_signature_change),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL);
+
+ if (result) {
+ g_variant_get (
+ result,
+ "(sbbb)",
+ &ret_val,
+ set_signature_from_message,
+ check_if_signature_is_changed,
+ ignore_next_signature_change);
+ g_variant_unref (result);
+ }
+
+ return ret_val;
+}
+
+static guint
+webkit_editor_get_caret_position (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+ GVariant *result;
+ guint ret_val = 0;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+ return 0;
+ }
+
+ result = g_dbus_proxy_call_sync_wrapper (
+ wk_editor->priv->web_extension,
+ "DOMGetCaretPosition",
+ g_variant_new ("(t)", current_page_id (wk_editor)),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL);
+
+ if (result) {
+ ret_val = g_variant_get_uint32 (result);
+ g_variant_unref (result);
+ }
+
+ return ret_val;
+}
+
+static guint
+webkit_editor_get_caret_offset (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+ GVariant *result;
+ guint ret_val = 0;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+ return 0;
+ }
+
+ result = g_dbus_proxy_call_sync_wrapper (
+ wk_editor->priv->web_extension,
+ "DOMGetCaretOffset",
+ g_variant_new ("(t)", current_page_id (wk_editor)),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL);
+
+ if (result) {
+ ret_val = g_variant_get_uint32 (result);
+ g_variant_unref (result);
+ }
+
+ return ret_val;
+}
+
+static void
+webkit_editor_clear_undo_redo_history (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+ return;
+ }
+
+ g_dbus_proxy_call (
+ wk_editor->priv->web_extension,
+ "DOMClearUndoRedoHistory",
+ g_variant_new ("(t)", current_page_id (wk_editor)),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+}
+
+static void
+webkit_editor_replace_caret_word (EContentEditor *editor,
+ const gchar *replacement)
+{
+ EWebKitEditor *wk_editor;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+ return;
+ }
+
+ g_dbus_proxy_call (
+ wk_editor->priv->web_extension,
+ "DOMReplaceCaretWord",
+ g_variant_new ("(ts)", current_page_id (wk_editor), replacement),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+}
+
+static void
+webkit_editor_finish_search (EWebKitEditor *wk_editor)
+{
+ g_return_if_fail (E_IS_WEBKIT_EDITOR (wk_editor));
+
+ if (!wk_editor->priv->find_controller)
+ return;
+
+ webkit_find_controller_search_finish (wk_editor->priv->find_controller);
+
+ wk_editor->priv->performing_replace_all = FALSE;
+ wk_editor->priv->replaced_count = 0;
+ g_free (wk_editor->priv->replace_with);
+ wk_editor->priv->replace_with = NULL;
+
+ if (wk_editor->priv->found_text_handler_id) {
+ g_signal_handler_disconnect (wk_editor->priv->find_controller,
wk_editor->priv->found_text_handler_id);
+ wk_editor->priv->found_text_handler_id = 0;
+ }
+
+ if (wk_editor->priv->failed_to_find_text_handler_id) {
+ g_signal_handler_disconnect (wk_editor->priv->find_controller,
wk_editor->priv->failed_to_find_text_handler_id);
+ wk_editor->priv->failed_to_find_text_handler_id = 0;
+ }
+
+ wk_editor->priv->find_controller = NULL;
+}
+
+static guint32 /* WebKitFindOptions */
+find_flags_to_webkit_find_options (guint32 flags /* EContentEditorFindFlags */)
+{
+ guint32 options = 0;
+
+ if (flags & E_CONTENT_EDITOR_FIND_CASE_INSENSITIVE)
+ options |= WEBKIT_FIND_OPTIONS_CASE_INSENSITIVE;
+
+ if (flags & E_CONTENT_EDITOR_FIND_WRAP_AROUND)
+ options |= WEBKIT_FIND_OPTIONS_WRAP_AROUND;
+
+ if (flags & E_CONTENT_EDITOR_FIND_MODE_BACKWARDS)
+ options |= WEBKIT_FIND_OPTIONS_BACKWARDS;
+
+ return options;
+}
+
+static void
+webkit_find_controller_found_text_cb (WebKitFindController *find_controller,
+ guint match_count,
+ EWebKitEditor *wk_editor)
+{
+ if (wk_editor->priv->performing_replace_all) {
+ if (!wk_editor->priv->replaced_count)
+ wk_editor->priv->replaced_count = match_count;
+
+ /* Repeatedly search for 'word', then replace selection by
+ * 'replacement'. Repeat until there's at least one occurrence of
+ * 'word' in the document */
+ e_content_editor_insert_content (
+ E_CONTENT_EDITOR (wk_editor),
+ wk_editor->priv->replace_with,
+ E_CONTENT_EDITOR_INSERT_TEXT_PLAIN);
+
+ webkit_find_controller_search_next (find_controller);
+ } else {
+ e_content_editor_emit_find_done (E_CONTENT_EDITOR (wk_editor), match_count);
+ }
+}
+
+static void
+webkit_find_controller_failed_to_find_text_cb (WebKitFindController *find_controller,
+ EWebKitEditor *wk_editor)
+{
+ if (wk_editor->priv->performing_replace_all) {
+ guint replaced_count = wk_editor->priv->replaced_count;
+
+ webkit_editor_finish_search (wk_editor);
+ e_content_editor_emit_replace_all_done (E_CONTENT_EDITOR (wk_editor), replaced_count);
+ } else {
+ e_content_editor_emit_find_done (E_CONTENT_EDITOR (wk_editor), 0);
+ }
+}
+
+static void
+webkit_editor_prepare_find_controller (EWebKitEditor *wk_editor)
+{
+ g_return_if_fail (E_IS_WEBKIT_EDITOR (wk_editor));
+ g_return_if_fail (wk_editor->priv->find_controller == NULL);
+
+ wk_editor->priv->find_controller = webkit_web_view_get_find_controller (WEBKIT_WEB_VIEW (wk_editor));
+
+ wk_editor->priv->found_text_handler_id = g_signal_connect (
+ wk_editor->priv->find_controller, "found-text",
+ G_CALLBACK (webkit_find_controller_found_text_cb), wk_editor);
+
+ wk_editor->priv->failed_to_find_text_handler_id = g_signal_connect (
+ wk_editor->priv->find_controller, "failed-to-find-text",
+ G_CALLBACK (webkit_find_controller_failed_to_find_text_cb), wk_editor);
+
+ wk_editor->priv->performing_replace_all = FALSE;
+ wk_editor->priv->replaced_count = 0;
+ g_free (wk_editor->priv->replace_with);
+ wk_editor->priv->replace_with = NULL;
+}
+
+static void
+webkit_editor_find (EContentEditor *editor,
+ guint32 flags,
+ const gchar *text)
+{
+ EWebKitEditor *wk_editor;
+ guint32 wk_options;
+ gboolean needs_init;
+
+ g_return_if_fail (E_IS_WEBKIT_EDITOR (editor));
+ g_return_if_fail (text != NULL);
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ wk_options = find_flags_to_webkit_find_options (flags);
+
+ needs_init = !wk_editor->priv->find_controller;
+ if (needs_init) {
+ webkit_editor_prepare_find_controller (wk_editor);
+ } else {
+ needs_init = wk_options != webkit_find_controller_get_options
(wk_editor->priv->find_controller) ||
+ g_strcmp0 (text, webkit_find_controller_get_search_text
(wk_editor->priv->find_controller)) != 0;
+ }
+
+ if (needs_init) {
+ webkit_find_controller_search (wk_editor->priv->find_controller, text, wk_options, G_MAXUINT);
+ } else if ((flags & E_CONTENT_EDITOR_FIND_PREVIOUS) != 0) {
+ webkit_find_controller_search_previous (wk_editor->priv->find_controller);
+ } else {
+ webkit_find_controller_search_next (wk_editor->priv->find_controller);
+ }
+}
+
+static void
+webkit_editor_replace (EContentEditor *editor,
+ const gchar *replacement)
+{
+ EWebKitEditor *wk_editor;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+ return;
+ }
+
+ g_dbus_proxy_call (
+ wk_editor->priv->web_extension,
+ "DOMSelectionReplace",
+ g_variant_new ("(ts)", current_page_id (wk_editor), replacement),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+}
+
+static void
+webkit_editor_replace_all (EContentEditor *editor,
+ guint32 flags,
+ const gchar *find_text,
+ const gchar *replace_with)
+{
+ EWebKitEditor *wk_editor;
+ guint32 wk_options;
+
+ g_return_if_fail (E_IS_WEBKIT_EDITOR (editor));
+ g_return_if_fail (find_text != NULL);
+ g_return_if_fail (replace_with != NULL);
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+ wk_options = find_flags_to_webkit_find_options (flags);
+
+ if (!wk_editor->priv->find_controller)
+ webkit_editor_prepare_find_controller (wk_editor);
+
+ g_free (wk_editor->priv->replace_with);
+ wk_editor->priv->replace_with = g_strdup (replace_with);
+
+ wk_editor->priv->performing_replace_all = TRUE;
+ wk_editor->priv->replaced_count = 0;
+
+ webkit_find_controller_search (wk_editor->priv->find_controller, find_text, wk_options, G_MAXUINT);
+}
+
+static void
+webkit_editor_selection_save (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ webkit_editor_call_simple_extension_function (
+ wk_editor, "DOMSaveSelection");
+}
+
+static void
+webkit_editor_selection_restore (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ webkit_editor_call_simple_extension_function (
+ wk_editor, "DOMRestoreSelection");
+}
+
+static void
+webkit_editor_delete_cell_contents (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ webkit_editor_call_simple_extension_function (
+ wk_editor, "EEditorDialogDeleteCellContents");
+}
+
+static void
+webkit_editor_delete_column (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ webkit_editor_call_simple_extension_function (
+ wk_editor, "EEditorDialogDeleteColumn");
+}
+
+static void
+webkit_editor_delete_row (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ webkit_editor_call_simple_extension_function (
+ wk_editor, "EEditorDialogDeleteRow");
+}
+
+static void
+webkit_editor_delete_table (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ webkit_editor_call_simple_extension_function (
+ wk_editor, "EEditorDialogDeleteTable");
+}
+
+static void
+webkit_editor_insert_column_after (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ webkit_editor_call_simple_extension_function (
+ wk_editor, "EEditorDialogInsertColumnAfter");
+}
+
+static void
+webkit_editor_insert_column_before (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ webkit_editor_call_simple_extension_function (
+ wk_editor, "EEditorDialogInsertColumnBefore");
+}
+
+
+static void
+webkit_editor_insert_row_above (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ webkit_editor_call_simple_extension_function (
+ wk_editor, "EEditorDialogInsertRowAbove");
+}
+
+static void
+webkit_editor_insert_row_below (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ webkit_editor_call_simple_extension_function (
+ wk_editor, "EEditorDialogInsertRowBelow");
+}
+
+static gboolean
+webkit_editor_on_h_rule_dialog_open (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+ gboolean value = FALSE;
+ GVariant *result;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+ return FALSE;
+ }
+
+ result = g_dbus_proxy_call_sync_wrapper (
+ wk_editor->priv->web_extension,
+ "EEditorHRuleDialogFindHRule",
+ g_variant_new ("(t)", current_page_id (wk_editor)),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL);
+
+ if (result) {
+ g_variant_get (result, "(b)", &value);
+ g_variant_unref (result);
+ }
+
+ return value;
+}
+
+static void
+webkit_editor_on_h_rule_dialog_close (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ webkit_editor_call_simple_extension_function (
+ wk_editor, "EEditorHRuleDialogOnClose");
+}
+
+static void
+webkit_editor_h_rule_set_align (EContentEditor *editor,
+ const gchar *value)
+{
+ EWebKitEditor *wk_editor;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ webkit_editor_set_element_attribute (
+ wk_editor, "#-x-evo-current-hr", "align", value);
+}
+
+static gchar *
+webkit_editor_h_rule_get_align (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+ gchar *value = NULL;
+ GVariant *result;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ result = webkit_editor_get_element_attribute (
+ wk_editor, "#-x-evo-current-hr", "align");
+ if (result) {
+ g_variant_get (result, "(s)", &value);
+ g_variant_unref (result);
+ }
+
+ return value;
+}
+
+static void
+webkit_editor_h_rule_set_size (EContentEditor *editor,
+ gint value)
+{
+ EWebKitEditor *wk_editor;
+ gchar *size;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ size = g_strdup_printf ("%d", value);
+
+ webkit_editor_set_element_attribute (
+ wk_editor, "#-x-evo-current-hr", "size", size);
+
+ g_free (size);
+}
+
+static gint
+webkit_editor_h_rule_get_size (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+ gint size = 0;
+ GVariant *result;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ result = webkit_editor_get_element_attribute (
+ wk_editor, "#-x-evo-current-hr", "size");
+ if (result) {
+ const gchar *value;
+
+ g_variant_get (result, "(&s)", &value);
+ if (value && *value)
+ size = atoi (value);
+
+ if (size == 0)
+ size = 2;
+
+ g_variant_unref (result);
+ }
+
+ return size;
+}
+
+static void
+webkit_editor_h_rule_set_width (EContentEditor *editor,
+ gint value,
+ EContentEditorUnit unit)
+{
+ EWebKitEditor *wk_editor;
+ gchar *width;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ width = g_strdup_printf (
+ "%d%s",
+ value,
+ (unit == E_CONTENT_EDITOR_UNIT_PIXEL) ? "px" : "%");
+
+ webkit_editor_set_element_attribute (
+ wk_editor, "#-x-evo-current-hr", "width", width);
+
+ g_free (width);
+}
+
+static gint
+webkit_editor_h_rule_get_width (EContentEditor *editor,
+ EContentEditorUnit *unit)
+{
+ EWebKitEditor *wk_editor;
+ gint value = 0;
+ GVariant *result;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ *unit = E_CONTENT_EDITOR_UNIT_PIXEL;
+
+ result = webkit_editor_get_element_attribute (
+ wk_editor, "#-x-evo-current-hr", "width");
+ if (result) {
+ const gchar *width;
+ g_variant_get (result, "(&s)", &width);
+ if (width && *width) {
+ value = atoi (width);
+ if (strstr (width, "%"))
+ *unit = E_CONTENT_EDITOR_UNIT_PERCENTAGE;
+ }
+ g_variant_unref (result);
+ }
+
+ return value;
+}
+
+static void
+webkit_editor_h_rule_set_no_shade (EContentEditor *editor,
+ gboolean value)
+{
+ EWebKitEditor *wk_editor;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+ return;
+ }
+
+ if (value)
+ webkit_editor_set_element_attribute (
+ wk_editor, "#-x-evo-current-hr", "noshade", "");
+ else
+ webkit_editor_remove_element_attribute (
+ wk_editor, "#-x-evo-current-hr", "noshade");
+}
+
+static gboolean
+webkit_editor_h_rule_get_no_shade (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+ GVariant *result;
+ gboolean no_shade = FALSE;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+ return FALSE;
+ }
+
+ result = g_dbus_proxy_call_sync_wrapper (
+ wk_editor->priv->web_extension,
+ "ElementHasAttribute",
+ g_variant_new ("(tss)", current_page_id (wk_editor), "-x-evo-current-hr", "noshade"),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL);
+
+ if (result) {
+ g_variant_get (result, "(b)", &no_shade);
+ g_variant_unref (result);
+ }
+
+ return no_shade;
+}
+
+static void
+webkit_editor_on_image_dialog_open (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ webkit_editor_call_simple_extension_function (
+ wk_editor, "EEditorImageDialogMarkImage");
+}
+
+static void
+webkit_editor_on_image_dialog_close (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ webkit_editor_call_simple_extension_function (
+ wk_editor, "EEditorImageDialogSaveHistoryOnExit");
+}
+
+static void
+webkit_editor_insert_image (EContentEditor *editor,
+ const gchar *image_uri)
+{
+ EWebKitEditor *wk_editor;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+ return;
+ }
+
+ g_dbus_proxy_call (
+ wk_editor->priv->web_extension,
+ "DOMSelectionInsertImage",
+ g_variant_new ("(ts)", current_page_id (wk_editor), image_uri),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+}
+
+static void
+webkit_editor_replace_image_src (EWebKitEditor *wk_editor,
+ const gchar *selector,
+ const gchar *image_uri)
+{
+
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+ return;
+ }
+
+ g_dbus_proxy_call (
+ wk_editor->priv->web_extension,
+ "DOMReplaceImageSrc",
+ g_variant_new ("(tss)", current_page_id (wk_editor), selector, image_uri),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+}
+
+static void
+webkit_editor_image_set_src (EContentEditor *editor,
+ const gchar *value)
+{
+ EWebKitEditor *wk_editor;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ webkit_editor_replace_image_src (
+ wk_editor, "img#-x-evo-current-img", value);
+}
+
+static gchar *
+webkit_editor_image_get_src (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+ gchar *value = NULL;
+ GVariant *result;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ result = webkit_editor_get_element_attribute (
+ wk_editor, "#-x-evo-current-img", "data-uri");
+
+ if (result) {
+ g_variant_get (result, "(s)", &value);
+ g_variant_unref (result);
+ }
+
+ return value;
+}
+
+static void
+webkit_editor_image_set_alt (EContentEditor *editor,
+ const gchar *value)
+{
+ EWebKitEditor *wk_editor;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ webkit_editor_set_element_attribute (
+ wk_editor, "#-x-evo-current-img", "alt", value);
+}
+
+static gchar *
+webkit_editor_image_get_alt (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+ gchar *value = NULL;
+ GVariant *result;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ result = webkit_editor_get_element_attribute (
+ wk_editor, "#-x-evo-current-img", "alt");
+
+ if (result) {
+ g_variant_get (result, "(s)", &value);
+ g_variant_unref (result);
+ }
+
+ return value;
+}
+
+static void
+webkit_editor_image_set_url (EContentEditor *editor,
+ const gchar *value)
+{
+ EWebKitEditor *wk_editor;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+ return;
+ }
+
+ g_dbus_proxy_call (
+ wk_editor->priv->web_extension,
+ "EEditorImageDialogSetElementUrl",
+ g_variant_new ("(ts)", current_page_id (wk_editor), value),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+}
+
+static gchar *
+webkit_editor_image_get_url (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+ GVariant *result;
+ gchar *value = NULL;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+ return NULL;
+ }
+
+ result = g_dbus_proxy_call_sync_wrapper (
+ wk_editor->priv->web_extension,
+ "EEditorImageDialogGetElementUrl",
+ g_variant_new ("(t)", current_page_id (wk_editor)),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL);
+
+ if (result) {
+ g_variant_get (result, "(s)", &value);
+ g_variant_unref (result);
+ }
+
+ return value;
+}
+
+static void
+webkit_editor_image_set_vspace (EContentEditor *editor,
+ gint value)
+{
+ EWebKitEditor *wk_editor;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+ return;
+ }
+
+ g_dbus_proxy_call (
+ wk_editor->priv->web_extension,
+ "ImageElementSetVSpace",
+ g_variant_new (
+ "(tsi)", current_page_id (wk_editor), "-x-evo-current-img", value),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+}
+
+static gint
+webkit_editor_image_get_vspace (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+ GVariant *result;
+ gint value = 0;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+ return 0;
+ }
+
+ result = g_dbus_proxy_call_sync_wrapper (
+ wk_editor->priv->web_extension,
+ "ImageElementGetVSpace",
+ g_variant_new ("(ts)", current_page_id (wk_editor), "-x-evo-current-img"),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL);
+
+ if (result) {
+ g_variant_get (result, "(i)", &value);
+ g_variant_unref (result);
+ }
+
+ return value;
+}
+
+static void
+webkit_editor_image_set_hspace (EContentEditor *editor,
+ gint value)
+{
+ EWebKitEditor *wk_editor;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+ return;
+ }
+
+ g_dbus_proxy_call (
+ wk_editor->priv->web_extension,
+ "ImageElementSetHSpace",
+ g_variant_new (
+ "(tsi)", current_page_id (wk_editor), "-x-evo-current-img", value),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+}
+
+static gint
+webkit_editor_image_get_hspace (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+ GVariant *result;
+ gint value = 0;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+ return 0;
+ }
+
+ result = g_dbus_proxy_call_sync_wrapper (
+ wk_editor->priv->web_extension,
+ "ImageElementGetHSpace",
+ g_variant_new ("(ts)", current_page_id (wk_editor), "-x-evo-current-img"),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL);
+
+ if (result) {
+ g_variant_get (result, "(i)", &value);
+ g_variant_unref (result);
+ }
+
+ return value;
+}
+
+static void
+webkit_editor_image_set_border (EContentEditor *editor,
+ gint value)
+{
+ EWebKitEditor *wk_editor;
+ gchar *border;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ border = g_strdup_printf ("%d", value);
+
+ webkit_editor_set_element_attribute (
+ wk_editor, "#-x-evo-current-img", "border", border);
+
+ g_free (border);
+}
+
+static gint
+webkit_editor_image_get_border (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+ gint value = 0;
+ GVariant *result;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ result = webkit_editor_get_element_attribute (
+ wk_editor, "#-x-evo-current-img", "border");
+
+ if (result) {
+ const gchar *border;
+ g_variant_get (result, "(&s)", &border);
+ if (border && *border)
+ value = atoi (border);
+ g_variant_unref (result);
+ }
+
+ return value;
+}
+
+static void
+webkit_editor_image_set_align (EContentEditor *editor,
+ const gchar *value)
+{
+ EWebKitEditor *wk_editor;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ webkit_editor_set_element_attribute (
+ wk_editor, "#-x-evo-current-img", "align", value);
+}
+
+static gchar *
+webkit_editor_image_get_align (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+ gchar *value = NULL;
+ GVariant *result;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ result = webkit_editor_get_element_attribute (
+ wk_editor, "#-x-evo-current-img", "align");
+
+ if (result) {
+ g_variant_get (result, "(s)", &value);
+ g_variant_unref (result);
+ }
+
+ return value;
+}
+
+static gint32
+webkit_editor_image_get_natural_width (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+ GVariant *result;
+ gint32 value = 0;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+ return 0;
+ }
+
+ result = g_dbus_proxy_call_sync_wrapper (
+ wk_editor->priv->web_extension,
+ "ImageElementGetNaturalWidth",
+ g_variant_new ("(ts)", current_page_id (wk_editor), "-x-evo-current-img"),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL);
+
+ if (result) {
+ g_variant_get (result, "(i)", &value);
+ g_variant_unref (result);
+ }
+
+ return value;
+}
+
+static gint32
+webkit_editor_image_get_natural_height (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+ GVariant *result;
+ gint32 value = 0;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+ return 0;
+ }
+
+ result = g_dbus_proxy_call_sync_wrapper (
+ wk_editor->priv->web_extension,
+ "ImageElementGetNaturalHeight",
+ g_variant_new ("(ts)", current_page_id (wk_editor), "-x-evo-current-img"),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL);
+
+ if (result) {
+ g_variant_get (result, "(i)", &value);
+ g_variant_unref (result);
+ }
+
+ return value;
+}
+
+static void
+webkit_editor_image_set_height (EContentEditor *editor,
+ gint value)
+{
+ EWebKitEditor *wk_editor;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+ return;
+ }
+
+ g_dbus_proxy_call (
+ wk_editor->priv->web_extension,
+ "ImageElementSetHeight",
+ g_variant_new (
+ "(tsi)", current_page_id (wk_editor), "-x-evo-current-img", value),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+}
+
+static void
+webkit_editor_image_set_width (EContentEditor *editor,
+ gint value)
+{
+ EWebKitEditor *wk_editor;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+ return;
+ }
+
+ g_dbus_proxy_call (
+ wk_editor->priv->web_extension,
+ "ImageElementSetWidth",
+ g_variant_new (
+ "(tsi)", current_page_id (wk_editor), "-x-evo-current-img", value),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+}
+
+static void
+webkit_editor_image_set_height_follow (EContentEditor *editor,
+ gboolean value)
+{
+ EWebKitEditor *wk_editor;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ if (value)
+ webkit_editor_set_element_attribute (
+ wk_editor, "#-x-evo-current-img", "style", "height: auto;");
+ else
+ webkit_editor_remove_element_attribute (
+ wk_editor, "#-x-evo-current-img", "style");
+}
+
+static void
+webkit_editor_image_set_width_follow (EContentEditor *editor,
+ gboolean value)
+{
+ EWebKitEditor *wk_editor;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ if (value)
+ webkit_editor_set_element_attribute (
+ wk_editor, "#-x-evo-current-img", "style", "width: auto;");
+ else
+ webkit_editor_remove_element_attribute (
+ wk_editor, "#-x-evo-current-img", "style");
+}
+
+static gint32
+webkit_editor_image_get_width (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+ GVariant *result;
+ gint32 value = 0;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+ return 0;
+ }
+
+ result = g_dbus_proxy_call_sync_wrapper (
+ wk_editor->priv->web_extension,
+ "ImageElementGetWidth",
+ g_variant_new ("(ts)", current_page_id (wk_editor), "-x-evo-current-img"),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL);
+
+ if (result) {
+ g_variant_get (result, "(i)", &value);
+ g_variant_unref (result);
+ }
+
+ return value;
+}
+
+static gint32
+webkit_editor_image_get_height (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+ GVariant *result;
+ gint32 value = 0;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+ return 0;
+ }
+
+ result = g_dbus_proxy_call_sync_wrapper (
+ wk_editor->priv->web_extension,
+ "ImageElementGetHeight",
+ g_variant_new ("(ts)", current_page_id (wk_editor), "-x-evo-current-img"),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL);
+
+ if (result) {
+ g_variant_get (result, "(i)", &value);
+ g_variant_unref (result);
+ }
+
+ return value;
+}
+
+static void
+webkit_editor_selection_unlink (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ webkit_editor_call_simple_extension_function (
+ wk_editor, "EEditorLinkDialogUnlink");
+}
+
+static void
+webkit_editor_on_link_dialog_open (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ webkit_editor_call_simple_extension_function (
+ wk_editor, "EEditorLinkDialogOnOpen");
+}
+
+static void
+webkit_editor_on_link_dialog_close (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ webkit_editor_call_simple_extension_function (
+ wk_editor, "EEditorLinkDialogOnClose");
+}
+
+static void
+webkit_editor_link_set_values (EContentEditor *editor,
+ const gchar *href,
+ const gchar *text)
+{
+ EWebKitEditor *wk_editor;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+ return;
+ }
+
+ g_dbus_proxy_call (
+ wk_editor->priv->web_extension,
+ "EEditorLinkDialogOk",
+ g_variant_new ("(tss)", current_page_id (wk_editor), href, text),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+}
+
+static void
+webkit_editor_link_get_values (EContentEditor *editor,
+ gchar **href,
+ gchar **text)
+{
+ EWebKitEditor *wk_editor;
+ GVariant *result;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+ return;
+ }
+
+ result = g_dbus_proxy_call_sync_wrapper (
+ wk_editor->priv->web_extension,
+ "EEditorLinkDialogShow",
+ g_variant_new ("(t)", current_page_id (wk_editor)),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL);
+
+ if (result) {
+ g_variant_get (result, "(ss)", href, text);
+ g_variant_unref (result);
+ } else {
+ *href = NULL;
+ *text = NULL;
+ }
+}
+
+static void
+webkit_editor_set_alignment (EWebKitEditor *wk_editor,
+ EContentEditorAlignment value)
+{
+ g_return_if_fail (E_IS_WEBKIT_EDITOR (wk_editor));
+
+ webkit_editor_set_format_int (
+ wk_editor, "DOMSelectionSetAlignment", (gint32) value);
+}
+
+static EContentEditorAlignment
+webkit_editor_get_alignment (EWebKitEditor *wk_editor)
+{
+ g_return_val_if_fail (E_IS_WEBKIT_EDITOR (wk_editor), E_CONTENT_EDITOR_ALIGNMENT_LEFT);
+
+ return wk_editor->priv->alignment;
+}
+
+static void
+webkit_editor_set_block_format (EWebKitEditor *wk_editor,
+ EContentEditorBlockFormat value)
+{
+ g_return_if_fail (E_IS_WEBKIT_EDITOR (wk_editor));
+
+ webkit_editor_set_format_int (
+ wk_editor, "DOMSelectionSetBlockFormat", (gint32) value);
+}
+
+static EContentEditorBlockFormat
+webkit_editor_get_block_format (EWebKitEditor *wk_editor)
+{
+ g_return_val_if_fail (E_IS_WEBKIT_EDITOR (wk_editor), E_CONTENT_EDITOR_BLOCK_FORMAT_NONE);
+
+ return wk_editor->priv->block_format;
+}
+
+static void
+webkit_editor_set_background_color (EWebKitEditor *wk_editor,
+ const GdkRGBA *value)
+{
+ gchar *color;
+
+ g_return_if_fail (E_IS_WEBKIT_EDITOR (wk_editor));
+
+ if (gdk_rgba_equal (value, wk_editor->priv->background_color))
+ return;
+
+ color = g_strdup_printf ("#%06x", e_rgba_to_value (value));
+
+ if (wk_editor->priv->background_color)
+ gdk_rgba_free (wk_editor->priv->background_color);
+
+ wk_editor->priv->background_color = gdk_rgba_copy (value);
+
+ webkit_editor_set_format_string (
+ wk_editor,
+ "background-color",
+ "DOMSelectionSetBackgroundColor",
+ color);
+
+ g_free (color);
+}
+
+static const GdkRGBA *
+webkit_editor_get_background_color (EWebKitEditor *wk_editor)
+{
+ g_return_val_if_fail (E_IS_WEBKIT_EDITOR (wk_editor), NULL);
+
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+ return NULL;
+ }
+
+ if (!wk_editor->priv->html_mode || !wk_editor->priv->background_color)
+ return &white;
+
+ return wk_editor->priv->background_color;
+}
+
+static void
+webkit_editor_set_font_name (EWebKitEditor *wk_editor,
+ const gchar *value)
+{
+ g_return_if_fail (E_IS_WEBKIT_EDITOR (wk_editor));
+
+ wk_editor->priv->font_name = g_strdup (value);
+
+ webkit_editor_set_format_string (
+ wk_editor, "font-name", "DOMSelectionSetFontName", value);
+}
+
+static const gchar *
+webkit_editor_get_font_name (EWebKitEditor *wk_editor)
+{
+ g_return_val_if_fail (E_IS_WEBKIT_EDITOR (wk_editor), NULL);
+
+ return wk_editor->priv->font_name;
+}
+
+static void
+webkit_editor_set_font_color (EWebKitEditor *wk_editor,
+ const GdkRGBA *value)
+{
+ gchar *color;
+
+ g_return_if_fail (E_IS_WEBKIT_EDITOR (wk_editor));
+
+ if (gdk_rgba_equal (value, wk_editor->priv->font_color))
+ return;
+
+ color = g_strdup_printf ("#%06x", e_rgba_to_value (value));
+
+ if (wk_editor->priv->font_color)
+ gdk_rgba_free (wk_editor->priv->font_color);
+
+ wk_editor->priv->font_color = gdk_rgba_copy (value);
+
+ webkit_editor_set_format_string (
+ wk_editor,
+ "font-color",
+ "DOMSelectionSetFontColor",
+ color);
+
+ g_free (color);
+}
+
+static const GdkRGBA *
+webkit_editor_get_font_color (EWebKitEditor *wk_editor)
+{
+ g_return_val_if_fail (E_IS_WEBKIT_EDITOR (wk_editor), NULL);
+
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+ return NULL;
+ }
+
+ if (!wk_editor->priv->html_mode || !wk_editor->priv->font_color)
+ return &black;
+
+ return wk_editor->priv->font_color;
+}
+
+static void
+webkit_editor_set_font_size (EWebKitEditor *wk_editor,
+ gint value)
+{
+ g_return_if_fail (E_IS_WEBKIT_EDITOR (wk_editor));
+
+ if (wk_editor->priv->font_size == value)
+ return;
+
+ wk_editor->priv->font_size = value;
+
+ webkit_editor_set_format_int (
+ wk_editor, "DOMSelectionSetFontSize", value);
+}
+
+static gint
+webkit_editor_get_font_size (EWebKitEditor *wk_editor)
+{
+ g_return_val_if_fail (E_IS_WEBKIT_EDITOR (wk_editor), -1);
+
+ return wk_editor->priv->font_size;
+}
+
+static void
+webkit_editor_set_style_flag (EWebKitEditor *wk_editor,
+ EContentEditorStyleFlags flag,
+ gboolean do_set,
+ const gchar *dom_function_name)
+{
+ g_return_if_fail (E_IS_WEBKIT_EDITOR (wk_editor));
+
+ if (((wk_editor->priv->style_flags & flag) != 0 ? 1 : 0) == (do_set ? 1 : 0))
+ return;
+
+ wk_editor->priv->style_flags = (wk_editor->priv->style_flags & ~flag) | (do_set ? flag : 0);
+
+ webkit_editor_set_format_boolean (wk_editor, dom_function_name, do_set);
+}
+
+static gboolean
+webkit_editor_get_style_flag (EWebKitEditor *wk_editor,
+ EContentEditorStyleFlags flag)
+{
+ g_return_val_if_fail (E_IS_WEBKIT_EDITOR (wk_editor), FALSE);
+
+ return (wk_editor->priv->style_flags & flag) != 0;
+}
+
+static void
+webkit_editor_page_set_text_color (EContentEditor *editor,
+ const GdkRGBA *value)
+{
+ EWebKitEditor *wk_editor;
+ gchar *color;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ color = g_strdup_printf ("#%06x", e_rgba_to_value (value));
+
+ webkit_editor_set_element_attribute (wk_editor, "body", "text", color);
+
+ g_free (color);
+}
+
+static void
+webkit_editor_page_get_text_color (EContentEditor *editor,
+ GdkRGBA *color)
+{
+ EWebKitEditor *wk_editor;
+ GVariant *result;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ if (!wk_editor->priv->html_mode)
+ goto theme;
+
+ result = webkit_editor_get_element_attribute (wk_editor, "body", "text");
+ if (result) {
+ const gchar *value;
+
+ g_variant_get (result, "(&s)", &value);
+ if (!value || !*value || !gdk_rgba_parse (color, value)) {
+ g_variant_unref (result);
+ goto theme;
+ }
+ g_variant_unref (result);
+ return;
+ }
+
+ theme:
+ e_utils_get_theme_color (
+ GTK_WIDGET (wk_editor),
+ "theme_text_color",
+ E_UTILS_DEFAULT_THEME_TEXT_COLOR,
+ color);
+}
+
+static void
+webkit_editor_page_set_background_color (EContentEditor *editor,
+ const GdkRGBA *value)
+{
+ EWebKitEditor *wk_editor;
+ gchar *color;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ if (value->alpha != 0.0)
+ color = g_strdup_printf ("#%06x", e_rgba_to_value (value));
+ else
+ color = g_strdup ("");
+
+ webkit_editor_set_element_attribute (wk_editor, "body", "bgcolor", color);
+
+ g_free (color);
+}
+
+static void
+webkit_editor_page_get_background_color (EContentEditor *editor,
+ GdkRGBA *color)
+{
+ EWebKitEditor *wk_editor;
+ GVariant *result;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ if (!wk_editor->priv->html_mode)
+ goto theme;
+
+ result = webkit_editor_get_element_attribute (wk_editor, "body", "bgcolor");
+ if (result) {
+ const gchar *value;
+
+ g_variant_get (result, "(&s)", &value);
+ if (!value || !*value || !gdk_rgba_parse (color, value)) {
+ g_variant_unref (result);
+ goto theme;
+ }
+ g_variant_unref (result);
+ return;
+ }
+
+ theme:
+ e_utils_get_theme_color (
+ GTK_WIDGET (wk_editor),
+ "theme_base_color",
+ E_UTILS_DEFAULT_THEME_BASE_COLOR,
+ color);
+}
+
+static void
+webkit_editor_page_set_link_color (EContentEditor *editor,
+ const GdkRGBA *value)
+{
+ EWebKitEditor *wk_editor;
+ gchar *color;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ color = g_strdup_printf ("#%06x", e_rgba_to_value (value));
+
+ webkit_editor_set_element_attribute (wk_editor, "body", "link", color);
+
+ g_free (color);
+}
+
+static void
+webkit_editor_page_get_link_color (EContentEditor *editor,
+ GdkRGBA *color)
+{
+ EWebKitEditor *wk_editor;
+ GVariant *result;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ if (!wk_editor->priv->html_mode)
+ goto theme;
+
+ result = webkit_editor_get_element_attribute (wk_editor, "body", "link");
+ if (result) {
+ const gchar *value;
+
+ g_variant_get (result, "(&s)", &value);
+ if (!value || !*value || !gdk_rgba_parse (color, value)) {
+ g_variant_unref (result);
+ goto theme;
+ }
+ g_variant_unref (result);
+ return;
+ }
+
+ theme:
+ color->alpha = 1;
+ color->red = 0;
+ color->green = 0;
+ color->blue = 1;
+}
+
+static void
+webkit_editor_page_set_visited_link_color (EContentEditor *editor,
+ const GdkRGBA *value)
+{
+ EWebKitEditor *wk_editor;
+ gchar *color;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ color = g_strdup_printf ("#%06x", e_rgba_to_value (value));
+
+ webkit_editor_set_element_attribute (wk_editor, "body", "vlink", color);
+
+ g_free (color);
+}
+
+static void
+webkit_editor_page_get_visited_link_color (EContentEditor *editor,
+ GdkRGBA *color)
+{
+ EWebKitEditor *wk_editor;
+ GVariant *result;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ if (!wk_editor->priv->html_mode)
+ goto theme;
+
+ result = webkit_editor_get_element_attribute (wk_editor, "body", "vlink");
+ if (result) {
+ const gchar *value;
+
+ g_variant_get (result, "(&s)", &value);
+ if (!value || !*value || !gdk_rgba_parse (color, value)) {
+ g_variant_unref (result);
+ goto theme;
+ }
+ g_variant_unref (result);
+ return;
+ }
+
+ theme:
+ color->alpha = 1;
+ color->red = 1;
+ color->green = 0;
+ color->blue = 0;
+}
+
+static void
+webkit_editor_on_page_dialog_open (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ webkit_editor_call_simple_extension_function (
+ wk_editor, "EEditorPageDialogSaveHistory");
+}
+
+static void
+webkit_editor_on_page_dialog_close (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ webkit_editor_call_simple_extension_function (
+ wk_editor, "EEditorPageDialogSaveHistoryOnExit");
+}
+
+static gchar *
+webkit_editor_page_get_background_image_uri (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+ GVariant *result;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ if (!wk_editor->priv->html_mode)
+ return NULL;
+
+ result = webkit_editor_get_element_attribute (wk_editor, "body", "data-uri");
+ if (result) {
+ gchar *value;
+
+ g_variant_get (result, "(s)", &value);
+ g_variant_unref (result);
+ }
+
+ return NULL;
+}
+
+static void
+webkit_editor_page_set_background_image_uri (EContentEditor *editor,
+ const gchar *uri)
+{
+ EWebKitEditor *wk_editor;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ if (!wk_editor->priv->html_mode)
+ return;
+
+ if (uri && *uri)
+ webkit_editor_replace_image_src (wk_editor, "body", uri);
+ else {
+ g_dbus_proxy_call (
+ wk_editor->priv->web_extension,
+ "RemoveImageAttributesFromElementBySelector",
+ g_variant_new ("(ts)", current_page_id (wk_editor), "body"),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+ }
+}
+
+static void
+webkit_editor_on_cell_dialog_open (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+ return;
+ }
+
+ g_dbus_proxy_call (
+ wk_editor->priv->web_extension,
+ "EEditorCellDialogMarkCurrentCellElement",
+ g_variant_new ("(ts)", current_page_id (wk_editor), "-x-evo-current-cell"),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+}
+
+static void
+webkit_editor_on_cell_dialog_close (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ webkit_editor_call_simple_extension_function (
+ wk_editor, "EEditorCellDialogSaveHistoryOnExit");
+}
+
+static void
+webkit_editor_cell_set_v_align (EContentEditor *editor,
+ const gchar *value,
+ EContentEditorScope scope)
+{
+ EWebKitEditor *wk_editor;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ if (!wk_editor->priv->html_mode)
+ return;
+
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+ return;
+ }
+
+ g_dbus_proxy_call (
+ wk_editor->priv->web_extension,
+ "EEditorCellDialogSetElementVAlign",
+ g_variant_new ("(tsi)", current_page_id (wk_editor), value, (gint32) scope),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+}
+
+static gchar *
+webkit_editor_cell_get_v_align (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+ gchar *value = NULL;
+ GVariant *result;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ if (!wk_editor->priv->html_mode)
+ return NULL;
+
+ result = webkit_editor_get_element_attribute (
+ wk_editor, "#-x-evo-current-cell", "valign");
+ if (result) {
+ g_variant_get (result, "(s)", &value);
+ g_variant_unref (result);
+ }
+
+ return value;
+}
+
+static void
+webkit_editor_cell_set_align (EContentEditor *editor,
+ const gchar *value,
+ EContentEditorScope scope)
+{
+ EWebKitEditor *wk_editor;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ if (!wk_editor->priv->html_mode)
+ return;
+
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+ return;
+ }
+
+ g_dbus_proxy_call (
+ wk_editor->priv->web_extension,
+ "EEditorCellDialogSetElementAlign",
+ g_variant_new ("(tsi)", current_page_id (wk_editor), value, (gint32) scope),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+}
+
+static gchar *
+webkit_editor_cell_get_align (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+ gchar *value = NULL;
+ GVariant *result;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ if (!wk_editor->priv->html_mode)
+ return NULL;
+
+ result = webkit_editor_get_element_attribute (
+ wk_editor, "#-x-evo-current-cell", "align");
+ if (result) {
+ g_variant_get (result, "(s)", &value);
+ g_variant_unref (result);
+ }
+
+ return value;
+}
+
+static void
+webkit_editor_cell_set_wrap (EContentEditor *editor,
+ gboolean value,
+ EContentEditorScope scope)
+{
+ EWebKitEditor *wk_editor;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ if (!wk_editor->priv->html_mode)
+ return;
+
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+ return;
+ }
+
+ g_dbus_proxy_call (
+ wk_editor->priv->web_extension,
+ "EEditorCellDialogSetElementNoWrap",
+ g_variant_new ("(tbi)", current_page_id (wk_editor), !value, (gint32) scope),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+}
+
+static gboolean
+webkit_editor_cell_get_wrap (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+ gboolean value = FALSE;
+ GVariant *result;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ if (!wk_editor->priv->html_mode)
+ return FALSE;
+
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+ return FALSE;
+ }
+
+ result = g_dbus_proxy_call_sync_wrapper (
+ wk_editor->priv->web_extension,
+ "TableCellElementGetNoWrap",
+ g_variant_new ("(ts)", current_page_id (wk_editor), "-x-evo-current-cell"),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL);
+
+ if (result) {
+ g_variant_get (result, "(b)", &value);
+ value = !value;
+ g_variant_unref (result);
+ }
+
+ return value;
+}
+
+static void
+webkit_editor_cell_set_header_style (EContentEditor *editor,
+ gboolean value,
+ EContentEditorScope scope)
+{
+ EWebKitEditor *wk_editor;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+ return;
+ }
+
+ if (!wk_editor->priv->html_mode)
+ return;
+
+ g_dbus_proxy_call (
+ wk_editor->priv->web_extension,
+ "EEditorCellDialogSetElementHeaderStyle",
+ g_variant_new ("(tbi)", current_page_id (wk_editor), value, (gint32) scope),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+}
+
+static gboolean
+webkit_editor_cell_is_header (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+ gboolean value = FALSE;
+ GVariant *result;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ if (!wk_editor->priv->html_mode)
+ return FALSE;
+
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+ return FALSE;
+ }
+
+ result = g_dbus_proxy_call_sync_wrapper (
+ wk_editor->priv->web_extension,
+ "ElementGetTagName",
+ g_variant_new ("(ts)", current_page_id (wk_editor), "-x-evo-current-cell"),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL);
+
+ if (result) {
+ const gchar *tag_name;
+
+ g_variant_get (result, "(&s)", &tag_name);
+ value = g_ascii_strncasecmp (tag_name, "TH", 2) == 0;
+ g_variant_unref (result);
+ }
+
+ return value;
+}
+
+static gint
+webkit_editor_cell_get_width (EContentEditor *editor,
+ EContentEditorUnit *unit)
+{
+ EWebKitEditor *wk_editor;
+ gint value = 0;
+ GVariant *result;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ *unit = E_CONTENT_EDITOR_UNIT_AUTO;
+
+ if (!wk_editor->priv->html_mode)
+ return 0;
+
+ result = webkit_editor_get_element_attribute (
+ wk_editor, "#-x-evo-current-cell", "width");
+
+ if (result) {
+ const gchar *width;
+
+ g_variant_get (result, "(&s)", &width);
+ if (width && *width) {
+ value = atoi (width);
+ if (strstr (width, "%"))
+ *unit = E_CONTENT_EDITOR_UNIT_PERCENTAGE;
+ else if (g_ascii_strncasecmp (width, "auto", 4) != 0)
+ *unit = E_CONTENT_EDITOR_UNIT_PIXEL;
+ }
+ g_variant_unref (result);
+ }
+
+ return value;
+}
+
+static gint
+webkit_editor_cell_get_row_span (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+ gint value = 0;
+ GVariant *result;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ if (!wk_editor->priv->html_mode)
+ return 0;
+
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+ return 0;
+ }
+
+ result = g_dbus_proxy_call_sync_wrapper (
+ wk_editor->priv->web_extension,
+ "TableCellElementGetRowSpan",
+ g_variant_new ("(ts)", current_page_id (wk_editor), "-x-evo-current-cell"),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL);
+
+ if (result) {
+ g_variant_get (result, "(i)", &value);
+ g_variant_unref (result);
+ }
+
+ return value;
+}
+
+static gint
+webkit_editor_cell_get_col_span (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+ gint value = 0;
+ GVariant *result;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ if (!wk_editor->priv->html_mode)
+ return 0;
+
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+ return 0;
+ }
+
+ result = g_dbus_proxy_call_sync_wrapper (
+ wk_editor->priv->web_extension,
+ "TableCellElementGetColSpan",
+ g_variant_new ("(ts)", current_page_id (wk_editor), "-x-evo-current-cell"),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL);
+
+ if (result) {
+ g_variant_get (result, "(i)", &value);
+ g_variant_unref (result);
+ }
+
+ return value;
+}
+
+static gchar *
+webkit_editor_cell_get_background_image_uri (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+ GVariant *result;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ if (!wk_editor->priv->html_mode)
+ return NULL;
+
+ result = webkit_editor_get_element_attribute (
+ wk_editor, "#-x-evo-current-cell", "data-uri");
+ if (result) {
+ gchar *value;
+
+ g_variant_get (result, "(s)", &value);
+ g_variant_unref (result);
+ }
+
+ return NULL;
+}
+
+static void
+webkit_editor_cell_get_background_color (EContentEditor *editor,
+ GdkRGBA *color)
+{
+ EWebKitEditor *wk_editor;
+ GVariant *result;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ if (!wk_editor->priv->html_mode)
+ goto exit;
+
+ result = webkit_editor_get_element_attribute (
+ wk_editor, "#-x-evo-current-cell", "bgcolor");
+ if (result) {
+ const gchar *value;
+
+ g_variant_get (result, "(&s)", &value);
+ if (!value || !*value || !gdk_rgba_parse (color, value)) {
+ g_variant_unref (result);
+ goto exit;
+ }
+ g_variant_unref (result);
+ return;
+ }
+
+ exit:
+ *color = transparent;
+}
+
+static void
+webkit_editor_cell_set_row_span (EContentEditor *editor,
+ gint value,
+ EContentEditorScope scope)
+{
+ EWebKitEditor *wk_editor;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ if (!wk_editor->priv->html_mode)
+ return;
+
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+ return;
+ }
+
+ g_dbus_proxy_call (
+ wk_editor->priv->web_extension,
+ "EEditorCellDialogSetElementRowSpan",
+ g_variant_new ("(tii)", current_page_id (wk_editor), value, (gint32) scope),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+}
+
+static void
+webkit_editor_cell_set_col_span (EContentEditor *editor,
+ gint value,
+ EContentEditorScope scope)
+{
+ EWebKitEditor *wk_editor;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ if (!wk_editor->priv->html_mode)
+ return;
+
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+ return;
+ }
+
+ g_dbus_proxy_call (
+ wk_editor->priv->web_extension,
+ "EEditorCellDialogSetElementColSpan",
+ g_variant_new ("(tii)", current_page_id (wk_editor), value, (gint32) scope),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+}
+
+static void
+webkit_editor_cell_set_width (EContentEditor *editor,
+ gint value,
+ EContentEditorUnit unit,
+ EContentEditorScope scope)
+{
+ EWebKitEditor *wk_editor;
+ gchar *width;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ if (!wk_editor->priv->html_mode)
+ return;
+
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+ return;
+ }
+
+ if (unit == E_CONTENT_EDITOR_UNIT_AUTO)
+ width = g_strdup ("auto");
+ else
+ width = g_strdup_printf (
+ "%d%s",
+ value,
+ (unit == E_CONTENT_EDITOR_UNIT_PIXEL) ? "px" : "%");
+
+ g_dbus_proxy_call (
+ wk_editor->priv->web_extension,
+ "EEditorCellDialogSetElementWidth",
+ g_variant_new ("(tsi)", current_page_id (wk_editor), width, (gint32) scope),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+
+ g_free (width);
+}
+
+static void
+webkit_editor_cell_set_background_color (EContentEditor *editor,
+ const GdkRGBA *value,
+ EContentEditorScope scope)
+{
+ EWebKitEditor *wk_editor;
+ gchar *color;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+ return;
+ }
+
+ if (value->alpha != 0.0)
+ color = g_strdup_printf ("#%06x", e_rgba_to_value (value));
+ else
+ color = g_strdup ("");
+
+ g_dbus_proxy_call (
+ wk_editor->priv->web_extension,
+ "EEditorCellDialogSetElementBgColor",
+ g_variant_new ("(tsi)", current_page_id (wk_editor), color, (gint32) scope),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+
+ g_free (color);
+}
+
+static void
+webkit_editor_cell_set_background_image_uri (EContentEditor *editor,
+ const gchar *uri)
+{
+ EWebKitEditor *wk_editor;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+ return;
+ }
+
+ if (!wk_editor->priv->html_mode)
+ return;
+
+ if (uri && *uri)
+ webkit_editor_replace_image_src (wk_editor, "#-x-evo-current-cell", uri);
+ else {
+ g_dbus_proxy_call (
+ wk_editor->priv->web_extension,
+ "RemoveImageAttributesFromElementBySelector",
+ g_variant_new ("(ts)", current_page_id (wk_editor), "#-x-evo-current-cell"),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+ }
+}
+
+static void
+webkit_editor_table_set_row_count (EContentEditor *editor,
+ guint value)
+{
+ EWebKitEditor *wk_editor;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ if (!wk_editor->priv->html_mode)
+ return;
+
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+ return;
+ }
+
+ g_dbus_proxy_call (
+ wk_editor->priv->web_extension,
+ "EEditorTableDialogSetRowCount",
+ g_variant_new ("(tu)", current_page_id (wk_editor), value),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+}
+
+static guint
+webkit_editor_table_get_row_count (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+ GVariant *result;
+ guint value = 0;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ if (!wk_editor->priv->html_mode)
+ return 0;
+
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+ return 0;
+ }
+
+ result = g_dbus_proxy_call_sync_wrapper (
+ wk_editor->priv->web_extension,
+ "EEditorTableDialogGetRowCount",
+ g_variant_new ("(t)", current_page_id (wk_editor)),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL);
+
+ if (result) {
+ g_variant_get (result, "(u)", &value);
+ g_variant_unref (result);
+ }
+
+ return value;
+}
+
+static void
+webkit_editor_table_set_column_count (EContentEditor *editor,
+ guint value)
+{
+ EWebKitEditor *wk_editor;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ if (!wk_editor->priv->html_mode)
+ return;
+
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+ return;
+ }
+
+ g_dbus_proxy_call (
+ wk_editor->priv->web_extension,
+ "EEditorTableDialogSetColumnCount",
+ g_variant_new ("(tu)", current_page_id (wk_editor), value),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+}
+
+static guint
+webkit_editor_table_get_column_count (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+ GVariant *result;
+ guint value = 0;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ if (!wk_editor->priv->html_mode)
+ return 0;
+
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+ return 0;
+ }
+
+ result = g_dbus_proxy_call_sync_wrapper (
+ wk_editor->priv->web_extension,
+ "EEditorTableDialogGetColumnCount",
+ g_variant_new ("(t)", current_page_id (wk_editor)),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL);
+
+ if (result) {
+ g_variant_get (result, "(u)", &value);
+ g_variant_unref (result);
+ }
+
+ return value;
+}
+
+static void
+webkit_editor_table_set_width (EContentEditor *editor,
+ gint value,
+ EContentEditorUnit unit)
+{
+ EWebKitEditor *wk_editor;
+ gchar *width;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ if (!wk_editor->priv->html_mode)
+ return;
+
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+ return;
+ }
+
+ if (unit == E_CONTENT_EDITOR_UNIT_AUTO)
+ width = g_strdup ("auto");
+ else
+ width = g_strdup_printf (
+ "%d%s",
+ value,
+ (unit == E_CONTENT_EDITOR_UNIT_PIXEL) ? "px" : "%");
+
+ webkit_editor_set_element_attribute (
+ wk_editor, "#-x-evo-current-table", "width", width);
+
+ g_free (width);
+}
+
+static guint
+webkit_editor_table_get_width (EContentEditor *editor,
+ EContentEditorUnit *unit)
+{
+ EWebKitEditor *wk_editor;
+ guint value = 0;
+ GVariant *result;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ *unit = E_CONTENT_EDITOR_UNIT_PIXEL;
+
+ if (!wk_editor->priv->html_mode)
+ return 0;
+
+ result = webkit_editor_get_element_attribute (
+ wk_editor, "#-x-evo-current-table", "width");
+
+ if (result) {
+ const gchar *width;
+
+ g_variant_get (result, "(&s)", &width);
+ if (width && *width) {
+ value = atoi (width);
+ if (strstr (width, "%"))
+ *unit = E_CONTENT_EDITOR_UNIT_PERCENTAGE;
+ else if (g_ascii_strncasecmp (width, "auto", 4) != 0)
+ *unit = E_CONTENT_EDITOR_UNIT_PIXEL;
+ }
+ g_variant_unref (result);
+ }
+
+ return value;
+}
+
+static void
+webkit_editor_table_set_align (EContentEditor *editor,
+ const gchar *value)
+{
+ EWebKitEditor *wk_editor;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ if (!wk_editor->priv->html_mode)
+ return;
+
+ webkit_editor_set_element_attribute (
+ wk_editor, "#-x-evo-current-table", "align", value);
+}
+
+static gchar *
+webkit_editor_table_get_align (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+ gchar *value = NULL;
+ GVariant *result;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ if (!wk_editor->priv->html_mode)
+ return NULL;
+
+ result = webkit_editor_get_element_attribute (
+ wk_editor, "#-x-evo-current-table", "align");
+ if (result) {
+ g_variant_get (result, "(s)", &value);
+ g_variant_unref (result);
+ }
+
+ return value;
+}
+
+static void
+webkit_editor_table_set_padding (EContentEditor *editor,
+ gint value)
+{
+ EWebKitEditor *wk_editor;
+ gchar *padding;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ padding = g_strdup_printf ("%d", value);
+
+ webkit_editor_set_element_attribute (
+ wk_editor, "#-x-evo-current-table", "cellpadding", padding);
+
+ g_free (padding);
+}
+
+static gint
+webkit_editor_table_get_padding (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+ GVariant *result;
+ gint value = 0;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ result = webkit_editor_get_element_attribute (
+ wk_editor, "#-x-evo-current-table", "cellpadding");
+
+ if (result) {
+ const gchar *padding;
+
+ g_variant_get (result, "(&s)", &padding);
+ if (padding && *padding)
+ value = atoi (padding);
+ g_variant_unref (result);
+ }
+
+ return value;
+}
+
+static void
+webkit_editor_table_set_spacing (EContentEditor *editor,
+ gint value)
+{
+ EWebKitEditor *wk_editor;
+ gchar *spacing;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ spacing = g_strdup_printf ("%d", value);
+
+ webkit_editor_set_element_attribute (
+ wk_editor, "#-x-evo-current-table", "cellspacing", spacing);
+
+ g_free (spacing);
+}
+
+static gint
+webkit_editor_table_get_spacing (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+ GVariant *result;
+ gint value = 0;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ result = webkit_editor_get_element_attribute (
+ wk_editor, "#-x-evo-current-table", "cellspacing");
+
+ if (result) {
+ const gchar *spacing;
+
+ g_variant_get (result, "(&s)", &spacing);
+ if (spacing && *spacing)
+ value = atoi (spacing);
+ g_variant_unref (result);
+ }
+
+ return value;
+}
+
+static void
+webkit_editor_table_set_border (EContentEditor *editor,
+ gint value)
+{
+ EWebKitEditor *wk_editor;
+ gchar *border;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ border = g_strdup_printf ("%d", value);
+
+ webkit_editor_set_element_attribute (
+ wk_editor, "#-x-evo-current-table", "border", border);
+
+ g_free (border);
+}
+
+static gint
+webkit_editor_table_get_border (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+ GVariant *result;
+ gint value = 0;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ result = webkit_editor_get_element_attribute (
+ wk_editor, "#-x-evo-current-table", "border");
+
+ if (result) {
+ const gchar *border;
+
+ g_variant_get (result, "(&s)", &border);
+ if (border && *border)
+ value = atoi (border);
+ g_variant_unref (result);
+ }
+
+ return value;
+}
+
+static void
+webkit_editor_table_get_background_color (EContentEditor *editor,
+ GdkRGBA *color)
+{
+ EWebKitEditor *wk_editor;
+ GVariant *result;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ if (!wk_editor->priv->html_mode)
+ goto exit;
+
+ result = webkit_editor_get_element_attribute (
+ wk_editor, "#-x-evo-current-table", "bgcolor");
+ if (result) {
+ const gchar *value;
+
+ g_variant_get (result, "(&s)", &value);
+ if (!value || !*value || !gdk_rgba_parse (color, value)) {
+ g_variant_unref (result);
+ goto exit;
+ }
+ g_variant_unref (result);
+ return;
+ }
+
+ exit:
+ *color = transparent;
+}
+
+static void
+webkit_editor_table_set_background_color (EContentEditor *editor,
+ const GdkRGBA *value)
+{
+ EWebKitEditor *wk_editor;
+ gchar *color;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+ return;
+ }
+
+ if (value->alpha != 0.0)
+ color = g_strdup_printf ("#%06x", e_rgba_to_value (value));
+ else
+ color = g_strdup ("");
+
+ webkit_editor_set_element_attribute (
+ wk_editor, "#-x-evo-current-table", "bgcolor", color);
+
+ g_free (color);
+}
+
+static gchar *
+webkit_editor_table_get_background_image_uri (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+ GVariant *result;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ if (!wk_editor->priv->html_mode)
+ return NULL;
+
+ result = webkit_editor_get_element_attribute (wk_editor, "#-x-evo-current-table", "data-uri");
+ if (result) {
+ gchar *value;
+
+ g_variant_get (result, "(s)", &value);
+ g_variant_unref (result);
+ }
+
+ return NULL;
+}
+
+static void
+webkit_editor_table_set_background_image_uri (EContentEditor *editor,
+ const gchar *uri)
+{
+ EWebKitEditor *wk_editor;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+ return;
+ }
+
+ if (!wk_editor->priv->html_mode)
+ return;
+
+ if (uri && *uri)
+ webkit_editor_replace_image_src (wk_editor, "#-x-evo-current-table", uri);
+ else {
+ g_dbus_proxy_call (
+ wk_editor->priv->web_extension,
+ "RemoveImageAttributesFromElementBySelector",
+ g_variant_new ("(ts)", current_page_id (wk_editor), "#-x-evo-current-table"),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+ }
+}
+
+static gboolean
+webkit_editor_on_table_dialog_open (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+ GVariant *result;
+ gboolean value = FALSE;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+ return FALSE;
+ }
+
+ result = g_dbus_proxy_call_sync_wrapper (
+ wk_editor->priv->web_extension,
+ "EEditorTableDialogShow",
+ g_variant_new ("(t)", current_page_id (wk_editor)),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL);
+
+ if (result) {
+ g_variant_get (result, "(b)", &value);
+ g_variant_unref (result);
+ }
+
+ return value;
+}
+
+static void
+webkit_editor_on_table_dialog_close (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ webkit_editor_call_simple_extension_function (
+ wk_editor, "EEditorTableDialogSaveHistoryOnExit");
+
+ webkit_editor_finish_search (E_WEBKIT_EDITOR (editor));
+}
+
+static void
+webkit_editor_on_spell_check_dialog_open (EContentEditor *editor)
+{
+}
+
+static void
+webkit_editor_on_spell_check_dialog_close (EContentEditor *editor)
+{
+ webkit_editor_finish_search (E_WEBKIT_EDITOR (editor));
+}
+
+static gchar *
+move_to_another_word (EContentEditor *editor,
+ const gchar *word,
+ const gchar *dom_function)
+{
+ EWebKitEditor *wk_editor;
+ gchar **active_languages;
+ gchar *another_word = NULL;
+ GVariant *result;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ if (!wk_editor->priv->web_extension) {
+ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+ return NULL;
+ }
+
+ active_languages = e_spell_checker_list_active_languages (
+ wk_editor->priv->spell_checker, NULL);
+ if (!active_languages)
+ return NULL;
+
+ result = g_dbus_proxy_call_sync_wrapper (
+ wk_editor->priv->web_extension,
+ dom_function,
+ g_variant_new (
+ "(ts^as)", current_page_id (wk_editor), word ? word : "", active_languages),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL);
+
+ g_strfreev (active_languages);
+
+ if (result) {
+ g_variant_get (result, "(s)", &another_word);
+ g_variant_unref (result);
+ }
+
+ return another_word;
+}
+
+static gchar *
+webkit_editor_spell_check_next_word (EContentEditor *editor,
+ const gchar *word)
+{
+ return move_to_another_word (editor, word, "EEditorSpellCheckDialogNext");
+}
+
+static gchar *
+webkit_editor_spell_check_prev_word (EContentEditor *editor,
+ const gchar *word)
+{
+ return move_to_another_word (editor, word, "EEditorSpellCheckDialogPrev");
+}
+
+static void
+webkit_editor_on_replace_dialog_open (EContentEditor *editor)
+{
+}
+
+static void
+webkit_editor_on_replace_dialog_close (EContentEditor *editor)
+{
+ webkit_editor_finish_search (E_WEBKIT_EDITOR (editor));
+}
+
+static void
+webkit_editor_on_find_dialog_open (EContentEditor *editor)
+{
+}
+
+static void
+webkit_editor_on_find_dialog_close (EContentEditor *editor)
+{
+ webkit_editor_finish_search (E_WEBKIT_EDITOR (editor));
+}
+
+static GDBusProxy *
+webkit_editor_get_web_extension (EWebKitEditor *wk_editor)
+{
+ g_return_val_if_fail (E_IS_WEBKIT_EDITOR (wk_editor), NULL);
+
+ return wk_editor->priv->web_extension;
+}
+
+static void
+webkit_editor_constructed (GObject *object)
+{
+ EWebKitEditor *wk_editor;
+ gchar **languages;
+ WebKitWebContext *web_context;
+ WebKitSettings *web_settings;
+ WebKitWebView *web_view;
+
+ G_OBJECT_CLASS (e_webkit_editor_parent_class)->constructed (object);
+
+ wk_editor = E_WEBKIT_EDITOR (object);
+ web_view = WEBKIT_WEB_VIEW (wk_editor);
+
+ /* Give spell check languages to WebKit */
+ languages = e_spell_checker_list_active_languages (wk_editor->priv->spell_checker, NULL);
+
+ web_context = webkit_web_view_get_context (web_view);
+ webkit_web_context_set_spell_checking_enabled (web_context, TRUE);
+ webkit_web_context_set_spell_checking_languages (web_context, (const gchar * const *) languages);
+ g_strfreev (languages);
+
+ webkit_web_view_set_editable (web_view, TRUE);
+
+ web_settings = webkit_web_view_get_settings (web_view);
+ webkit_settings_set_allow_file_access_from_file_urls (web_settings, TRUE);
+ webkit_settings_set_enable_developer_extras (web_settings, TRUE);
+
+ /* Make WebKit think we are displaying a local file, so that it
+ * does not block loading resources from file:// protocol */
+ webkit_web_view_load_html (WEBKIT_WEB_VIEW (object), "", "file://");
+}
+
+static GObjectConstructParam*
+find_property (guint n_properties,
+ GObjectConstructParam* properties,
+ GParamSpec* param_spec)
+{
+ while (n_properties--) {
+ if (properties->pspec == param_spec)
+ return properties;
+ properties++;
+ }
+
+ return NULL;
+}
+
+static GObject *
+webkit_editor_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_properties)
+{
+ GObjectClass* object_class;
+ GParamSpec* param_spec;
+ GObjectConstructParam *param = NULL;
+
+ object_class = G_OBJECT_CLASS (g_type_class_ref (type));
+ g_return_val_if_fail (object_class != NULL, NULL);
+
+ if (construct_properties && n_construct_properties != 0) {
+ param_spec = g_object_class_find_property (object_class, "settings");
+ if ((param = find_property (n_construct_properties, construct_properties, param_spec)))
+ g_value_take_object (param->value, e_web_view_get_default_webkit_settings ());
+ param_spec = g_object_class_find_property (object_class, "user-content-manager");
+ if ((param = find_property (n_construct_properties, construct_properties, param_spec)))
+ g_value_take_object (param->value, webkit_user_content_manager_new ());
+ param_spec = g_object_class_find_property (object_class, "web-context");
+ if ((param = find_property (n_construct_properties, construct_properties, param_spec))) {
+ /* Share one web_context between all editors, thus there is one WebProcess
+ for all the editors (and one for the preview). */
+ static gpointer web_context = NULL;
+
+ if (!web_context) {
+ web_context = webkit_web_context_new ();
+
+ webkit_web_context_set_cache_model (web_context,
WEBKIT_CACHE_MODEL_DOCUMENT_VIEWER);
+ webkit_web_context_set_web_extensions_directory (web_context,
EVOLUTION_WEB_EXTENSIONS_WEBKIT_EDITOR_DIR);
+
+ g_object_add_weak_pointer (G_OBJECT (web_context), &web_context);
+ } else {
+ g_object_ref (web_context);
+ }
+
+ g_value_take_object (param->value, web_context);
+ }
+ }
+
+ g_type_class_unref (object_class);
+
+ return G_OBJECT_CLASS (e_webkit_editor_parent_class)->constructor (type, n_construct_properties,
construct_properties);
+}
+
+static void
+webkit_editor_dispose (GObject *object)
+{
+ EWebKitEditorPrivate *priv;
+
+ priv = E_WEBKIT_EDITOR_GET_PRIVATE (object);
+
+ if (priv->aliasing_settings != NULL) {
+ g_signal_handlers_disconnect_by_data (priv->aliasing_settings, object);
+ g_object_unref (priv->aliasing_settings);
+ priv->aliasing_settings = NULL;
+ }
+
+ if (priv->current_user_stylesheet != NULL) {
+ g_free (priv->current_user_stylesheet);
+ priv->current_user_stylesheet = NULL;
+ }
+
+ if (priv->font_settings != NULL) {
+ g_signal_handlers_disconnect_by_data (priv->font_settings, object);
+ g_object_unref (priv->font_settings);
+ priv->font_settings = NULL;
+ }
+
+ if (priv->mail_settings != NULL) {
+ g_signal_handlers_disconnect_by_data (priv->mail_settings, object);
+ g_object_unref (priv->mail_settings);
+ priv->mail_settings = NULL;
+ }
+
+ if (priv->web_extension_content_changed_cb_id > 0) {
+ g_dbus_connection_signal_unsubscribe (
+ g_dbus_proxy_get_connection (priv->web_extension),
+ priv->web_extension_content_changed_cb_id);
+ priv->web_extension_content_changed_cb_id = 0;
+ }
+
+ if (priv->web_extension_selection_changed_cb_id > 0) {
+ g_dbus_connection_signal_unsubscribe (
+ g_dbus_proxy_get_connection (priv->web_extension),
+ priv->web_extension_selection_changed_cb_id);
+ priv->web_extension_selection_changed_cb_id = 0;
+ }
+
+ if (priv->web_extension_undo_redo_state_changed_cb_id > 0) {
+ g_dbus_connection_signal_unsubscribe (
+ g_dbus_proxy_get_connection (priv->web_extension),
+ priv->web_extension_undo_redo_state_changed_cb_id);
+ priv->web_extension_undo_redo_state_changed_cb_id = 0;
+ }
+
+ if (priv->web_extension_watch_name_id > 0) {
+ g_bus_unwatch_name (priv->web_extension_watch_name_id);
+ priv->web_extension_watch_name_id = 0;
+ }
+
+ if (priv->owner_change_clipboard_cb_id > 0) {
+ g_signal_handler_disconnect (
+ gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
+ priv->owner_change_clipboard_cb_id);
+ priv->owner_change_clipboard_cb_id = 0;
+ }
+
+ if (priv->owner_change_primary_clipboard_cb_id > 0) {
+ g_signal_handler_disconnect (
+ gtk_clipboard_get (GDK_SELECTION_PRIMARY),
+ priv->owner_change_primary_clipboard_cb_id);
+ priv->owner_change_primary_clipboard_cb_id = 0;
+ }
+
+ webkit_editor_finish_search (E_WEBKIT_EDITOR (object));
+
+ g_clear_object (&priv->web_extension);
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (e_webkit_editor_parent_class)->dispose (object);
+}
+
+static void
+webkit_editor_finalize (GObject *object)
+{
+ EWebKitEditorPrivate *priv;
+
+ priv = E_WEBKIT_EDITOR_GET_PRIVATE (object);
+
+ if (priv->old_settings) {
+ g_hash_table_destroy (priv->old_settings);
+ priv->old_settings = NULL;
+ }
+
+ if (priv->post_reload_operations) {
+ g_warn_if_fail (g_queue_is_empty (priv->post_reload_operations));
+
+ g_queue_free (priv->post_reload_operations);
+ priv->post_reload_operations = NULL;
+ }
+
+ if (priv->background_color != NULL) {
+ gdk_rgba_free (priv->background_color);
+ priv->background_color = NULL;
+ }
+
+ if (priv->font_color != NULL) {
+ gdk_rgba_free (priv->font_color);
+ priv->font_color = NULL;
+ }
+
+ g_clear_object (&priv->spell_checker);
+
+ g_free (priv->font_name);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (e_webkit_editor_parent_class)->finalize (object);
+}
+
+static void
+webkit_editor_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_CHANGED:
+ webkit_editor_set_changed (
+ E_WEBKIT_EDITOR (object),
+ g_value_get_boolean (value));
+ return;
+
+ case PROP_EDITABLE:
+ webkit_editor_set_editable (
+ E_WEBKIT_EDITOR (object),
+ g_value_get_boolean (value));
+ return;
+
+ case PROP_HTML_MODE:
+ webkit_editor_set_html_mode (
+ E_WEBKIT_EDITOR (object),
+ g_value_get_boolean (value));
+ return;
+
+ case PROP_ALIGNMENT:
+ webkit_editor_set_alignment (
+ E_WEBKIT_EDITOR (object),
+ g_value_get_enum (value));
+ return;
+
+ case PROP_BACKGROUND_COLOR:
+ webkit_editor_set_background_color (
+ E_WEBKIT_EDITOR (object),
+ g_value_get_boxed (value));
+ return;
+
+ case PROP_BOLD:
+ webkit_editor_set_style_flag (
+ E_WEBKIT_EDITOR (object),
+ E_CONTENT_EDITOR_STYLE_IS_BOLD,
+ g_value_get_boolean (value),
+ "DOMSelectionSetBold");
+ return;
+
+ case PROP_FONT_COLOR:
+ webkit_editor_set_font_color (
+ E_WEBKIT_EDITOR (object),
+ g_value_get_boxed (value));
+ return;
+
+ case PROP_BLOCK_FORMAT:
+ webkit_editor_set_block_format (
+ E_WEBKIT_EDITOR (object),
+ g_value_get_enum (value));
+ return;
+
+ case PROP_FONT_NAME:
+ webkit_editor_set_font_name (
+ E_WEBKIT_EDITOR (object),
+ g_value_get_string (value));
+ return;
+
+ case PROP_FONT_SIZE:
+ webkit_editor_set_font_size (
+ E_WEBKIT_EDITOR (object),
+ g_value_get_int (value));
+ return;
+
+ case PROP_ITALIC:
+ webkit_editor_set_style_flag (
+ E_WEBKIT_EDITOR (object),
+ E_CONTENT_EDITOR_STYLE_IS_ITALIC,
+ g_value_get_boolean (value),
+ "DOMSelectionSetItalic");
+ return;
+
+ case PROP_MONOSPACED:
+ webkit_editor_set_style_flag (
+ E_WEBKIT_EDITOR (object),
+ E_CONTENT_EDITOR_STYLE_IS_MONOSPACE,
+ g_value_get_boolean (value),
+ "DOMSelectionSetMonospaced");
+ return;
+
+ case PROP_STRIKETHROUGH:
+ webkit_editor_set_style_flag (
+ E_WEBKIT_EDITOR (object),
+ E_CONTENT_EDITOR_STYLE_IS_STRIKETHROUGH,
+ g_value_get_boolean (value),
+ "DOMSelectionSetStrikethrough");
+ return;
+
+ case PROP_SUBSCRIPT:
+ webkit_editor_set_style_flag (
+ E_WEBKIT_EDITOR (object),
+ E_CONTENT_EDITOR_STYLE_IS_SUBSCRIPT,
+ g_value_get_boolean (value),
+ "DOMSelectionSetSubscript");
+ return;
+
+ case PROP_SUPERSCRIPT:
+ webkit_editor_set_style_flag (
+ E_WEBKIT_EDITOR (object),
+ E_CONTENT_EDITOR_STYLE_IS_SUPERSCRIPT,
+ g_value_get_boolean (value),
+ "DOMSelectionSetSuperscript");
+ return;
+
+ case PROP_UNDERLINE:
+ webkit_editor_set_style_flag (
+ E_WEBKIT_EDITOR (object),
+ E_CONTENT_EDITOR_STYLE_IS_UNDERLINE,
+ g_value_get_boolean (value),
+ "DOMSelectionSetUnderline");
+ return;
+
+ case PROP_SPELL_CHECK_ENABLED:
+ webkit_editor_set_spell_check_enabled (
+ E_WEBKIT_EDITOR (object),
+ g_value_get_boolean (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+webkit_editor_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_WEB_EXTENSION:
+ g_value_set_object (
+ value, webkit_editor_get_web_extension (
+ E_WEBKIT_EDITOR (object)));
+ return;
+
+ case PROP_CAN_COPY:
+ g_value_set_boolean (
+ value, webkit_editor_can_copy (
+ E_WEBKIT_EDITOR (object)));
+ return;
+
+ case PROP_CAN_CUT:
+ g_value_set_boolean (
+ value, webkit_editor_can_cut (
+ E_WEBKIT_EDITOR (object)));
+ return;
+
+ case PROP_CAN_PASTE:
+ g_value_set_boolean (
+ value, webkit_editor_can_paste (
+ E_WEBKIT_EDITOR (object)));
+ return;
+
+ case PROP_CAN_REDO:
+ g_value_set_boolean (
+ value, webkit_editor_can_redo (
+ E_WEBKIT_EDITOR (object)));
+ return;
+
+ case PROP_CAN_UNDO:
+ g_value_set_boolean (
+ value, webkit_editor_can_undo (
+ E_WEBKIT_EDITOR (object)));
+ return;
+
+ case PROP_CHANGED:
+ g_value_set_boolean (
+ value, webkit_editor_get_changed (
+ E_WEBKIT_EDITOR (object)));
+ return;
+
+ case PROP_HTML_MODE:
+ g_value_set_boolean (
+ value, webkit_editor_get_html_mode (
+ E_WEBKIT_EDITOR (object)));
+ return;
+
+ case PROP_EDITABLE:
+ g_value_set_boolean (
+ value, webkit_editor_is_editable (
+ E_WEBKIT_EDITOR (object)));
+ return;
+
+ case PROP_ALIGNMENT:
+ g_value_set_enum (
+ value,
+ webkit_editor_get_alignment (
+ E_WEBKIT_EDITOR (object)));
+ return;
+
+ case PROP_BACKGROUND_COLOR:
+ g_value_set_boxed (
+ value,
+ webkit_editor_get_background_color (
+ E_WEBKIT_EDITOR (object)));
+ return;
+
+ case PROP_BLOCK_FORMAT:
+ g_value_set_enum (
+ value,
+ webkit_editor_get_block_format (
+ E_WEBKIT_EDITOR (object)));
+ return;
+
+ case PROP_BOLD:
+ g_value_set_boolean (
+ value,
+ webkit_editor_get_style_flag (
+ E_WEBKIT_EDITOR (object),
+ E_CONTENT_EDITOR_STYLE_IS_BOLD));
+ return;
+
+ case PROP_FONT_COLOR:
+ g_value_set_boxed (
+ value,
+ webkit_editor_get_font_color (
+ E_WEBKIT_EDITOR (object)));
+ return;
+
+ case PROP_FONT_NAME:
+ g_value_set_string (
+ value,
+ webkit_editor_get_font_name (
+ E_WEBKIT_EDITOR (object)));
+ return;
+
+ case PROP_FONT_SIZE:
+ g_value_set_int (
+ value,
+ webkit_editor_get_font_size (
+ E_WEBKIT_EDITOR (object)));
+ return;
+
+ case PROP_INDENTED:
+ g_value_set_boolean (
+ value,
+ webkit_editor_selection_is_indented (
+ E_WEBKIT_EDITOR (object)));
+ return;
+
+ case PROP_ITALIC:
+ g_value_set_boolean (
+ value,
+ webkit_editor_get_style_flag (
+ E_WEBKIT_EDITOR (object),
+ E_CONTENT_EDITOR_STYLE_IS_ITALIC));
+ return;
+
+ case PROP_MONOSPACED:
+ g_value_set_boolean (
+ value,
+ webkit_editor_get_style_flag (
+ E_WEBKIT_EDITOR (object),
+ E_CONTENT_EDITOR_STYLE_IS_MONOSPACE));
+ return;
+
+ case PROP_STRIKETHROUGH:
+ g_value_set_boolean (
+ value,
+ webkit_editor_get_style_flag (
+ E_WEBKIT_EDITOR (object),
+ E_CONTENT_EDITOR_STYLE_IS_STRIKETHROUGH));
+ return;
+
+ case PROP_SUBSCRIPT:
+ g_value_set_boolean (
+ value,
+ webkit_editor_get_style_flag (
+ E_WEBKIT_EDITOR (object),
+ E_CONTENT_EDITOR_STYLE_IS_SUBSCRIPT));
+ return;
+
+ case PROP_SUPERSCRIPT:
+ g_value_set_boolean (
+ value,
+ webkit_editor_get_style_flag (
+ E_WEBKIT_EDITOR (object),
+ E_CONTENT_EDITOR_STYLE_IS_SUPERSCRIPT));
+ return;
+
+ case PROP_UNDERLINE:
+ g_value_set_boolean (
+ value,
+ webkit_editor_get_style_flag (
+ E_WEBKIT_EDITOR (object),
+ E_CONTENT_EDITOR_STYLE_IS_UNDERLINE));
+ return;
+
+ case PROP_SPELL_CHECK_ENABLED:
+ g_value_set_boolean (
+ value,
+ webkit_editor_get_spell_check_enabled (
+ E_WEBKIT_EDITOR (object)));
+ return;
+
+ case PROP_SPELL_CHECKER:
+ g_value_set_object (
+ value,
+ webkit_editor_get_spell_checker (
+ E_WEBKIT_EDITOR (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+webkit_editor_move_caret_on_current_coordinates (GtkWidget *widget)
+{
+ gint x, y;
+ GdkDeviceManager *device_manager;
+ GdkDevice *pointer;
+
+ device_manager = gdk_display_get_device_manager (gtk_widget_get_display (widget));
+ pointer = gdk_device_manager_get_client_pointer (device_manager);
+ gdk_window_get_device_position (
+ gtk_widget_get_window (widget), pointer, &x, &y, NULL);
+ webkit_editor_move_caret_on_coordinates
+ (E_CONTENT_EDITOR (widget), x, y, TRUE);
+}
+
+static void
+webkit_editor_settings_changed_cb (GSettings *settings,
+ const gchar *key,
+ EWebKitEditor *wk_editor)
+{
+ GVariant *new_value, *old_value;
+
+ new_value = g_settings_get_value (settings, key);
+ old_value = g_hash_table_lookup (wk_editor->priv->old_settings, key);
+
+ if (!new_value || !old_value || !g_variant_equal (new_value, old_value)) {
+ if (new_value)
+ g_hash_table_insert (wk_editor->priv->old_settings, g_strdup (key), new_value);
+ else
+ g_hash_table_remove (wk_editor->priv->old_settings, key);
+
+ webkit_editor_update_styles (E_CONTENT_EDITOR (wk_editor));
+ } else if (new_value) {
+ g_variant_unref (new_value);
+ }
+}
+
+static void
+webkit_editor_load_changed_cb (EWebKitEditor *wk_editor,
+ WebKitLoadEvent load_event)
+{
+ wk_editor->priv->webkit_load_event = load_event;
+
+ if (load_event != WEBKIT_LOAD_FINISHED)
+ return;
+
+ if (wk_editor->priv->web_extension)
+ e_content_editor_emit_load_finished (E_CONTENT_EDITOR (wk_editor));
+ else
+ wk_editor->priv->emit_load_finished_when_extension_is_ready = TRUE;
+
+ wk_editor->priv->reload_in_progress = FALSE;
+
+ dispatch_pending_operations (wk_editor);
+}
+
+static void
+webkit_editor_clipboard_owner_change_cb (GtkClipboard *clipboard,
+ GdkEventOwnerChange *event,
+ EWebKitEditor *wk_editor)
+{
+ if (!E_IS_WEBKIT_EDITOR (wk_editor))
+ return;
+
+ if (!wk_editor->priv->web_extension)
+ return;
+
+ if (wk_editor->priv->copy_cut_actions_triggered && event->owner)
+ wk_editor->priv->copy_paste_clipboard_in_view = TRUE;
+ else
+ wk_editor->priv->copy_paste_clipboard_in_view = FALSE;
+
+ if (wk_editor->priv->copy_paste_clipboard_in_view ==
wk_editor->priv->pasting_from_itself_extension_value)
+ return;
+
+ g_dbus_proxy_call (
+ wk_editor->priv->web_extension,
+ "SetPastingContentFromItself",
+ g_variant_new (
+ "(tb)",
+ current_page_id (wk_editor),
+ wk_editor->priv->copy_paste_clipboard_in_view),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+
+ wk_editor->priv->copy_cut_actions_triggered = FALSE;
+
+ wk_editor->priv->pasting_from_itself_extension_value = wk_editor->priv->copy_paste_clipboard_in_view;
+}
+
+static void
+webkit_editor_primary_clipboard_owner_change_cb (GtkClipboard *clipboard,
+ GdkEventOwnerChange *event,
+ EWebKitEditor *wk_editor)
+{
+ if (!E_IS_WEBKIT_EDITOR (wk_editor) ||
+ !wk_editor->priv->web_extension)
+ return;
+
+ if (!event->owner || !wk_editor->priv->can_copy)
+ wk_editor->priv->copy_paste_clipboard_in_view = FALSE;
+
+ if (wk_editor->priv->copy_paste_clipboard_in_view ==
wk_editor->priv->pasting_from_itself_extension_value)
+ return;
+
+ g_dbus_proxy_call (
+ wk_editor->priv->web_extension,
+ "SetPastingContentFromItself",
+ g_variant_new (
+ "(tb)",
+ current_page_id (wk_editor),
+ wk_editor->priv->copy_paste_clipboard_in_view),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+
+ wk_editor->priv->pasting_from_itself_extension_value = wk_editor->priv->copy_paste_clipboard_in_view;
+}
+
+static gboolean
+webkit_editor_paste_prefer_text_html (EWebKitEditor *wk_editor)
+{
+ if (wk_editor->priv->pasting_primary_clipboard)
+ return wk_editor->priv->copy_paste_primary_in_view;
+ else
+ return wk_editor->priv->copy_paste_clipboard_in_view;
+}
+
+static void
+webkit_editor_paste_clipboard_targets_cb (GtkClipboard *clipboard,
+ GdkAtom *targets,
+ gint n_targets,
+ EWebKitEditor *wk_editor)
+{
+ if (targets == NULL || n_targets < 0)
+ return;
+
+ /* If view doesn't have focus, focus it */
+ if (!gtk_widget_has_focus (GTK_WIDGET (wk_editor)))
+ gtk_widget_grab_focus (GTK_WIDGET (wk_editor));
+
+ /* Order is important here to ensure common use cases are
+ * handled correctly. See GNOME bug #603715 for details. */
+ /* Prefer plain text over HTML when in the plain text mode, but only
+ * when pasting content from outside the editor view. */
+ if (wk_editor->priv->html_mode ||
+ webkit_editor_paste_prefer_text_html (wk_editor)) {
+ gchar *content = NULL;
+
+ if (e_targets_include_html (targets, n_targets)) {
+ if (!(content = e_clipboard_wait_for_html (clipboard)))
+ return;
+
+ webkit_editor_insert_content (
+ E_CONTENT_EDITOR (wk_editor),
+ content,
+ E_CONTENT_EDITOR_INSERT_TEXT_HTML);
+
+ g_free (content);
+ return;
+ }
+
+ if (gtk_targets_include_text (targets, n_targets)) {
+ if (!(content = gtk_clipboard_wait_for_text (clipboard)))
+ return;
+
+ webkit_editor_insert_content (
+ E_CONTENT_EDITOR (wk_editor),
+ content,
+ E_CONTENT_EDITOR_INSERT_TEXT_PLAIN |
+ E_CONTENT_EDITOR_INSERT_CONVERT);
+
+ g_free (content);
+ return;
+ }
+ } else {
+ gchar *content = NULL;
+
+ if (gtk_targets_include_text (targets, n_targets)) {
+ if (!(content = gtk_clipboard_wait_for_text (clipboard)))
+ return;
+
+ webkit_editor_insert_content (
+ E_CONTENT_EDITOR (wk_editor),
+ content,
+ E_CONTENT_EDITOR_INSERT_TEXT_PLAIN |
+ E_CONTENT_EDITOR_INSERT_CONVERT);
+
+ g_free (content);
+ return;
+ }
+
+ if (e_targets_include_html (targets, n_targets)) {
+ if (!(content = e_clipboard_wait_for_html (clipboard)))
+ return;
+
+ webkit_editor_insert_content (
+ E_CONTENT_EDITOR (wk_editor),
+ content,
+ E_CONTENT_EDITOR_INSERT_TEXT_HTML);
+
+ g_free (content);
+ return;
+ }
+ }
+
+ if (gtk_targets_include_image (targets, n_targets, TRUE)) {
+ gchar *uri;
+
+ if (!(uri = e_util_save_image_from_clipboard (clipboard)))
+ return;
+
+ webkit_editor_insert_image (E_CONTENT_EDITOR (wk_editor), uri);
+
+ g_free (uri);
+
+ return;
+ }
+}
+
+static void
+webkit_editor_paste_primary (EContentEditor *editor)
+{
+
+ GtkClipboard *clipboard;
+ EWebKitEditor *wk_editor;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ /* Remember, that we are pasting primary clipboard to return
+ * correct value in e_html_editor_view_is_pasting_content_from_itself. */
+ wk_editor->priv->pasting_primary_clipboard = TRUE;
+
+ webkit_editor_move_caret_on_current_coordinates (GTK_WIDGET (wk_editor));
+
+ clipboard = gtk_clipboard_get (GDK_SELECTION_PRIMARY);
+
+ gtk_clipboard_request_targets (
+ clipboard, (GtkClipboardTargetsReceivedFunc)
+ webkit_editor_paste_clipboard_targets_cb, wk_editor);
+}
+
+static void
+webkit_editor_paste (EContentEditor *editor)
+{
+ GtkClipboard *clipboard;
+ EWebKitEditor *wk_editor;
+
+ wk_editor = E_WEBKIT_EDITOR (editor);
+
+ clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
+
+ gtk_clipboard_request_targets (
+ clipboard, (GtkClipboardTargetsReceivedFunc)
+ webkit_editor_paste_clipboard_targets_cb, wk_editor);
+}
+
+static void
+webkit_editor_mouse_target_changed_cb (EWebKitEditor *wk_editor,
+ WebKitHitTestResult *hit_test_result,
+ guint modifiers,
+ gpointer user_data)
+{
+ /* Ctrl + Left Click on link opens it. */
+ if (webkit_hit_test_result_context_is_link (hit_test_result) &&
+ (modifiers & GDK_CONTROL_MASK)) {
+ GdkScreen *screen;
+ const gchar *uri;
+ GtkWidget *toplevel;
+
+ toplevel = gtk_widget_get_toplevel (GTK_WIDGET (wk_editor));
+ screen = gtk_window_get_screen (GTK_WINDOW (toplevel));
+
+ uri = webkit_hit_test_result_get_link_uri (hit_test_result);
+
+ gtk_show_uri (screen, uri, GDK_CURRENT_TIME, NULL);
+ }
+}
+
+static gboolean
+webkit_editor_context_menu_cb (EWebKitEditor *wk_editor,
+ WebKitContextMenu *context_menu,
+ GdkEvent *event,
+ WebKitHitTestResult *hit_test_result)
+{
+ GVariant *result;
+ EContentEditorNodeFlags flags = 0;
+ gboolean handled;
+
+ webkit_context_menu_remove_all (context_menu);
+
+ if ((result = webkit_context_menu_get_user_data (context_menu)))
+ flags = g_variant_get_int32 (result);
+
+ handled = e_content_editor_emit_context_menu_requested (E_CONTENT_EDITOR (wk_editor), flags, event);
+
+ return handled;
+}
+
+static void
+webkit_editor_drag_end_cb (EWebKitEditor *wk_editor,
+ GdkDragContext *context)
+{
+ webkit_editor_call_simple_extension_function (wk_editor, "DOMDragAndDropEnd");
+}
+
+static void
+webkit_editor_web_process_crashed_cb (EWebKitEditor *wk_editor)
+{
+ g_warning (
+ "WebKitWebProcess (page id %ld) for EWebKitEditor crashed",
+ webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (wk_editor)));
+
+ wk_editor->priv->web_extension_selection_changed_cb_id = 0;
+ wk_editor->priv->web_extension_content_changed_cb_id = 0;
+ wk_editor->priv->web_extension_undo_redo_state_changed_cb_id = 0;
+}
+
+static gboolean
+webkit_editor_button_press_event (GtkWidget *widget,
+ GdkEventButton *event)
+{
+ if (event->button == 2) {
+ if (!e_content_editor_emit_paste_primary_clipboard (E_CONTENT_EDITOR (widget)))
+ webkit_editor_paste_primary (E_CONTENT_EDITOR( (widget)));
+
+ return TRUE;
+ }
+
+ /* Chain up to parent's button_press_event() method. */
+ return GTK_WIDGET_CLASS (e_webkit_editor_parent_class)->button_press_event (widget, event);
+}
+
+static gboolean
+webkit_editor_key_press_event (GtkWidget *widget,
+ GdkEventKey *event)
+{
+ EWebKitEditor *wk_editor;
+
+ wk_editor = E_WEBKIT_EDITOR (widget);
+
+ if ((((event)->state & GDK_SHIFT_MASK) &&
+ ((event)->keyval == GDK_KEY_Insert)) ||
+ (((event)->state & GDK_CONTROL_MASK) &&
+ ((event)->keyval == GDK_KEY_v))) {
+ if (!e_content_editor_emit_paste_clipboard (E_CONTENT_EDITOR (widget)))
+ webkit_editor_paste (E_CONTENT_EDITOR (widget));
+
+ return TRUE;
+ }
+
+ if (((event)->state & GDK_CONTROL_MASK) &&
+ ((event)->keyval == GDK_KEY_Insert)) {
+ webkit_editor_copy (E_CONTENT_EDITOR (wk_editor));
+ return TRUE;
+ }
+
+ if (((event)->state & GDK_CONTROL_MASK) &&
+ ((event)->keyval == GDK_KEY_z)) {
+ webkit_editor_undo (E_CONTENT_EDITOR (wk_editor));
+ return TRUE;
+ }
+
+ if (((event)->state & (GDK_CONTROL_MASK)) &&
+ ((event)->keyval == GDK_KEY_Z)) {
+ webkit_editor_redo (E_CONTENT_EDITOR (wk_editor));
+ return TRUE;
+ }
+
+ if (((event)->state & GDK_SHIFT_MASK) &&
+ ((event)->keyval == GDK_KEY_Delete)) {
+ webkit_editor_cut (E_CONTENT_EDITOR (wk_editor));
+ return TRUE;
+ }
+
+ if (((event)->state & GDK_CONTROL_MASK) &&
+ ((event)->state & GDK_SHIFT_MASK) &&
+ ((event)->keyval == GDK_KEY_I)) {
+ webkit_editor_show_inspector (wk_editor);
+ return TRUE;
+ }
+
+ /* Chain up to parent's key_press_event() method. */
+ return GTK_WIDGET_CLASS (e_webkit_editor_parent_class)->key_press_event (widget, event);
+}
+
+static void
+e_webkit_editor_class_init (EWebKitEditorClass *class)
+{
+ GObjectClass *object_class;
+ GtkWidgetClass *widget_class;
+
+ g_type_class_add_private (class, sizeof (EWebKitEditorPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->constructed = webkit_editor_constructed;
+ object_class->constructor = webkit_editor_constructor;
+ object_class->get_property = webkit_editor_get_property;
+ object_class->set_property = webkit_editor_set_property;
+ object_class->dispose = webkit_editor_dispose;
+ object_class->finalize = webkit_editor_finalize;
+
+ widget_class = GTK_WIDGET_CLASS (class);
+ widget_class->button_press_event = webkit_editor_button_press_event;
+ widget_class->key_press_event = webkit_editor_key_press_event;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_WEB_EXTENSION,
+ g_param_spec_object (
+ "web-extension",
+ "Web Extension",
+ "The Web Extension to use to talk to the WebProcess",
+ G_TYPE_DBUS_PROXY,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_override_property (
+ object_class, PROP_CAN_COPY, "can-copy");
+ g_object_class_override_property (
+ object_class, PROP_CAN_CUT, "can-cut");
+ g_object_class_override_property (
+ object_class, PROP_CAN_PASTE, "can-paste");
+ g_object_class_override_property (
+ object_class, PROP_CAN_REDO, "can-redo");
+ g_object_class_override_property (
+ object_class, PROP_CAN_UNDO, "can-undo");
+ g_object_class_override_property (
+ object_class, PROP_CHANGED, "changed");
+ g_object_class_override_property (
+ object_class, PROP_HTML_MODE, "html-mode");
+ g_object_class_override_property (
+ object_class, PROP_EDITABLE, "editable");
+ g_object_class_override_property (
+ object_class, PROP_ALIGNMENT, "alignment");
+ g_object_class_override_property (
+ object_class, PROP_BACKGROUND_COLOR, "background-color");
+ g_object_class_override_property (
+ object_class, PROP_BLOCK_FORMAT, "block-format");
+ g_object_class_override_property (
+ object_class, PROP_BOLD, "bold");
+ g_object_class_override_property (
+ object_class, PROP_FONT_COLOR, "font-color");
+ g_object_class_override_property (
+ object_class, PROP_FONT_NAME, "font-name");
+ g_object_class_override_property (
+ object_class, PROP_FONT_SIZE, "font-size");
+ g_object_class_override_property (
+ object_class, PROP_INDENTED, "indented");
+ g_object_class_override_property (
+ object_class, PROP_ITALIC, "italic");
+ g_object_class_override_property (
+ object_class, PROP_MONOSPACED, "monospaced");
+ g_object_class_override_property (
+ object_class, PROP_STRIKETHROUGH, "strikethrough");
+ g_object_class_override_property (
+ object_class, PROP_SUBSCRIPT, "subscript");
+ g_object_class_override_property (
+ object_class, PROP_SUPERSCRIPT, "superscript");
+ g_object_class_override_property (
+ object_class, PROP_UNDERLINE, "underline");
+ g_object_class_override_property (
+ object_class, PROP_SPELL_CHECK_ENABLED, "spell-check-enabled");
+ g_object_class_override_property (
+ object_class, PROP_SPELL_CHECKER, "spell-checker");
+}
+
+static void
+e_webkit_editor_init (EWebKitEditor *wk_editor)
+{
+ GSettings *g_settings;
+ GSettingsSchema *settings_schema;
+
+ wk_editor->priv = E_WEBKIT_EDITOR_GET_PRIVATE (wk_editor);
+
+ wk_editor->priv->spell_check_enabled = TRUE;
+ wk_editor->priv->spell_checker = e_spell_checker_new ();
+ wk_editor->priv->old_settings = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
(GDestroyNotify) g_variant_unref);
+
+ webkit_editor_watch_web_extension (wk_editor);
+
+ g_signal_connect (
+ wk_editor, "load-changed",
+ G_CALLBACK (webkit_editor_load_changed_cb), NULL);
+
+ g_signal_connect (
+ wk_editor, "context-menu",
+ G_CALLBACK (webkit_editor_context_menu_cb), NULL);
+
+ g_signal_connect (
+ wk_editor, "mouse-target-changed",
+ G_CALLBACK (webkit_editor_mouse_target_changed_cb), NULL);
+
+ g_signal_connect (
+ wk_editor, "drag-end",
+ G_CALLBACK (webkit_editor_drag_end_cb), NULL);
+
+ g_signal_connect (
+ wk_editor, "web-process-crashed",
+ G_CALLBACK (webkit_editor_web_process_crashed_cb), NULL);
+
+ wk_editor->priv->owner_change_primary_clipboard_cb_id = g_signal_connect (
+ gtk_clipboard_get (GDK_SELECTION_PRIMARY), "owner-change",
+ G_CALLBACK (webkit_editor_primary_clipboard_owner_change_cb), wk_editor);
+
+ wk_editor->priv->owner_change_clipboard_cb_id = g_signal_connect (
+ gtk_clipboard_get (GDK_SELECTION_CLIPBOARD), "owner-change",
+ G_CALLBACK (webkit_editor_clipboard_owner_change_cb), wk_editor);
+
+ g_settings = e_util_ref_settings ("org.gnome.desktop.interface");
+ g_signal_connect (
+ g_settings, "changed::font-name",
+ G_CALLBACK (webkit_editor_settings_changed_cb), wk_editor);
+ g_signal_connect (
+ g_settings, "changed::monospace-font-name",
+ G_CALLBACK (webkit_editor_settings_changed_cb), wk_editor);
+ wk_editor->priv->font_settings = g_settings;
+
+ g_settings = e_util_ref_settings ("org.gnome.evolution.mail");
+ wk_editor->priv->mail_settings = g_settings;
+
+ /* This schema is optional. Use if available. */
+ settings_schema = g_settings_schema_source_lookup (
+ g_settings_schema_source_get_default (),
+ "org.gnome.settings-daemon.plugins.xsettings", FALSE);
+ if (settings_schema != NULL) {
+ g_settings = e_util_ref_settings ("org.gnome.settings-daemon.plugins.xsettings");
+ g_signal_connect (
+ g_settings, "changed::antialiasing",
+ G_CALLBACK (webkit_editor_settings_changed_cb), wk_editor);
+ wk_editor->priv->aliasing_settings = g_settings;
+ }
+
+ wk_editor->priv->html_mode = TRUE;
+ wk_editor->priv->changed = FALSE;
+ wk_editor->priv->can_copy = FALSE;
+ wk_editor->priv->can_cut = FALSE;
+ wk_editor->priv->can_paste = FALSE;
+ wk_editor->priv->can_undo = FALSE;
+ wk_editor->priv->can_redo = FALSE;
+ wk_editor->priv->copy_paste_clipboard_in_view = FALSE;
+ wk_editor->priv->copy_paste_primary_in_view = FALSE;
+ wk_editor->priv->copy_cut_actions_triggered = FALSE;
+ wk_editor->priv->pasting_primary_clipboard = FALSE;
+ wk_editor->priv->pasting_from_itself_extension_value = FALSE;
+ wk_editor->priv->current_user_stylesheet = NULL;
+ wk_editor->priv->emit_load_finished_when_extension_is_ready = FALSE;
+
+ wk_editor->priv->font_color = gdk_rgba_copy (&black);
+ wk_editor->priv->background_color = gdk_rgba_copy (&white);
+ wk_editor->priv->font_name = NULL;
+ wk_editor->priv->font_size = E_CONTENT_EDITOR_FONT_SIZE_NORMAL;
+ wk_editor->priv->block_format = E_CONTENT_EDITOR_BLOCK_FORMAT_PARAGRAPH;
+ wk_editor->priv->alignment = E_CONTENT_EDITOR_ALIGNMENT_LEFT;
+
+ wk_editor->priv->web_extension_selection_changed_cb_id = 0;
+ wk_editor->priv->web_extension_content_changed_cb_id = 0;
+ wk_editor->priv->web_extension_undo_redo_state_changed_cb_id = 0;
+}
+
+static void
+e_webkit_editor_content_editor_init (EContentEditorInterface *iface)
+{
+ iface->initialize = webkit_editor_initialize;
+ iface->update_styles = webkit_editor_update_styles;
+ iface->insert_content = webkit_editor_insert_content;
+ iface->get_content = webkit_editor_get_content;
+ iface->insert_image = webkit_editor_insert_image;
+ iface->insert_image_from_mime_part = webkit_editor_insert_image_from_mime_part;
+ iface->insert_emoticon = webkit_editor_insert_emoticon;
+ iface->move_caret_on_coordinates = webkit_editor_move_caret_on_coordinates;
+ iface->cut = webkit_editor_cut;
+ iface->copy = webkit_editor_copy;
+ iface->paste = webkit_editor_paste;
+ iface->paste_primary = webkit_editor_paste_primary;
+ iface->undo = webkit_editor_undo;
+ iface->redo = webkit_editor_redo;
+ iface->clear_undo_redo_history = webkit_editor_clear_undo_redo_history;
+ iface->set_spell_checking_languages = webkit_editor_set_spell_checking_languages;
+ /* FIXME WK2 iface->get_selected_text = webkit_editor_get_selected_text; */
+ iface->get_caret_word = webkit_editor_get_caret_word;
+ iface->replace_caret_word = webkit_editor_replace_caret_word;
+ iface->select_all = webkit_editor_select_all;
+ iface->selection_indent = webkit_editor_selection_indent;
+ iface->selection_unindent = webkit_editor_selection_unindent;
+ /* FIXME WK2 iface->create_link = webkit_editor_create_link; */
+ iface->selection_unlink = webkit_editor_selection_unlink;
+ iface->find = webkit_editor_find;
+ iface->replace = webkit_editor_replace;
+ iface->replace_all = webkit_editor_replace_all;
+ iface->selection_save = webkit_editor_selection_save;
+ iface->selection_restore = webkit_editor_selection_restore;
+ iface->selection_wrap = webkit_editor_selection_wrap;
+ iface->get_caret_position = webkit_editor_get_caret_position;
+ iface->get_caret_offset = webkit_editor_get_caret_offset;
+ iface->get_current_signature_uid = webkit_editor_get_current_signature_uid;
+ iface->is_ready = webkit_editor_is_ready;
+ iface->insert_signature = webkit_editor_insert_signature;
+ iface->delete_cell_contents = webkit_editor_delete_cell_contents;
+ iface->delete_column = webkit_editor_delete_column;
+ iface->delete_row = webkit_editor_delete_row;
+ iface->delete_table = webkit_editor_delete_table;
+ iface->insert_column_after = webkit_editor_insert_column_after;
+ iface->insert_column_before = webkit_editor_insert_column_before;
+ iface->insert_row_above = webkit_editor_insert_row_above;
+ iface->insert_row_below = webkit_editor_insert_row_below;
+ iface->on_h_rule_dialog_open = webkit_editor_on_h_rule_dialog_open;
+ iface->on_h_rule_dialog_close = webkit_editor_on_h_rule_dialog_close;
+ iface->h_rule_set_align = webkit_editor_h_rule_set_align;
+ iface->h_rule_get_align = webkit_editor_h_rule_get_align;
+ iface->h_rule_set_size = webkit_editor_h_rule_set_size;
+ iface->h_rule_get_size = webkit_editor_h_rule_get_size;
+ iface->h_rule_set_width = webkit_editor_h_rule_set_width;
+ iface->h_rule_get_width = webkit_editor_h_rule_get_width;
+ iface->h_rule_set_no_shade = webkit_editor_h_rule_set_no_shade;
+ iface->h_rule_get_no_shade = webkit_editor_h_rule_get_no_shade;
+ iface->on_image_dialog_open = webkit_editor_on_image_dialog_open;
+ iface->on_image_dialog_close = webkit_editor_on_image_dialog_close;
+ iface->image_set_src = webkit_editor_image_set_src;
+ iface->image_get_src = webkit_editor_image_get_src;
+ iface->image_set_alt = webkit_editor_image_set_alt;
+ iface->image_get_alt = webkit_editor_image_get_alt;
+ iface->image_set_url = webkit_editor_image_set_url;
+ iface->image_get_url = webkit_editor_image_get_url;
+ iface->image_set_vspace = webkit_editor_image_set_vspace;
+ iface->image_get_vspace = webkit_editor_image_get_vspace;
+ iface->image_set_hspace = webkit_editor_image_set_hspace;
+ iface->image_get_hspace = webkit_editor_image_get_hspace;
+ iface->image_set_border = webkit_editor_image_set_border;
+ iface->image_get_border = webkit_editor_image_get_border;
+ iface->image_set_align = webkit_editor_image_set_align;
+ iface->image_get_align = webkit_editor_image_get_align;
+ iface->image_get_natural_width = webkit_editor_image_get_natural_width;
+ iface->image_get_natural_height = webkit_editor_image_get_natural_height;
+ iface->image_set_height = webkit_editor_image_set_height;
+ iface->image_set_width = webkit_editor_image_set_width;
+ iface->image_set_height_follow = webkit_editor_image_set_height_follow;
+ iface->image_set_width_follow = webkit_editor_image_set_width_follow;
+ iface->image_get_width = webkit_editor_image_get_width;
+ iface->image_get_height = webkit_editor_image_get_height;
+ iface->on_link_dialog_open = webkit_editor_on_link_dialog_open;
+ iface->on_link_dialog_close = webkit_editor_on_link_dialog_close;
+ iface->link_set_values = webkit_editor_link_set_values;
+ iface->link_get_values = webkit_editor_link_get_values;
+ iface->page_set_text_color = webkit_editor_page_set_text_color;
+ iface->page_get_text_color = webkit_editor_page_get_text_color;
+ iface->page_set_background_color = webkit_editor_page_set_background_color;
+ iface->page_get_background_color = webkit_editor_page_get_background_color;
+ iface->page_set_link_color = webkit_editor_page_set_link_color;
+ iface->page_get_link_color = webkit_editor_page_get_link_color;
+ iface->page_set_visited_link_color = webkit_editor_page_set_visited_link_color;
+ iface->page_get_visited_link_color = webkit_editor_page_get_visited_link_color;
+ iface->page_set_background_image_uri = webkit_editor_page_set_background_image_uri;
+ iface->page_get_background_image_uri = webkit_editor_page_get_background_image_uri;
+ iface->on_page_dialog_open = webkit_editor_on_page_dialog_open;
+ iface->on_page_dialog_close = webkit_editor_on_page_dialog_close;
+ iface->on_cell_dialog_open = webkit_editor_on_cell_dialog_open;
+ iface->on_cell_dialog_close = webkit_editor_on_cell_dialog_close;
+ iface->cell_set_v_align = webkit_editor_cell_set_v_align;
+ iface->cell_get_v_align = webkit_editor_cell_get_v_align;
+ iface->cell_set_align = webkit_editor_cell_set_align;
+ iface->cell_get_align = webkit_editor_cell_get_align;
+ iface->cell_set_wrap = webkit_editor_cell_set_wrap;
+ iface->cell_get_wrap = webkit_editor_cell_get_wrap;
+ iface->cell_set_header_style = webkit_editor_cell_set_header_style;
+ iface->cell_is_header = webkit_editor_cell_is_header;
+ iface->cell_get_width = webkit_editor_cell_get_width;
+ iface->cell_set_width = webkit_editor_cell_set_width;
+ iface->cell_get_row_span = webkit_editor_cell_get_row_span;
+ iface->cell_set_row_span = webkit_editor_cell_set_row_span;
+ iface->cell_get_col_span = webkit_editor_cell_get_col_span;
+ iface->cell_set_col_span = webkit_editor_cell_set_col_span;
+ iface->cell_get_background_image_uri = webkit_editor_cell_get_background_image_uri;
+ iface->cell_set_background_image_uri = webkit_editor_cell_set_background_image_uri;
+ iface->cell_get_background_color = webkit_editor_cell_get_background_color;
+ iface->cell_set_background_color = webkit_editor_cell_set_background_color;
+ iface->table_set_row_count = webkit_editor_table_set_row_count;
+ iface->table_get_row_count = webkit_editor_table_get_row_count;
+ iface->table_set_column_count = webkit_editor_table_set_column_count;
+ iface->table_get_column_count = webkit_editor_table_get_column_count;
+ iface->table_set_width = webkit_editor_table_set_width;
+ iface->table_get_width = webkit_editor_table_get_width;
+ iface->table_set_align = webkit_editor_table_set_align;
+ iface->table_get_align = webkit_editor_table_get_align;
+ iface->table_set_padding = webkit_editor_table_set_padding;
+ iface->table_get_padding = webkit_editor_table_get_padding;
+ iface->table_set_spacing = webkit_editor_table_set_spacing;
+ iface->table_get_spacing = webkit_editor_table_get_spacing;
+ iface->table_set_border = webkit_editor_table_set_border;
+ iface->table_get_border = webkit_editor_table_get_border;
+ iface->table_get_background_image_uri = webkit_editor_table_get_background_image_uri;
+ iface->table_set_background_image_uri = webkit_editor_table_set_background_image_uri;
+ iface->table_get_background_color = webkit_editor_table_get_background_color;
+ iface->table_set_background_color = webkit_editor_table_set_background_color;
+ iface->on_table_dialog_open = webkit_editor_on_table_dialog_open;
+ iface->on_table_dialog_close = webkit_editor_on_table_dialog_close;
+ iface->on_spell_check_dialog_open = webkit_editor_on_spell_check_dialog_open;
+ iface->on_spell_check_dialog_close = webkit_editor_on_spell_check_dialog_close;
+ iface->spell_check_next_word = webkit_editor_spell_check_next_word;
+ iface->spell_check_prev_word = webkit_editor_spell_check_prev_word;
+ iface->on_replace_dialog_open = webkit_editor_on_replace_dialog_open;
+ iface->on_replace_dialog_close = webkit_editor_on_replace_dialog_close;
+ iface->on_find_dialog_open = webkit_editor_on_find_dialog_open;
+ iface->on_find_dialog_close = webkit_editor_on_find_dialog_close;
+}
diff --git a/modules/webkit-editor/e-webkit-editor.h b/modules/webkit-editor/e-webkit-editor.h
new file mode 100644
index 0000000..3b21679
--- /dev/null
+++ b/modules/webkit-editor/e-webkit-editor.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2016 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library 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.
+ *
+ * This library 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 this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef E_WEBKIT_EDITOR_H
+#define E_WEBKIT_EDITOR_H
+
+#include <webkit2/webkit2.h>
+
+/* Standard GObject macros */
+#define E_TYPE_WEBKIT_EDITOR \
+ (e_webkit_editor_get_type ())
+#define E_WEBKIT_EDITOR(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_WEBKIT_EDITOR, EWebKitEditor))
+#define E_WEBKIT_EDITOR_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_WEBKIT_EDITOR, EWebKitEditorClass))
+#define E_IS_WEBKIT_EDITOR(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_WEBKIT_EDITOR))
+#define E_IS_WEBKIT_EDITOR_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_WEBKIT_EDITOR))
+#define E_WEBKIT_EDITOR_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_WEBKIT_EDITOR, EWebKitEditorClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EWebKitEditor EWebKitEditor;
+typedef struct _EWebKitEditorClass EWebKitEditorClass;
+typedef struct _EWebKitEditorPrivate EWebKitEditorPrivate;
+
+struct _EWebKitEditor {
+ WebKitWebView parent;
+ EWebKitEditorPrivate *priv;
+};
+
+struct _EWebKitEditorClass {
+ WebKitWebViewClass parent_class;
+
+ gboolean (*popup_event) (EWebKitEditor *wk_editor,
+ GdkEventButton *event);
+ void (*paste_primary_clipboard)
+ (EWebKitEditor *wk_editor);
+};
+
+GType e_webkit_editor_get_type (void) G_GNUC_CONST;
+
+EWebKitEditor *
+ e_webkit_editor_new (void);
+
+G_END_DECLS
+
+#endif /* E_WEBKIT_EDITOR_H */
diff --git a/modules/webkit-editor/evolution-module-webkit-editor.c
b/modules/webkit-editor/evolution-module-webkit-editor.c
new file mode 100644
index 0000000..116903f
--- /dev/null
+++ b/modules/webkit-editor/evolution-module-webkit-editor.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2016 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library 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.
+ *
+ * This library 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 this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-webkit-editor-extension.h"
+
+/* Module Entry Points */
+void e_module_load (GTypeModule *type_module);
+void e_module_unload (GTypeModule *type_module);
+
+G_MODULE_EXPORT void
+e_module_load (GTypeModule *type_module)
+{
+ e_webkit_editor_extension_type_register (type_module);
+}
+
+G_MODULE_EXPORT void
+e_module_unload (GTypeModule *type_module)
+{
+}
diff --git a/modules/webkit-editor/web-extension/Makefile.am b/modules/webkit-editor/web-extension/Makefile.am
new file mode 100644
index 0000000..f2a7b02
--- /dev/null
+++ b/modules/webkit-editor/web-extension/Makefile.am
@@ -0,0 +1,38 @@
+webextensionswebkiteditor_LTLIBRARIES = libewebkiteditorwebextension.la
+
+libewebkiteditorwebextension_la_SOURCES = \
+ e-composer-dom-functions.c \
+ e-composer-dom-functions.h \
+ e-dialogs-dom-functions.c \
+ e-dialogs-dom-functions.h \
+ e-editor-dom-functions.c \
+ e-editor-dom-functions.h \
+ e-editor-page.c \
+ e-editor-page.h \
+ e-editor-undo-redo-manager.c \
+ e-editor-undo-redo-manager.h \
+ e-editor-web-extension.c \
+ e-editor-web-extension.h \
+ e-editor-web-extension-main.c \
+ e-editor-web-extension-names.h \
+ $(NULL)
+
+libewebkiteditorwebextension_la_CPPFLAGS = \
+ $(AM_CPPFLAGS) \
+ -I$(top_srcdir) \
+ -DEVOLUTION_IMAGESDIR=\""$(imagesdir)"\" \
+ $(EVOLUTION_DATA_SERVER_CFLAGS) \
+ $(GNOME_PLATFORM_CFLAGS) \
+ $(WEB_EXTENSIONS_CFLAGS)
+
+libewebkiteditorwebextension_la_LIBADD = \
+ $(top_builddir)/e-util/libevolution-util.la \
+ $(top_builddir)/web-extensions/libedomutils.la \
+ $(EVOLUTION_DATA_SERVER_LIBS) \
+ $(GNOME_PLATFORM_LIBS) \
+ $(WEB_EXTENSIONS_LIBS)
+
+libewebkiteditorwebextension_la_LDFLAGS = \
+ -module -avoid-version -no-undefined
+
+-include $(top_srcdir)/git.mk
diff --git a/modules/webkit-editor/web-extension/e-composer-dom-functions.c
b/modules/webkit-editor/web-extension/e-composer-dom-functions.c
new file mode 100644
index 0000000..9c8a4fa
--- /dev/null
+++ b/modules/webkit-editor/web-extension/e-composer-dom-functions.c
@@ -0,0 +1,832 @@
+/*
+ * e-composer-private-dom-functions.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/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#define WEBKIT_DOM_USE_UNSTABLE_API
+#include <webkitdom/WebKitDOMDOMSelection.h>
+#include <webkitdom/WebKitDOMDOMWindowUnstable.h>
+#include <webkitdom/WebKitDOMHTMLElementUnstable.h>
+#undef WEBKIT_DOM_USE_UNSTABLE_API
+
+#include <camel/camel.h>
+
+#include "web-extensions/e-dom-utils.h"
+
+#include "e-editor-page.h"
+#include "e-editor-dom-functions.h"
+#include "e-editor-undo-redo-manager.h"
+
+#include "e-composer-dom-functions.h"
+
+static WebKitDOMElement *
+prepare_top_signature_spacer (EEditorPage *editor_page)
+{
+ WebKitDOMElement *element;
+
+ element = e_editor_dom_prepare_paragraph (editor_page, FALSE);
+ webkit_dom_element_remove_attribute (element, "id");
+ element_add_class (element, "-x-evo-top-signature-spacer");
+
+ return element;
+}
+
+static gboolean
+add_signature_delimiter (void)
+{
+ gboolean ret_val;
+ GSettings *settings;
+
+ settings = e_util_ref_settings ("org.gnome.evolution.mail");
+ ret_val = !g_settings_get_boolean (settings, "composer-no-signature-delim");
+ g_object_unref (settings);
+
+ return ret_val;
+}
+
+static gboolean
+use_top_signature (void)
+{
+ gboolean ret_val;
+ GSettings *settings;
+
+ settings = e_util_ref_settings ("org.gnome.evolution.mail");
+ ret_val = g_settings_get_boolean (settings, "composer-top-signature");
+ g_object_unref (settings);
+
+ return ret_val;
+}
+
+static gboolean
+start_typing_at_bottom (void)
+{
+ gboolean ret_val;
+ GSettings *settings;
+
+ settings = e_util_ref_settings ("org.gnome.evolution.mail");
+ ret_val = g_settings_get_boolean (settings, "composer-reply-start-bottom");
+ g_object_unref (settings);
+
+ return ret_val;
+}
+
+static void
+move_caret_after_signature_inserted (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *element, *signature;
+ WebKitDOMHTMLElement *body;
+ WebKitDOMNodeList *paragraphs = NULL;
+ gboolean top_signature;
+ gboolean start_bottom;
+ gboolean has_paragraphs_in_body = TRUE;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+
+ top_signature = use_top_signature ();
+ start_bottom = start_typing_at_bottom ();
+
+ body = webkit_dom_document_get_body (document);
+ e_editor_page_block_selection_changed (editor_page);
+
+ paragraphs = webkit_dom_document_query_selector_all (document, "[data-evo-paragraph]", NULL);
+ signature = webkit_dom_document_query_selector (document, ".-x-evo-signature-wrapper", NULL);
+ /* Situation when wrapped paragraph is just in signature and not in message body */
+ if (webkit_dom_node_list_get_length (paragraphs) == 1)
+ if (signature && webkit_dom_element_query_selector (signature, "[data-evo-paragraph]", NULL))
+ has_paragraphs_in_body = FALSE;
+
+ /*
+ *
+ * Keeping Signatures in the beginning of composer
+ * ------------------------------------------------
+ *
+ * Purists are gonna blast me for this.
+ * But there are so many people (read Outlook users) who want this.
+ * And Evo is an exchange-client, Outlook-replacement etc.
+ * So Here it goes :(
+ *
+ * -- Sankar
+ *
+ */
+ if (signature && top_signature) {
+ WebKitDOMElement *spacer;
+
+ spacer = prepare_top_signature_spacer (editor_page);
+ webkit_dom_node_insert_before (
+ WEBKIT_DOM_NODE (body),
+ WEBKIT_DOM_NODE (spacer),
+ webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (signature)),
+ NULL);
+ }
+
+ if (webkit_dom_node_list_get_length (paragraphs) == 0)
+ has_paragraphs_in_body = FALSE;
+
+ element = webkit_dom_document_get_element_by_id (document, "-x-evo-input-start");
+ if (!signature) {
+ if (start_bottom) {
+ if (!element) {
+ element = e_editor_dom_prepare_paragraph (editor_page, FALSE);
+ webkit_dom_element_set_id (element, "-x-evo-input-start");
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (body),
+ WEBKIT_DOM_NODE (element),
+ NULL);
+ }
+ } else
+ element = WEBKIT_DOM_ELEMENT (body);
+
+ goto move_caret;
+ }
+
+ /* When there is an option composer-reply-start-bottom set we have
+ * to move the caret between reply and signature. */
+ if (!has_paragraphs_in_body) {
+ element = e_editor_dom_prepare_paragraph (editor_page, FALSE);
+ webkit_dom_element_set_id (element, "-x-evo-input-start");
+ if (top_signature) {
+ if (start_bottom) {
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (body),
+ WEBKIT_DOM_NODE (element),
+ NULL);
+ } else {
+ webkit_dom_node_insert_before (
+ WEBKIT_DOM_NODE (body),
+ WEBKIT_DOM_NODE (element),
+ WEBKIT_DOM_NODE (signature),
+ NULL);
+ }
+ } else {
+ if (start_bottom)
+ webkit_dom_node_insert_before (
+ WEBKIT_DOM_NODE (body),
+ WEBKIT_DOM_NODE (element),
+ WEBKIT_DOM_NODE (signature),
+ NULL);
+ else
+ element = WEBKIT_DOM_ELEMENT (body);
+ }
+ } else {
+ if (!element && top_signature) {
+ element = e_editor_dom_prepare_paragraph (editor_page, FALSE);
+ webkit_dom_element_set_id (element, "-x-evo-input-start");
+ if (start_bottom) {
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (body),
+ WEBKIT_DOM_NODE (element),
+ NULL);
+ } else {
+ webkit_dom_node_insert_before (
+ WEBKIT_DOM_NODE (body),
+ WEBKIT_DOM_NODE (element),
+ WEBKIT_DOM_NODE (signature),
+ NULL);
+ }
+ } else if (element && top_signature && !start_bottom) {
+ webkit_dom_node_insert_before (
+ WEBKIT_DOM_NODE (body),
+ WEBKIT_DOM_NODE (element),
+ WEBKIT_DOM_NODE (signature),
+ NULL);
+ } else if (element && start_bottom) {
+ /* Leave it how it is */
+ } else
+ element = WEBKIT_DOM_ELEMENT (body);
+ }
+
+ move_caret:
+ if (element) {
+ WebKitDOMDOMSelection *dom_selection = NULL;
+ WebKitDOMDOMWindow *dom_window = NULL;
+ WebKitDOMRange *range = NULL;
+
+ dom_window = webkit_dom_document_get_default_view (document);
+ dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+ range = webkit_dom_document_create_range (document);
+
+ webkit_dom_range_select_node_contents (
+ range, WEBKIT_DOM_NODE (element), NULL);
+ webkit_dom_range_collapse (range, TRUE, NULL);
+ webkit_dom_dom_selection_remove_all_ranges (dom_selection);
+ webkit_dom_dom_selection_add_range (dom_selection, range);
+
+ g_clear_object (&dom_selection);
+ g_clear_object (&dom_window);
+ g_clear_object (&range);
+ }
+
+ if (start_bottom)
+ e_editor_dom_scroll_to_caret (editor_page);
+
+ g_clear_object (¶graphs);
+
+ e_editor_dom_force_spell_check_in_viewport (editor_page);
+ e_editor_page_unblock_selection_changed (editor_page);
+}
+
+gchar *
+e_composer_dom_insert_signature (EEditorPage *editor_page,
+ const gchar *content,
+ gboolean is_html,
+ const gchar *id,
+ gboolean *set_signature_from_message,
+ gboolean *check_if_signature_is_changed,
+ gboolean *ignore_next_signature_change)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *signature_to_insert;
+ WebKitDOMElement *insert_signature_in = NULL;
+ WebKitDOMElement *signature_wrapper = NULL;
+ WebKitDOMElement *element, *converted_signature = NULL;
+ WebKitDOMHTMLElement *body;
+ WebKitDOMHTMLCollection *signatures = NULL;
+ gchar *new_signature_id = NULL;
+ gchar *signature_text = NULL;
+ gboolean top_signature, html_mode;
+ gulong list_length, ii;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+ g_return_val_if_fail (set_signature_from_message != NULL, NULL);
+ g_return_val_if_fail (check_if_signature_is_changed != NULL, NULL);
+ g_return_val_if_fail (ignore_next_signature_change != NULL, NULL);
+
+ document = e_editor_page_get_document (editor_page);
+ body = webkit_dom_document_get_body (document);
+
+ /* "Edit as New Message" sets is_message_from_edit_as_new.
+ * Always put the signature at the bottom for that case. */
+ top_signature = use_top_signature ();
+
+ html_mode = e_editor_page_get_html_mode (editor_page);
+
+ /* Create the DOM signature that is the same across all types of signatures. */
+ signature_to_insert = webkit_dom_document_create_element (document, "span", NULL);
+ webkit_dom_element_set_class_name (signature_to_insert, "-x-evo-signature");
+ /* The combo box active ID is the signature's ESource UID. */
+ webkit_dom_element_set_id (signature_to_insert, id);
+ insert_signature_in = signature_to_insert;
+
+ /* The signature has no content usually it means it is set to None. */
+ if (!(content && *content))
+ goto insert;
+
+ if (!is_html) {
+ gchar *html;
+
+ html = camel_text_to_html (content, 0, 0);
+ if (html) {
+ signature_text = html;
+ } else
+ signature_text = g_strdup (content);
+
+ insert_signature_in = webkit_dom_document_create_element (document, "pre", NULL);
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (signature_to_insert),
+ WEBKIT_DOM_NODE (insert_signature_in),
+ NULL);
+ } else
+ signature_text = g_strdup (content);
+
+ /* If inserting HTML signature in the plain text composer we have to convert it. */
+ if (is_html && !html_mode && !strstr (signature_text, "data-evo-signature-plain-text-mode")) {
+ gchar *inner_text;
+
+ /* Save the converted signature to avoid parsing it later again
+ * while inserting it into the view. */
+ converted_signature = webkit_dom_document_create_element (document, "pre", NULL);
+ webkit_dom_element_set_inner_html (converted_signature, signature_text, NULL);
+ e_editor_dom_convert_element_from_html_to_plain_text (editor_page, converted_signature);
+ inner_text = webkit_dom_html_element_get_inner_text (WEBKIT_DOM_HTML_ELEMENT
(converted_signature));
+
+ g_free (signature_text);
+ signature_text = inner_text ? g_strstrip (inner_text) : g_strdup ("");
+ /* because of the -- \n check */
+ is_html = FALSE;
+ }
+
+ /* The signature dash convention ("-- \n") is specified
+ * in the "Son of RFC 1036", section 4.3.2.
+ * http://www.chemie.fu-berlin.de/outerspace/netnews/son-of-1036.html
+ */
+ if (add_signature_delimiter ()) {
+ const gchar *delim;
+ const gchar *delim_nl;
+
+ if (is_html) {
+ delim = "-- <BR>";
+ delim_nl = "\n-- <BR>";
+ } else {
+ delim = "-- \n";
+ delim_nl = "\n-- \n";
+ }
+
+ /* Skip the delimiter if the signature already has one. */
+ if (g_ascii_strncasecmp (signature_text, delim, strlen (delim)) == 0)
+ ; /* skip */
+ else if (e_util_strstrcase (signature_text, delim_nl) != NULL)
+ ; /* skip */
+ else {
+ WebKitDOMElement *pre_delimiter;
+
+ pre_delimiter = webkit_dom_document_create_element (document, "pre", NULL);
+ /* Always use the HTML delimiter as we are never in anything
+ * like a strict plain text mode. */
+ webkit_dom_element_set_inner_html (pre_delimiter, "-- <br>", NULL);
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (insert_signature_in),
+ WEBKIT_DOM_NODE (pre_delimiter),
+ NULL);
+ }
+ }
+
+ if (converted_signature) {
+ WebKitDOMNode *node;
+
+ while ((node = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (converted_signature))))
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (insert_signature_in), node, NULL);
+ remove_node (WEBKIT_DOM_NODE (converted_signature));
+ } else
+ webkit_dom_html_element_insert_adjacent_html (
+ WEBKIT_DOM_HTML_ELEMENT (insert_signature_in),
+ "beforeend",
+ signature_text,
+ NULL);
+
+ element = webkit_dom_element_query_selector (
+ insert_signature_in, "[data-evo-signature-plain-text-mode]", NULL);
+ if (element)
+ webkit_dom_element_remove_attribute (
+ element, "data-evo-signature-plain-text-mode");
+ g_free (signature_text);
+
+insert:
+ /* Remove the old signature and insert the new one. */
+ signatures = webkit_dom_document_get_elements_by_class_name_as_html_collection (
+ document, "-x-evo-signature-wrapper");
+ list_length = webkit_dom_html_collection_get_length (signatures);
+ for (ii = 0; ii < list_length; ii++) {
+ WebKitDOMNode *wrapper, *signature;
+
+ wrapper = webkit_dom_html_collection_item (signatures, ii);
+ signature = webkit_dom_node_get_first_child (wrapper);
+
+ /* Old messages will have the signature id in the name attribute, correct it. */
+ element_rename_attribute (WEBKIT_DOM_ELEMENT (signature), "name", "id");
+
+ /* When we are editing a message with signature, we need to unset the
+ * active signature id as if the signature in the message was edited
+ * by the user we would discard these changes. */
+ if (*set_signature_from_message && content) {
+ if (*check_if_signature_is_changed) {
+ /* Normalize the signature that we want to insert as the one in the
+ * message already is normalized. */
+ webkit_dom_node_normalize (WEBKIT_DOM_NODE (signature_to_insert));
+ if (!webkit_dom_node_is_equal_node (WEBKIT_DOM_NODE (signature_to_insert),
signature)) {
+ /* Signature in the body is different than the one with the
+ * same id, so set the active signature to None and leave
+ * the signature that is in the body. */
+ new_signature_id = g_strdup ("none");
+ *ignore_next_signature_change = TRUE;
+ }
+
+ *check_if_signature_is_changed = FALSE;
+ *set_signature_from_message = FALSE;
+ } else {
+ /* Load the signature and check if is it the same
+ * as the signature in body or the user previously
+ * changed it. */
+ new_signature_id = webkit_dom_element_get_id (WEBKIT_DOM_ELEMENT (signature));
+ *check_if_signature_is_changed = TRUE;
+ }
+ g_object_unref (wrapper);
+ g_clear_object (&signatures);
+
+ return new_signature_id;
+ }
+
+ /* If the top signature was set we have to remove the newline
+ * that was inserted after it */
+ if (top_signature) {
+ WebKitDOMElement *spacer;
+
+ spacer = webkit_dom_document_query_selector (
+ document, ".-x-evo-top-signature-spacer", NULL);
+ if (spacer)
+ remove_node_if_empty (WEBKIT_DOM_NODE (spacer));
+ }
+
+ /* Leave just one signature wrapper there as it will be reused. */
+ if (ii != list_length - 1) {
+ g_object_unref (wrapper);
+ remove_node (wrapper);
+ } else {
+ remove_node (signature);
+ signature_wrapper = WEBKIT_DOM_ELEMENT (wrapper);
+ }
+ }
+
+ if (signature_wrapper) {
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (signature_wrapper),
+ WEBKIT_DOM_NODE (signature_to_insert),
+ NULL);
+
+ /* Insert a spacer below the top signature */
+ if (top_signature && content) {
+ WebKitDOMElement *spacer;
+
+ spacer = prepare_top_signature_spacer (editor_page);
+ webkit_dom_node_insert_before (
+ WEBKIT_DOM_NODE (body),
+ WEBKIT_DOM_NODE (spacer),
+ webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (signature_wrapper)),
+ NULL);
+ }
+
+ g_object_unref (signature_wrapper);
+ } else {
+ signature_wrapper = webkit_dom_document_create_element (document, "div", NULL);
+ webkit_dom_element_set_class_name (signature_wrapper, "-x-evo-signature-wrapper");
+
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (signature_wrapper),
+ WEBKIT_DOM_NODE (signature_to_insert),
+ NULL);
+
+ if (top_signature) {
+ WebKitDOMNode *child;
+
+ child = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (body));
+
+ if (start_typing_at_bottom ()) {
+ webkit_dom_node_insert_before (
+ WEBKIT_DOM_NODE (body),
+ WEBKIT_DOM_NODE (signature_wrapper),
+ child,
+ NULL);
+ } else {
+ /* When we are using signature on top the caret
+ * should be before the signature */
+ webkit_dom_node_insert_before (
+ WEBKIT_DOM_NODE (body),
+ WEBKIT_DOM_NODE (signature_wrapper),
+ child,
+ NULL);
+ }
+ } else {
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (body),
+ WEBKIT_DOM_NODE (signature_wrapper),
+ NULL);
+ }
+
+ move_caret_after_signature_inserted (editor_page);
+ }
+ g_clear_object (&signatures);
+
+ if (is_html && html_mode)
+ e_editor_dom_fix_file_uri_images (editor_page);
+
+ /* Make sure the flag will be unset and won't influence user's choice */
+ *set_signature_from_message = FALSE;
+
+ return NULL;
+}
+
+gchar *
+e_composer_dom_get_active_signature_uid (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *element;
+ gchar *uid = NULL;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+ document = e_editor_page_get_document (editor_page);
+
+ if ((element = webkit_dom_document_query_selector (document, ".-x-evo-signature[id]", NULL)))
+ uid = webkit_dom_element_get_id (element);
+
+ return uid;
+}
+
+gchar *
+e_composer_dom_get_raw_body_content_without_signature (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMNodeList *list = NULL;
+ GString* content;
+ gulong ii, length;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+ document = e_editor_page_get_document (editor_page);
+
+ content = g_string_new (NULL);
+
+ list = webkit_dom_document_query_selector_all (
+ document, "body > *:not(.-x-evo-signature-wrapper)", NULL);
+ length = webkit_dom_node_list_get_length (list);
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMNode *node = webkit_dom_node_list_item (list, ii);
+
+ if (!WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (node)) {
+ gchar *text;
+
+ text = webkit_dom_html_element_get_inner_text (WEBKIT_DOM_HTML_ELEMENT (node));
+ g_string_append (content, text);
+ g_free (text);
+
+ if (WEBKIT_DOM_IS_HTML_DIV_ELEMENT (node))
+ g_string_append (content, "\n");
+ else
+ g_string_append (content, " ");
+ }
+ }
+ g_clear_object (&list);
+
+ return g_string_free (content, FALSE);
+}
+
+gchar *
+e_composer_dom_get_raw_body_content (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMHTMLElement *body;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+ document = e_editor_page_get_document (editor_page);
+
+ body = webkit_dom_document_get_body (document);
+
+ return webkit_dom_html_element_get_inner_text (body);
+}
+
+static void
+insert_nbsp_history_event (WebKitDOMDocument *document,
+ EEditorUndoRedoManager *manager,
+ gboolean delete,
+ guint x,
+ guint y)
+{
+ EEditorHistoryEvent *event;
+ WebKitDOMDocumentFragment *fragment;
+
+ event = g_new0 (EEditorHistoryEvent, 1);
+ event->type = HISTORY_AND;
+ e_editor_undo_redo_manager_insert_history_event (manager, event);
+
+ fragment = webkit_dom_document_create_document_fragment (document);
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (fragment),
+ WEBKIT_DOM_NODE (
+ webkit_dom_document_create_text_node (document, UNICODE_NBSP)),
+ NULL);
+
+ event = g_new0 (EEditorHistoryEvent, 1);
+ event->type = HISTORY_DELETE;
+
+ if (delete)
+ g_object_set_data (G_OBJECT (fragment), "history-delete-key", GINT_TO_POINTER (1));
+
+ event->data.fragment = fragment;
+
+ event->before.start.x = x;
+ event->before.start.y = y;
+ event->before.end.x = x;
+ event->before.end.y = y;
+
+ event->after.start.x = x;
+ event->after.start.y = y;
+ event->after.end.x = x;
+ event->after.end.y = y;
+
+ e_editor_undo_redo_manager_insert_history_event (manager, event);
+}
+
+void
+e_composer_dom_save_drag_and_drop_history (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMDocumentFragment *fragment;
+ WebKitDOMDOMSelection *dom_selection = NULL;
+ WebKitDOMDOMWindow *dom_window = NULL;
+ WebKitDOMRange *beginning_of_line = NULL;
+ WebKitDOMRange *range = NULL, *range_clone = NULL;
+ EEditorHistoryEvent *event;
+ EEditorUndoRedoManager *manager;
+ gboolean start_to_start, end_to_end;
+ gchar *range_text;
+ guint x, y;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+ manager = e_editor_page_get_undo_redo_manager (editor_page);
+
+ if (!(dom_window = webkit_dom_document_get_default_view (document)))
+ return;
+
+ if (!(dom_selection = webkit_dom_dom_window_get_selection (dom_window))) {
+ g_clear_object (&dom_window);
+ return;
+ }
+
+ g_clear_object (&dom_window);
+
+ if (webkit_dom_dom_selection_get_range_count (dom_selection) < 1) {
+ g_clear_object (&dom_selection);
+ return;
+ }
+
+ /* Obtain the dragged content. */
+ range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+ range_clone = webkit_dom_range_clone_range (range, NULL);
+
+ /* Create the history event for the content that will
+ * be removed by DnD. */
+ event = g_new0 (EEditorHistoryEvent, 1);
+ event->type = HISTORY_DELETE;
+
+ e_editor_dom_selection_get_coordinates (editor_page,
+ &event->before.start.x,
+ &event->before.start.y,
+ &event->before.end.x,
+ &event->before.end.y);
+
+ x = event->before.start.x;
+ y = event->before.start.y;
+
+ event->after.start.x = x;
+ event->after.start.y = y;
+ event->after.end.x = x;
+ event->after.end.y = y;
+
+ /* Save the content that will be removed. */
+ fragment = webkit_dom_range_clone_contents (range_clone, NULL);
+
+ /* Extend the cloned range to point one character after
+ * the selection ends to later check if there is a whitespace
+ * after it. */
+ webkit_dom_range_set_end (
+ range_clone,
+ webkit_dom_range_get_end_container (range_clone, NULL),
+ webkit_dom_range_get_end_offset (range_clone, NULL) + 1,
+ NULL);
+ range_text = webkit_dom_range_get_text (range_clone);
+
+ /* Check if the current selection starts on the beginning
+ * of line. */
+ webkit_dom_dom_selection_modify (
+ dom_selection, "extend", "left", "lineboundary");
+ beginning_of_line = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+ start_to_start = webkit_dom_range_compare_boundary_points (
+ beginning_of_line, 0 /* START_TO_START */, range, NULL) == 0;
+
+ /* Restore the selection to state before the check. */
+ webkit_dom_dom_selection_remove_all_ranges (dom_selection);
+ webkit_dom_dom_selection_add_range (dom_selection, range);
+ g_clear_object (&beginning_of_line);
+
+ /* Check if the current selection end on the end of the line. */
+ webkit_dom_dom_selection_modify (
+ dom_selection, "extend", "right", "lineboundary");
+ beginning_of_line = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+ end_to_end = webkit_dom_range_compare_boundary_points (
+ beginning_of_line, 2 /* END_TO_END */, range, NULL) == 0;
+
+ /* Dragging the whole line. */
+ if (start_to_start && end_to_end) {
+ WebKitDOMNode *container, *actual_block, *tmp_block;
+
+ /* Select the whole line (to the beginning of the next
+ * one so we can reuse the undo code while undoing this.
+ * Because of this we need to special mark the event
+ * with history-drag-and-drop to correct the selection
+ * after undoing it (otherwise the beginning of the next
+ * line will be selected as well. */
+ webkit_dom_dom_selection_modify (
+ dom_selection, "extend", "right", "character");
+ g_clear_object (&beginning_of_line);
+ beginning_of_line = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+
+ container = webkit_dom_range_get_end_container (range, NULL);
+ actual_block = e_editor_dom_get_parent_block_node_from_child (container);
+
+ tmp_block = webkit_dom_range_get_end_container (beginning_of_line, NULL);
+ if ((tmp_block = e_editor_dom_get_parent_block_node_from_child (tmp_block))) {
+ e_editor_dom_selection_get_coordinates (editor_page,
+ &event->before.start.x,
+ &event->before.start.y,
+ &event->before.end.x,
+ &event->before.end.y);
+
+ /* Create the right content for the history event. */
+ fragment = webkit_dom_document_create_document_fragment (document);
+ /* The removed line. */
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (fragment),
+ webkit_dom_node_clone_node_with_error (actual_block, TRUE, NULL),
+ NULL);
+ /* The following block, but empty. */
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (fragment),
+ webkit_dom_node_clone_node_with_error (tmp_block, FALSE, NULL),
+ NULL);
+ g_object_set_data (
+ G_OBJECT (fragment),
+ "history-drag-and-drop",
+ GINT_TO_POINTER (1));
+ /* It should act as a Delete key press. */
+ g_object_set_data (
+ G_OBJECT (fragment),
+ "history-delete-key",
+ GINT_TO_POINTER (1));
+ }
+ }
+
+ event->data.fragment = fragment;
+ e_editor_undo_redo_manager_insert_history_event (manager, event);
+
+ /* Selection is ending on the end of the line, check if
+ * there is a space before the selection start. If so, it
+ * will be removed and we need create the history event
+ * for it. */
+ if (end_to_end) {
+ gchar *range_text_start;
+ glong start_offset;
+
+ start_offset = webkit_dom_range_get_start_offset (range_clone, NULL);
+ webkit_dom_range_set_start (
+ range_clone,
+ webkit_dom_range_get_start_container (range_clone, NULL),
+ start_offset > 0 ? start_offset - 1 : 0,
+ NULL);
+
+ range_text_start = webkit_dom_range_get_text (range_clone);
+ if (g_str_has_prefix (range_text_start, " ") ||
+ g_str_has_prefix (range_text_start, UNICODE_NBSP))
+ insert_nbsp_history_event (document, manager, FALSE, x, y);
+
+ g_free (range_text_start);
+ }
+
+ /* WebKit removes the space (if presented) after selection and
+ * we need to create a new history event for it. */
+ if (g_str_has_suffix (range_text, " ") ||
+ g_str_has_suffix (range_text, UNICODE_NBSP))
+ insert_nbsp_history_event (document, manager, TRUE, x, y);
+
+ g_free (range_text);
+
+ /* Restore the selection to original state. */
+ webkit_dom_dom_selection_remove_all_ranges (dom_selection);
+ webkit_dom_dom_selection_add_range (dom_selection, range);
+ g_clear_object (&beginning_of_line);
+
+ /* All the things above were about removing the content,
+ * create an AND event to continue later with inserting
+ * the dropped content. */
+ event = g_new0 (EEditorHistoryEvent, 1);
+ event->type = HISTORY_AND;
+ e_editor_undo_redo_manager_insert_history_event (manager, event);
+
+ g_clear_object (&dom_selection);
+
+ g_clear_object (&range);
+ g_clear_object (&range_clone);
+}
+
+void
+e_composer_dom_clean_after_drag_and_drop (EEditorPage *editor_page)
+{
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ e_editor_dom_save_history_for_drop (editor_page);
+ e_editor_dom_check_magic_links (editor_page, FALSE);
+}
diff --git a/modules/webkit-editor/web-extension/e-composer-dom-functions.h
b/modules/webkit-editor/web-extension/e-composer-dom-functions.h
new file mode 100644
index 0000000..8e0f934
--- /dev/null
+++ b/modules/webkit-editor/web-extension/e-composer-dom-functions.h
@@ -0,0 +1,48 @@
+/*
+ * e-composer-dom-functions.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/>
+ *
+ */
+
+#ifndef E_COMPOSER_DOM_FUNCTIONS_H
+#define E_COMPOSER_DOM_FUNCTIONS_H
+
+#include <webkitdom/webkitdom.h>
+
+#include "e-editor-page.h"
+
+G_BEGIN_DECLS
+
+gchar * e_composer_dom_insert_signature (EEditorPage *editor_page,
+ const gchar *content,
+ gboolean is_html,
+ const gchar *id,
+ gboolean *set_signature_from_message,
+ gboolean *check_if_signature_is_changed,
+ gboolean *ignore_next_signature_change);
+gchar * e_composer_dom_get_active_signature_uid
+ (EEditorPage *editor_page);
+gchar * e_composer_dom_get_raw_body_content_without_signature
+ (EEditorPage *editor_page);
+gchar * e_composer_dom_get_raw_body_content
+ (EEditorPage *editor_page);
+void e_composer_dom_save_drag_and_drop_history
+ (EEditorPage *editor_page);
+void e_composer_dom_clean_after_drag_and_drop
+ (EEditorPage *editor_page);
+
+G_END_DECLS
+
+#endif /* E_COMPOSER_DOM_FUNCTIONS_H */
diff --git a/modules/webkit-editor/web-extension/e-dialogs-dom-functions.c
b/modules/webkit-editor/web-extension/e-dialogs-dom-functions.c
new file mode 100644
index 0000000..84d17ff
--- /dev/null
+++ b/modules/webkit-editor/web-extension/e-dialogs-dom-functions.c
@@ -0,0 +1,1455 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2016 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library 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.
+ *
+ * This library 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 this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define WEBKIT_DOM_USE_UNSTABLE_API
+#include <webkitdom/WebKitDOMDOMSelection.h>
+#include <webkitdom/WebKitDOMDOMWindowUnstable.h>
+#undef WEBKIT_DOM_USE_UNSTABLE_API
+
+#include "web-extensions/e-dom-utils.h"
+
+#include "e-editor-dom-functions.h"
+#include "e-editor-undo-redo-manager.h"
+
+#include "e-dialogs-dom-functions.h"
+
+/* ******************** Cell Dialog ***************** */
+
+typedef void (*DOMStrFunc) (WebKitDOMHTMLTableCellElement *cell, const gchar *val, gpointer user_data);
+typedef void (*DOMLongFunc) (WebKitDOMHTMLTableCellElement *cell, glong val, gpointer user_data);
+typedef void (*DOMBoolFunc) (WebKitDOMHTMLTableCellElement *cell, gboolean val, gpointer user_data);
+
+static WebKitDOMElement *
+get_current_cell_element (WebKitDOMDocument *document)
+{
+ return webkit_dom_document_get_element_by_id (document, "-x-evo-current-cell");
+}
+
+static void
+call_cell_dom_func (WebKitDOMHTMLTableCellElement *cell,
+ gpointer func,
+ GValue *value,
+ gpointer user_data)
+{
+ if (G_VALUE_HOLDS_STRING (value)) {
+ DOMStrFunc f = func;
+ f (cell, g_value_get_string (value), user_data);
+ } else if (G_VALUE_HOLDS_LONG (value)) {
+ DOMLongFunc f = func;
+ f (cell, g_value_get_long (value), user_data);
+ } else if (G_VALUE_HOLDS_BOOLEAN (value)) {
+ DOMBoolFunc f = func;
+ f (cell, g_value_get_boolean (value), user_data);
+ }
+}
+
+static void
+for_each_cell_do (WebKitDOMElement *row,
+ gpointer func,
+ GValue *value,
+ gpointer user_data)
+{
+ WebKitDOMHTMLCollection *cells = NULL;
+ gulong ii, length;
+
+ cells = webkit_dom_html_table_row_element_get_cells (
+ WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (row));
+ length = webkit_dom_html_collection_get_length (cells);
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMNode *cell;
+ cell = webkit_dom_html_collection_item (cells, ii);
+ if (!cell) {
+ continue;
+ }
+
+ call_cell_dom_func (
+ WEBKIT_DOM_HTML_TABLE_CELL_ELEMENT (cell), func, value, user_data);
+ g_object_unref (cell);
+ }
+ g_clear_object (&cells);
+}
+
+static void
+cell_dialog_set_attribute (WebKitDOMDocument *document,
+ EContentEditorScope scope,
+ gpointer func,
+ GValue *value,
+ gpointer user_data)
+{
+ WebKitDOMElement *cell = get_current_cell_element (document);
+
+ if (scope == E_CONTENT_EDITOR_SCOPE_CELL) {
+
+ call_cell_dom_func (
+ WEBKIT_DOM_HTML_TABLE_CELL_ELEMENT (cell),
+ func, value, user_data);
+
+ } else if (scope == E_CONTENT_EDITOR_SCOPE_COLUMN) {
+ gulong index, ii, length;
+ WebKitDOMElement *table;
+ WebKitDOMHTMLCollection *rows = NULL;
+
+ index = webkit_dom_html_table_cell_element_get_cell_index (
+ WEBKIT_DOM_HTML_TABLE_CELL_ELEMENT (cell));
+ table = dom_node_find_parent_element (WEBKIT_DOM_NODE (cell), "TABLE");
+ if (!table) {
+ return;
+ }
+
+ rows = webkit_dom_html_table_element_get_rows (
+ WEBKIT_DOM_HTML_TABLE_ELEMENT (table));
+ length = webkit_dom_html_collection_get_length (rows);
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMNode *row, *cell;
+ WebKitDOMHTMLCollection *cells = NULL;
+
+ row = webkit_dom_html_collection_item (rows, ii);
+ cells = webkit_dom_html_table_row_element_get_cells (
+ WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (row));
+ cell = webkit_dom_html_collection_item (cells, index);
+ if (!cell) {
+ g_object_unref (row);
+ g_clear_object (&cells);
+ continue;
+ }
+
+ call_cell_dom_func (
+ WEBKIT_DOM_HTML_TABLE_CELL_ELEMENT (cell),
+ func, value, user_data);
+ g_object_unref (row);
+ g_clear_object (&cells);
+ g_object_unref (cell);
+ }
+ g_clear_object (&rows);
+
+ } else if (scope == E_CONTENT_EDITOR_SCOPE_ROW) {
+ WebKitDOMElement *row;
+
+ row = dom_node_find_parent_element (WEBKIT_DOM_NODE (cell), "TR");
+ if (!row) {
+ return;
+ }
+
+ for_each_cell_do (row, func, value, user_data);
+
+ } else if (scope == E_CONTENT_EDITOR_SCOPE_TABLE) {
+ gulong ii, length;
+ WebKitDOMElement *table;
+ WebKitDOMHTMLCollection *rows = NULL;
+
+ table = dom_node_find_parent_element (WEBKIT_DOM_NODE (cell), "TABLE");
+ if (!table) {
+ return;
+ }
+
+ rows = webkit_dom_html_table_element_get_rows (
+ WEBKIT_DOM_HTML_TABLE_ELEMENT (table));
+ length = webkit_dom_html_collection_get_length (rows);
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMNode *row;
+
+ row = webkit_dom_html_collection_item (rows, ii);
+ if (!row) {
+ g_object_unref (row);
+ continue;
+ }
+
+ for_each_cell_do (
+ WEBKIT_DOM_ELEMENT (row), func, value, user_data);
+ g_object_unref (row);
+ }
+ g_clear_object (&rows);
+ }
+}
+
+static void
+cell_set_header_style (WebKitDOMHTMLTableCellElement *cell,
+ gboolean header_style,
+ gpointer user_data)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMNodeList *nodes = NULL;
+ WebKitDOMElement *new_cell;
+ gulong length, ii;
+ gchar *tagname;
+
+ document = webkit_dom_node_get_owner_document (WEBKIT_DOM_NODE (cell));
+ tagname = webkit_dom_element_get_tag_name (WEBKIT_DOM_ELEMENT (cell));
+
+ if (header_style && (g_ascii_strncasecmp (tagname, "TD", 2) == 0)) {
+
+ new_cell = webkit_dom_document_create_element (document, "TH", NULL);
+
+ } else if (!header_style && (g_ascii_strncasecmp (tagname, "TH", 2) == 0)) {
+
+ new_cell = webkit_dom_document_create_element (document, "TD", NULL);
+
+ } else {
+ g_free (tagname);
+ return;
+ }
+
+ webkit_dom_element_set_id (new_cell, "-x-evo-current-cell");
+
+ /* Move all child nodes from cell to new_cell */
+ nodes = webkit_dom_node_get_child_nodes (WEBKIT_DOM_NODE (cell));
+ length = webkit_dom_node_list_get_length (nodes);
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMNode *node;
+
+ node = webkit_dom_node_list_item (nodes, ii);
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (new_cell), node, NULL);
+ g_object_unref (node);
+ }
+ g_clear_object (&nodes);
+
+ /* Insert new_cell before cell and remove cell */
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (
+ WEBKIT_DOM_NODE (cell)),
+ WEBKIT_DOM_NODE (new_cell),
+ WEBKIT_DOM_NODE (cell), NULL);
+
+ webkit_dom_node_remove_child (
+ webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (cell)),
+ WEBKIT_DOM_NODE (cell), NULL);
+
+ g_free (tagname);
+}
+
+void
+e_dialogs_dom_cell_mark_current_cell_element (EEditorPage *editor_page,
+ const gchar *id)
+{
+ EEditorUndoRedoManager *manager;
+ WebKitDOMElement *cell;
+ WebKitDOMDocument *document;
+ WebKitDOMNode *node_under_mouse_click;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+ g_return_if_fail (id != NULL);
+
+ document = e_editor_page_get_document (editor_page);
+
+ node_under_mouse_click = e_editor_page_get_node_under_mouse_click (editor_page);
+
+ if (node_under_mouse_click && WEBKIT_DOM_IS_HTML_TABLE_CELL_ELEMENT (node_under_mouse_click)) {
+ cell = WEBKIT_DOM_ELEMENT (node_under_mouse_click);
+ } else {
+ WebKitDOMElement *selection_start;
+
+ e_editor_dom_selection_save (editor_page);
+
+ selection_start = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-start-marker");
+
+ cell = dom_node_find_parent_element (WEBKIT_DOM_NODE (selection_start), "TD");
+ if (!cell)
+ cell = dom_node_find_parent_element (WEBKIT_DOM_NODE (selection_start), "TH");
+
+ e_editor_dom_selection_restore (editor_page);
+ }
+
+ if (cell)
+ webkit_dom_element_set_id (cell, "-x-evo-current-cell");
+ else
+ return;
+
+ manager = e_editor_page_get_undo_redo_manager (editor_page);
+ if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+ EEditorHistoryEvent *ev;
+ WebKitDOMElement *table;
+
+ ev = g_new0 (EEditorHistoryEvent, 1);
+ ev->type = HISTORY_TABLE_DIALOG;
+
+ e_editor_dom_selection_get_coordinates (editor_page,
+ &ev->before.start.x,
+ &ev->before.start.y,
+ &ev->before.end.x,
+ &ev->before.end.y);
+
+ table = dom_node_find_parent_element (
+ WEBKIT_DOM_NODE (cell), "TABLE");
+ if (table)
+ ev->data.dom.from = webkit_dom_node_clone_node_with_error (
+ WEBKIT_DOM_NODE (table), TRUE, NULL);
+
+ e_editor_undo_redo_manager_insert_history_event (manager, ev);
+ }
+}
+
+void
+e_dialogs_dom_cell_save_history_on_exit (EEditorPage *editor_page)
+{
+ EEditorUndoRedoManager *manager;
+ EEditorHistoryEvent *ev = NULL;
+ WebKitDOMElement *cell, *table;
+ WebKitDOMDocument *document;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+
+ cell = get_current_cell_element (document);
+
+ table = dom_node_find_parent_element (WEBKIT_DOM_NODE (cell), "TABLE");
+ g_return_if_fail (table != NULL);
+
+ webkit_dom_element_remove_attribute (cell, "id");
+
+ manager = e_editor_page_get_undo_redo_manager (editor_page);
+ ev = e_editor_undo_redo_manager_get_current_history_event (manager);
+ ev->data.dom.to = webkit_dom_node_clone_node_with_error (
+ WEBKIT_DOM_NODE (table), TRUE, NULL);
+
+ if (ev->data.dom.from && webkit_dom_node_is_equal_node (ev->data.dom.from, ev->data.dom.to))
+ e_editor_undo_redo_manager_remove_current_history_event (manager);
+ else
+ e_editor_dom_selection_get_coordinates (editor_page, &ev->after.start.x, &ev->after.start.y,
&ev->after.end.x, &ev->after.end.y);
+}
+
+void
+e_dialogs_dom_cell_set_element_v_align (EEditorPage *editor_page,
+ const gchar *v_align,
+ EContentEditorScope scope)
+{
+ GValue val = { 0 };
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ g_value_init (&val, G_TYPE_STRING);
+ g_value_set_string (&val, v_align);
+
+ cell_dialog_set_attribute (e_editor_page_get_document (editor_page),
+ scope, webkit_dom_html_table_cell_element_set_v_align, &val, NULL);
+
+ g_value_unset (&val);
+}
+
+void
+e_dialogs_dom_cell_set_element_align (EEditorPage *editor_page,
+ const gchar *align,
+ EContentEditorScope scope)
+{
+ GValue val = { 0 };
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ g_value_init (&val, G_TYPE_STRING);
+ g_value_set_string (&val, align);
+
+ cell_dialog_set_attribute (e_editor_page_get_document (editor_page),
+ scope, webkit_dom_html_table_cell_element_set_align, &val, NULL);
+
+ g_value_unset (&val);
+}
+
+void
+e_dialogs_dom_cell_set_element_no_wrap (EEditorPage *editor_page,
+ gboolean wrap_text,
+ EContentEditorScope scope)
+{
+ GValue val = { 0 };
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ g_value_init (&val, G_TYPE_BOOLEAN);
+ g_value_set_boolean (&val, wrap_text);
+
+ cell_dialog_set_attribute (e_editor_page_get_document (editor_page),
+ scope, webkit_dom_html_table_cell_element_set_no_wrap, &val, NULL);
+}
+
+void
+e_dialogs_dom_cell_set_element_header_style (EEditorPage *editor_page,
+ gboolean header_style,
+ EContentEditorScope scope)
+{
+ GValue val = { 0 };
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ g_value_init (&val, G_TYPE_BOOLEAN);
+ g_value_set_boolean (&val, header_style);
+
+ cell_dialog_set_attribute (e_editor_page_get_document (editor_page),
+ scope, cell_set_header_style, &val, NULL);
+}
+
+void
+e_dialogs_dom_cell_set_element_width (EEditorPage *editor_page,
+ const gchar *width,
+ EContentEditorScope scope)
+{
+ GValue val = { 0 };
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ g_value_init (&val, G_TYPE_STRING);
+ g_value_set_string (&val, width);
+
+ cell_dialog_set_attribute (e_editor_page_get_document (editor_page),
+ scope, webkit_dom_html_table_cell_element_set_width, &val, NULL);
+
+ g_value_unset (&val);
+}
+
+void
+e_dialogs_dom_cell_set_element_col_span (EEditorPage *editor_page,
+ glong span,
+ EContentEditorScope scope)
+{
+ GValue val = { 0 };
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ g_value_init (&val, G_TYPE_LONG);
+ g_value_set_long (&val, span);
+
+ cell_dialog_set_attribute (e_editor_page_get_document (editor_page),
+ scope, webkit_dom_html_table_cell_element_set_col_span, &val, NULL);
+}
+
+void
+e_dialogs_dom_cell_set_element_row_span (EEditorPage *editor_page,
+ glong span,
+ EContentEditorScope scope)
+{
+ GValue val = { 0 };
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ g_value_init (&val, G_TYPE_LONG);
+ g_value_set_long (&val, span);
+
+ cell_dialog_set_attribute (e_editor_page_get_document (editor_page),
+ scope, webkit_dom_html_table_cell_element_set_row_span, &val, NULL);
+}
+
+void
+e_dialogs_dom_cell_set_element_bg_color (EEditorPage *editor_page,
+ const gchar *color,
+ EContentEditorScope scope)
+{
+ GValue val = { 0 };
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ g_value_init (&val, G_TYPE_STRING);
+ g_value_set_string (&val, color);
+
+ cell_dialog_set_attribute (e_editor_page_get_document (editor_page),
+ scope, webkit_dom_html_table_cell_element_set_bg_color, &val, NULL);
+}
+
+/* ******************** HRule Dialog ***************** */
+
+static WebKitDOMElement *
+get_current_hrule_element (WebKitDOMDocument *document)
+{
+ return webkit_dom_document_get_element_by_id (document, "-x-evo-current-hr");
+}
+
+gboolean
+e_dialogs_dom_h_rule_find_hrule (EEditorPage *editor_page)
+{
+ EEditorUndoRedoManager *manager;
+ gboolean created = FALSE;
+ WebKitDOMDocument *document;
+ WebKitDOMElement *rule;
+ WebKitDOMNode *node_under_mouse_click;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+ document = e_editor_page_get_document (editor_page);
+
+ node_under_mouse_click = e_editor_page_get_node_under_mouse_click (editor_page);
+
+ if (node_under_mouse_click && WEBKIT_DOM_IS_HTML_HR_ELEMENT (node_under_mouse_click)) {
+ rule = WEBKIT_DOM_ELEMENT (node_under_mouse_click);
+ webkit_dom_element_set_id (rule, "-x-evo-current-hr");
+ } else {
+ WebKitDOMElement *selection_start, *parent;
+
+ e_editor_dom_selection_save (editor_page);
+
+ selection_start = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-start-marker");
+ parent = get_parent_block_element (WEBKIT_DOM_NODE (selection_start));
+
+ rule = webkit_dom_document_create_element (document, "HR", NULL);
+ webkit_dom_element_set_id (rule, "-x-evo-current-hr");
+
+ /* Insert horizontal rule into body below the caret */
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (parent)),
+ WEBKIT_DOM_NODE (rule),
+ webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (parent)),
+ NULL);
+
+ e_editor_dom_selection_restore (editor_page);
+
+ e_editor_page_emit_content_changed (editor_page);
+
+ created = TRUE;
+ }
+
+ manager = e_editor_page_get_undo_redo_manager (editor_page);
+ if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+ EEditorHistoryEvent *ev;
+
+ ev = g_new0 (EEditorHistoryEvent, 1);
+ ev->type = HISTORY_HRULE_DIALOG;
+
+ e_editor_dom_selection_get_coordinates (editor_page, &ev->before.start.x,
&ev->before.start.y, &ev->before.end.x, &ev->before.end.y);
+ if (!created)
+ ev->data.dom.from = webkit_dom_node_clone_node_with_error (
+ WEBKIT_DOM_NODE (rule), FALSE, NULL);
+ else
+ ev->data.dom.from = NULL;
+
+ e_editor_undo_redo_manager_insert_history_event (manager, ev);
+ }
+
+ return created;
+}
+
+void
+e_dialogs_dom_h_rule_dialog_on_close (EEditorPage *editor_page)
+{
+ EEditorUndoRedoManager *manager;
+ EEditorHistoryEvent *ev = NULL;
+ WebKitDOMDocument *document;
+ WebKitDOMElement *element;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+ element = get_current_hrule_element (document);
+ g_return_if_fail (element != NULL);
+
+ webkit_dom_element_remove_attribute (element, "id");
+
+ manager = e_editor_page_get_undo_redo_manager (editor_page);
+ ev = e_editor_undo_redo_manager_get_current_history_event (manager);
+
+ ev->data.dom.to = webkit_dom_node_clone_node_with_error (
+ WEBKIT_DOM_NODE (element), TRUE, NULL);
+
+ if (ev->data.dom.from && webkit_dom_node_is_equal_node (ev->data.dom.from, ev->data.dom.to))
+ e_editor_undo_redo_manager_remove_current_history_event (manager);
+ else
+ e_editor_dom_selection_get_coordinates (editor_page, &ev->after.start.x, &ev->after.start.y,
&ev->after.end.x, &ev->after.end.y);
+}
+
+/* ******************** Image Dialog ***************** */
+
+static WebKitDOMElement *
+get_current_image_element (WebKitDOMDocument *document)
+{
+ return webkit_dom_document_get_element_by_id (document, "-x-evo-current-img");
+}
+
+void
+e_dialogs_dom_image_mark_image (EEditorPage *editor_page)
+{
+ EEditorUndoRedoManager *manager;
+ WebKitDOMNode *node_under_mouse_click;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ node_under_mouse_click = e_editor_page_get_node_under_mouse_click (editor_page);
+
+ g_return_if_fail (node_under_mouse_click && WEBKIT_DOM_IS_HTML_IMAGE_ELEMENT
(node_under_mouse_click));
+
+ webkit_dom_element_set_id (WEBKIT_DOM_ELEMENT (node_under_mouse_click), "-x-evo-current-img");
+
+ manager = e_editor_page_get_undo_redo_manager (editor_page);
+ if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+ EEditorHistoryEvent *ev;
+
+ ev = g_new0 (EEditorHistoryEvent, 1);
+ ev->type = HISTORY_IMAGE_DIALOG;
+
+ e_editor_dom_selection_get_coordinates (editor_page, &ev->before.start.x,
&ev->before.start.y, &ev->before.end.x, &ev->before.end.y);
+ ev->data.dom.from = webkit_dom_node_clone_node_with_error (node_under_mouse_click, FALSE,
NULL);
+
+ e_editor_undo_redo_manager_insert_history_event (manager, ev);
+ }
+}
+
+void
+e_dialogs_dom_image_save_history_on_exit (EEditorPage *editor_page)
+{
+ EEditorUndoRedoManager *manager;
+ EEditorHistoryEvent *ev = NULL;
+ WebKitDOMDocument *document;
+ WebKitDOMElement *element;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+ element = get_current_image_element (document);
+ g_return_if_fail (element != NULL);
+
+ webkit_dom_element_remove_attribute (element, "id");
+
+ manager = e_editor_page_get_undo_redo_manager (editor_page);
+ ev = e_editor_undo_redo_manager_get_current_history_event (manager);
+ ev->data.dom.to = webkit_dom_node_clone_node_with_error (
+ WEBKIT_DOM_NODE (element), TRUE, NULL);
+
+ if (ev->data.dom.from && webkit_dom_node_is_equal_node (ev->data.dom.from, ev->data.dom.to))
+ e_editor_undo_redo_manager_remove_current_history_event (manager);
+ else
+ e_editor_dom_selection_get_coordinates (editor_page, &ev->after.start.x, &ev->after.start.y,
&ev->after.end.x, &ev->after.end.y);
+}
+
+void
+e_dialogs_dom_image_set_element_url (EEditorPage *editor_page,
+ const gchar *url)
+{
+ WebKitDOMElement *image, *link;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ image = get_current_image_element (e_editor_page_get_document (editor_page));
+ link = dom_node_find_parent_element (WEBKIT_DOM_NODE (image), "A");
+
+ if (link) {
+ if (!url || !*url) {
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (
+ WEBKIT_DOM_NODE (link)),
+ WEBKIT_DOM_NODE (image),
+ WEBKIT_DOM_NODE (link), NULL);
+ webkit_dom_node_remove_child (
+ webkit_dom_node_get_parent_node (
+ WEBKIT_DOM_NODE (link)),
+ WEBKIT_DOM_NODE (link), NULL);
+ } else {
+ webkit_dom_html_anchor_element_set_href (
+ WEBKIT_DOM_HTML_ANCHOR_ELEMENT (link), url);
+ }
+ } else {
+ if (url && *url) {
+ WebKitDOMDocument *document;
+
+ document = webkit_dom_node_get_owner_document (
+ WEBKIT_DOM_NODE (image));
+ link = webkit_dom_document_create_element (
+ document, "A", NULL);
+
+ webkit_dom_html_anchor_element_set_href (
+ WEBKIT_DOM_HTML_ANCHOR_ELEMENT (link), url);
+
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (
+ WEBKIT_DOM_NODE (image)),
+ WEBKIT_DOM_NODE (link),
+ WEBKIT_DOM_NODE (image), NULL);
+
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (link),
+ WEBKIT_DOM_NODE (image), NULL);
+ }
+ }
+}
+
+gchar *
+e_dialogs_dom_image_get_element_url (EEditorPage *editor_page)
+{
+ gchar *value = NULL;
+ WebKitDOMElement *image, *link;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+ image = get_current_image_element (e_editor_page_get_document (editor_page));
+ link = dom_node_find_parent_element (WEBKIT_DOM_NODE (image), "A");
+
+ if (link)
+ value = webkit_dom_element_get_attribute (link, "href");
+
+ return value;
+}
+
+/* ******************** Link Dialog ***************** */
+
+void
+e_dialogs_dom_link_commit (EEditorPage *editor_page,
+ const gchar *url,
+ const gchar *inner_text)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *link;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+ link = webkit_dom_document_get_element_by_id (document, "-x-evo-current-anchor");
+
+ if (link) {
+ WebKitDOMElement *element;
+
+ webkit_dom_html_anchor_element_set_href (
+ WEBKIT_DOM_HTML_ANCHOR_ELEMENT (link), url);
+ webkit_dom_html_element_set_inner_text (
+ WEBKIT_DOM_HTML_ELEMENT (link), inner_text, NULL);
+
+ element = webkit_dom_document_create_element (document, "SPAN", NULL);
+ webkit_dom_element_set_id (element, "-x-evo-selection-end-marker");
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (link)),
+ WEBKIT_DOM_NODE (element),
+ webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (link)),
+ NULL);
+
+ element = webkit_dom_document_create_element (document, "SPAN", NULL);
+ webkit_dom_element_set_id (element, "-x-evo-selection-start-marker");
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (link)),
+ WEBKIT_DOM_NODE (element),
+ webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (link)),
+ NULL);
+
+ e_editor_dom_selection_restore (editor_page);
+ } else {
+ WebKitDOMDOMWindow *dom_window = NULL;
+ WebKitDOMDOMSelection *dom_selection = NULL;
+ WebKitDOMRange *range = NULL;
+
+ dom_window = webkit_dom_document_get_default_view (document);
+ dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+ g_clear_object (&dom_window);
+
+ e_editor_dom_selection_restore (editor_page);
+ range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+ if (webkit_dom_range_get_collapsed (range, NULL)) {
+ WebKitDOMElement *selection_marker;
+ WebKitDOMElement *anchor;
+
+ e_editor_dom_selection_save (editor_page);
+ selection_marker = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-start-marker");
+ anchor = webkit_dom_document_create_element (document, "A", NULL);
+ webkit_dom_element_set_attribute (anchor, "href", url, NULL);
+ webkit_dom_element_set_id (anchor, "-x-evo-current-anchor");
+ webkit_dom_html_element_set_inner_text (
+ WEBKIT_DOM_HTML_ELEMENT (anchor), inner_text, NULL);
+
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (
+ WEBKIT_DOM_NODE (selection_marker)),
+ WEBKIT_DOM_NODE (anchor),
+ WEBKIT_DOM_NODE (selection_marker),
+ NULL);
+ e_editor_dom_selection_restore (editor_page);
+ } else {
+ gchar *text;
+
+ text = webkit_dom_range_get_text (range);
+ if (text && *text) {
+ EEditorUndoRedoManager *manager;
+ EEditorHistoryEvent *ev;
+
+ e_editor_dom_create_link (editor_page, url);
+
+ manager = e_editor_page_get_undo_redo_manager (editor_page);
+ ev = e_editor_undo_redo_manager_get_current_history_event (manager);
+
+ ev->data.dom.from =
+ WEBKIT_DOM_NODE (webkit_dom_document_create_text_node (document,
text));
+
+ webkit_dom_dom_selection_collapse_to_end (dom_selection, NULL);
+ }
+ g_free (text);
+ }
+
+ g_clear_object (&range);
+ g_clear_object (&dom_selection);
+ }
+}
+
+void
+e_dialogs_dom_link_dialog_on_close (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *link;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+
+ link = webkit_dom_document_get_element_by_id (document, "-x-evo-current-anchor");
+ if (link) {
+ EEditorUndoRedoManager *manager;
+ EEditorHistoryEvent *ev;
+
+ manager = e_editor_page_get_undo_redo_manager (editor_page);
+ ev = e_editor_undo_redo_manager_get_current_history_event (manager);
+ if (ev->type == HISTORY_LINK_DIALOG) {
+ ev->data.dom.to = webkit_dom_node_clone_node_with_error (
+ WEBKIT_DOM_NODE (link), TRUE, NULL);
+
+ if (ev->data.dom.from && webkit_dom_node_is_equal_node (ev->data.dom.from,
ev->data.dom.to))
+ e_editor_undo_redo_manager_remove_current_history_event (manager);
+ else
+ e_editor_dom_selection_get_coordinates (
+ editor_page, &ev->after.start.x, &ev->after.start.y,
&ev->after.end.x, &ev->after.end.y);
+ }
+ webkit_dom_element_remove_attribute (link, "id");
+ }
+}
+
+void
+e_dialogs_dom_link_dialog_on_open (EEditorPage *editor_page)
+{
+ EEditorUndoRedoManager *manager;
+ WebKitDOMDocument *document;
+ WebKitDOMElement *link = NULL;
+ WebKitDOMNode *node_under_mouse_click;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+
+ node_under_mouse_click = e_editor_page_get_node_under_mouse_click (editor_page);
+ if (node_under_mouse_click && WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (node_under_mouse_click)) {
+ link = WEBKIT_DOM_ELEMENT (node_under_mouse_click);
+ } else {
+ if (!(link = webkit_dom_document_get_element_by_id (document, "-x-evo-current-anchor"))) {
+ if (node_under_mouse_click) {
+ link = dom_node_find_parent_element (node_under_mouse_click, "A");
+ } else {
+ WebKitDOMElement *selection_start;
+
+ e_editor_dom_selection_save (editor_page);
+
+ selection_start = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-start-marker");
+
+ link = dom_node_find_parent_element (WEBKIT_DOM_NODE (selection_start), "A");
+
+ e_editor_dom_selection_restore (editor_page);
+ }
+ }
+ }
+
+ if (link)
+ webkit_dom_element_set_id (link, "-x-evo-current-anchor");
+
+ manager = e_editor_page_get_undo_redo_manager (editor_page);
+ if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+ EEditorHistoryEvent *ev;
+
+ ev = g_new0 (EEditorHistoryEvent, 1);
+ ev->type = HISTORY_LINK_DIALOG;
+
+ e_editor_dom_selection_get_coordinates (
+ editor_page, &ev->before.start.x, &ev->before.start.y, &ev->before.end.x,
&ev->before.end.y);
+ if (link)
+ ev->data.dom.from = webkit_dom_node_clone_node_with_error (
+ WEBKIT_DOM_NODE (link), TRUE, NULL);
+ else
+ ev->data.dom.from = NULL;
+ e_editor_undo_redo_manager_insert_history_event (manager, ev);
+ }
+}
+
+GVariant *
+e_dialogs_dom_link_show (EEditorPage *editor_page)
+{
+ GVariant *result = NULL;
+ WebKitDOMDocument *document;
+ WebKitDOMElement *link;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+ document = e_editor_page_get_document (editor_page);
+
+ e_editor_dom_selection_save (editor_page);
+
+ link = webkit_dom_document_get_element_by_id (document, "-x-evo-current-anchor");
+ if (link) {
+ gchar *href, *text;
+
+ href = webkit_dom_element_get_attribute (link, "href");
+ text = webkit_dom_html_element_get_inner_text (
+ WEBKIT_DOM_HTML_ELEMENT (link));
+
+ result = g_variant_new ("(ss)", href, text);
+
+ g_free (text);
+ g_free (href);
+ } else {
+ gchar *text;
+ WebKitDOMDOMWindow *dom_window = NULL;
+ WebKitDOMDOMSelection *dom_selection = NULL;
+ WebKitDOMRange *range = NULL;
+
+ dom_window = webkit_dom_document_get_default_view (document);
+ dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+ g_clear_object (&dom_window);
+
+ /* No selection at all */
+ if (!dom_selection || webkit_dom_dom_selection_get_range_count (dom_selection) < 1)
+ result = g_variant_new ("(ss)", "", "");
+
+ range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+ text = webkit_dom_range_get_text (range);
+ if (text)
+ result = g_variant_new ("(ss)", "", text);
+
+ g_free (text);
+
+ g_clear_object (&range);
+ g_clear_object (&dom_selection);
+ }
+
+ return result;
+}
+
+/* ******************** Page Dialog ***************** */
+
+void
+e_dialogs_dom_page_save_history (EEditorPage *editor_page)
+{
+ EEditorUndoRedoManager *manager;
+ WebKitDOMDocument *document;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+
+ manager = e_editor_page_get_undo_redo_manager (editor_page);
+ if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+ EEditorHistoryEvent *ev;
+ WebKitDOMHTMLElement *body;
+
+ ev = g_new0 (EEditorHistoryEvent, 1);
+ ev->type = HISTORY_PAGE_DIALOG;
+
+ e_editor_dom_selection_get_coordinates (editor_page, &ev->before.start.x,
&ev->before.start.y, &ev->before.end.x, &ev->before.end.y);
+ body = webkit_dom_document_get_body (document);
+ ev->data.dom.from = webkit_dom_node_clone_node_with_error (WEBKIT_DOM_NODE (body), FALSE,
NULL);
+
+ e_editor_undo_redo_manager_insert_history_event (manager, ev);
+ }
+}
+
+void
+e_dialogs_dom_page_save_history_on_exit (EEditorPage *editor_page)
+{
+ EEditorHistoryEvent *ev = NULL;
+ EEditorUndoRedoManager *manager;
+ WebKitDOMDocument *document;
+ WebKitDOMHTMLElement *body;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+
+ manager = e_editor_page_get_undo_redo_manager (editor_page);
+ ev = e_editor_undo_redo_manager_get_current_history_event (manager);
+ body = webkit_dom_document_get_body (document);
+ ev->data.dom.to = webkit_dom_node_clone_node_with_error (WEBKIT_DOM_NODE (body), FALSE, NULL);
+
+ if (!webkit_dom_node_is_equal_node (ev->data.dom.from, ev->data.dom.to)) {
+ e_editor_dom_selection_get_coordinates (editor_page, &ev->after.start.x, &ev->after.start.y,
&ev->after.end.x, &ev->after.end.y);
+ } else {
+ e_editor_undo_redo_manager_remove_current_history_event (manager);
+ }
+}
+
+/* ******************** Spell Check Dialog ***************** */
+
+static gboolean
+select_next_word (WebKitDOMDOMSelection *dom_selection)
+{
+ gulong anchor_offset, focus_offset;
+ WebKitDOMNode *anchor, *focus;
+
+ anchor = webkit_dom_dom_selection_get_anchor_node (dom_selection);
+ anchor_offset = webkit_dom_dom_selection_get_anchor_offset (dom_selection);
+
+ focus = webkit_dom_dom_selection_get_focus_node (dom_selection);
+ focus_offset = webkit_dom_dom_selection_get_focus_offset (dom_selection);
+
+ /* Jump _behind_ next word */
+ webkit_dom_dom_selection_modify (dom_selection, "move", "forward", "word");
+ /* Jump before the word */
+ webkit_dom_dom_selection_modify (dom_selection, "move", "backward", "word");
+ /* Select it */
+ webkit_dom_dom_selection_modify (dom_selection, "extend", "forward", "word");
+
+ /* If the selection didn't change, then we have most probably
+ * reached the end of document - return FALSE */
+ return !((anchor == webkit_dom_dom_selection_get_anchor_node (dom_selection)) &&
+ (anchor_offset == webkit_dom_dom_selection_get_anchor_offset (dom_selection)) &&
+ (focus == webkit_dom_dom_selection_get_focus_node (dom_selection)) &&
+ (focus_offset == webkit_dom_dom_selection_get_focus_offset (dom_selection)));
+}
+
+static gboolean
+select_previous_word (WebKitDOMDOMSelection *dom_selection)
+{
+ WebKitDOMNode *old_anchor_node;
+ WebKitDOMNode *new_anchor_node;
+ gulong old_anchor_offset;
+ gulong new_anchor_offset;
+
+ old_anchor_node = webkit_dom_dom_selection_get_anchor_node (dom_selection);
+ old_anchor_offset = webkit_dom_dom_selection_get_anchor_offset (dom_selection);
+
+ /* Jump on the beginning of current word */
+ webkit_dom_dom_selection_modify (dom_selection, "move", "backward", "word");
+ /* Jump before previous word */
+ webkit_dom_dom_selection_modify (dom_selection, "move", "backward", "word");
+ /* Select it */
+ webkit_dom_dom_selection_modify (dom_selection, "extend", "forward", "word");
+
+ /* If the selection start didn't change, then we have most probably
+ * reached the beginnig of document. Return FALSE */
+
+ new_anchor_node = webkit_dom_dom_selection_get_anchor_node (dom_selection);
+ new_anchor_offset = webkit_dom_dom_selection_get_anchor_offset (dom_selection);
+
+ return (new_anchor_node != old_anchor_node) ||
+ (new_anchor_offset != old_anchor_offset);
+}
+
+static gchar *
+e_dialogs_dom_spell_check_run (EEditorPage *editor_page,
+ gboolean run_next,
+ const gchar *from_word,
+ const gchar * const *languages)
+{
+ gulong start_offset = 0, end_offset = 0;
+ WebKitDOMDocument *document;
+ WebKitDOMDOMSelection *dom_selection = NULL;
+ WebKitDOMDOMWindow *dom_window = NULL;
+ WebKitDOMNode *start = NULL, *end = NULL;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+ document = e_editor_page_get_document (editor_page);
+ dom_window = webkit_dom_document_get_default_view (document);
+ dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+ g_clear_object (&dom_window);
+
+ if (!from_word || !*from_word) {
+ if (run_next) {
+ webkit_dom_dom_selection_modify (
+ dom_selection, "move", "left", "documentboundary");
+ } else {
+ webkit_dom_dom_selection_modify (
+ dom_selection, "move", "right", "documentboundary");
+ webkit_dom_dom_selection_modify (
+ dom_selection, "extend", "backward", "word");
+ }
+ } else {
+ /* Remember last selected word */
+ start = webkit_dom_dom_selection_get_anchor_node (dom_selection);
+ end = webkit_dom_dom_selection_get_focus_node (dom_selection);
+ start_offset = webkit_dom_dom_selection_get_anchor_offset (dom_selection);
+ end_offset = webkit_dom_dom_selection_get_focus_offset (dom_selection);
+ }
+
+ while ((run_next ? select_next_word (dom_selection) : select_previous_word (dom_selection))) {
+ WebKitDOMRange *range = NULL;
+ gchar *word;
+
+ range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+ word = webkit_dom_range_get_text (range);
+ g_clear_object (&range);
+
+ if (!e_editor_page_check_word_spelling (editor_page, word, languages)) {
+ /* Found misspelled word! */
+ return word;
+ }
+
+ g_free (word);
+ }
+
+ /* Restore the selection to contain the last misspelled word. This is
+ * reached only when we reach the beginning/end of the document */
+ if (start && end)
+ webkit_dom_dom_selection_set_base_and_extent (
+ dom_selection, start, start_offset, end, end_offset, NULL);
+
+ g_clear_object (&dom_selection);
+
+ return NULL;
+}
+
+gchar *
+e_dialogs_dom_spell_check_next (EEditorPage *editor_page,
+ const gchar *from_word,
+ const gchar * const *languages)
+{
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+ return e_dialogs_dom_spell_check_run (editor_page, TRUE, from_word, languages);
+}
+
+gchar *
+e_dialogs_dom_spell_check_prev (EEditorPage *editor_page,
+ const gchar *from_word,
+ const gchar * const *languages)
+{
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+ return e_dialogs_dom_spell_check_run (editor_page, FALSE, from_word, languages);
+}
+
+/* ******************** Table Dialog ***************** */
+
+static WebKitDOMHTMLTableElement *
+get_current_table_element (WebKitDOMDocument *document)
+{
+ return WEBKIT_DOM_HTML_TABLE_ELEMENT (webkit_dom_document_get_element_by_id (document,
"-x-evo-current-table"));
+}
+
+void
+e_dialogs_dom_table_set_row_count (EEditorPage *editor_page,
+ gulong expected_count)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMHTMLCollection *rows = NULL, *cells = NULL;
+ WebKitDOMHTMLTableElement *table_element;
+ WebKitDOMHTMLTableRowElement *row;
+ gulong ii, rows_current_count, cells_current_count;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+
+ table_element = get_current_table_element (document);
+ if (!table_element)
+ return;
+
+ rows = webkit_dom_html_table_element_get_rows (table_element);
+ rows_current_count = webkit_dom_html_collection_get_length (rows);
+
+ if (rows_current_count < 1) {
+ g_clear_object (&rows);
+ return;
+ }
+
+ row = WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (webkit_dom_html_collection_item (rows, 0));
+ cells = webkit_dom_html_table_row_element_get_cells (row);
+ cells_current_count = webkit_dom_html_collection_get_length (cells);
+ g_object_unref (row);
+
+ if (rows_current_count < expected_count) {
+ for (ii = 0; ii < expected_count - rows_current_count; ii++) {
+ WebKitDOMHTMLElement *new_row;
+ gulong jj;
+
+ new_row = webkit_dom_html_table_element_insert_row (
+ table_element, -1, NULL);
+
+ for (jj = 0; jj < cells_current_count; jj++)
+ webkit_dom_html_table_row_element_insert_cell (
+ WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (new_row), -1, NULL);
+ }
+ } else if (rows_current_count > expected_count) {
+ for (ii = 0; ii < rows_current_count - expected_count; ii++) {
+ webkit_dom_html_table_element_delete_row (
+ table_element, -1, NULL);
+ }
+ }
+ g_clear_object (&cells);
+ g_clear_object (&rows);
+}
+
+gulong
+e_dialogs_dom_table_get_row_count (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMHTMLTableElement *table_element;
+ WebKitDOMHTMLCollection *rows = NULL;
+ glong count;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), 0);
+
+ document = e_editor_page_get_document (editor_page);
+
+ table_element = get_current_table_element (document);
+ if (!table_element)
+ return 0;
+
+ rows = webkit_dom_html_table_element_get_rows (table_element);
+
+ count = webkit_dom_html_collection_get_length (rows);
+ g_clear_object (&rows);
+
+ return count;
+}
+
+void
+e_dialogs_dom_table_set_column_count (EEditorPage *editor_page,
+ gulong expected_columns)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMHTMLTableElement *table_element;
+ WebKitDOMHTMLCollection *rows = NULL;
+ gulong ii, row_count;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+
+ table_element = get_current_table_element (document);
+ if (!table_element)
+ return;
+
+ rows = webkit_dom_html_table_element_get_rows (table_element);
+ row_count = webkit_dom_html_collection_get_length (rows);
+
+ for (ii = 0; ii < row_count; ii++) {
+ WebKitDOMHTMLTableRowElement *row;
+ WebKitDOMHTMLCollection *cells = NULL;
+ gulong jj, current_columns;
+
+ row = WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (
+ webkit_dom_html_collection_item (rows, ii));
+
+ cells = webkit_dom_html_table_row_element_get_cells (row);
+ current_columns = webkit_dom_html_collection_get_length (cells);
+
+ if (current_columns < expected_columns) {
+ for (jj = 0; jj < expected_columns - current_columns; jj++) {
+ webkit_dom_html_table_row_element_insert_cell (
+ row, -1, NULL);
+ }
+ } else if (expected_columns < current_columns) {
+ for (jj = 0; jj < current_columns - expected_columns; jj++) {
+ webkit_dom_html_table_row_element_delete_cell (
+ row, -1, NULL);
+ }
+ }
+ g_object_unref (row);
+ g_clear_object (&cells);
+ }
+ g_clear_object (&rows);
+}
+
+gulong
+e_dialogs_dom_table_get_column_count (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMHTMLTableElement *table_element;
+ WebKitDOMHTMLCollection *rows = NULL, *columns = NULL;
+ WebKitDOMNode *row;
+ glong count;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), 0);
+
+ document = e_editor_page_get_document (editor_page);
+
+ table_element = get_current_table_element (document);
+ if (!table_element)
+ return 0;
+
+ rows = webkit_dom_html_table_element_get_rows (table_element);
+ row = webkit_dom_html_collection_item (rows, 0);
+
+ columns = webkit_dom_html_table_row_element_get_cells (
+ WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (row));
+
+ count = webkit_dom_html_collection_get_length (columns);
+
+ g_object_unref (row);
+ g_clear_object (&rows);
+ g_clear_object (&columns);
+
+ return count;
+}
+
+static WebKitDOMElement *
+create_table (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *table, *br, *caret, *element, *cell;
+ WebKitDOMNode *clone;
+ gboolean empty = FALSE;
+ gchar *text_content;
+ gint i;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+ document = e_editor_page_get_document (editor_page);
+
+ /* Default 3x3 table */
+ table = webkit_dom_document_create_element (document, "TABLE", NULL);
+ for (i = 0; i < 3; i++) {
+ WebKitDOMHTMLElement *row;
+ gint j;
+
+ row = webkit_dom_html_table_element_insert_row (
+ WEBKIT_DOM_HTML_TABLE_ELEMENT (table), -1, NULL);
+
+ for (j = 0; j < 3; j++) {
+ webkit_dom_html_table_row_element_insert_cell (
+ WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (row), -1, NULL);
+ }
+ }
+
+ webkit_dom_element_set_id (table, "-x-evo-current-table");
+
+ e_editor_dom_selection_save (editor_page);
+ caret = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-end-marker");
+
+
+ element = get_parent_block_element (WEBKIT_DOM_NODE (caret));
+ text_content = webkit_dom_node_get_text_content (WEBKIT_DOM_NODE (element));
+ empty = text_content && !*text_content;
+ g_free (text_content);
+
+ clone = webkit_dom_node_clone_node_with_error (WEBKIT_DOM_NODE (element), FALSE, NULL);
+ br = webkit_dom_document_create_element (document, "BR", NULL);
+ webkit_dom_node_append_child (clone, WEBKIT_DOM_NODE (br), NULL);
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element)),
+ clone,
+ webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (element)),
+ NULL);
+
+ /* Move caret to the first cell */
+ cell = webkit_dom_element_query_selector (table, "td", NULL);
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (cell), WEBKIT_DOM_NODE (caret), NULL);
+ caret = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-start-marker");
+ webkit_dom_node_insert_before (
+ WEBKIT_DOM_NODE (cell),
+ WEBKIT_DOM_NODE (caret),
+ webkit_dom_node_get_last_child (WEBKIT_DOM_NODE (cell)),
+ NULL);
+
+ /* Insert the table into body unred the current block (if current block is not empty)
+ * otherwise replace the current block. */
+ if (empty) {
+ webkit_dom_node_replace_child (
+ webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element)),
+ WEBKIT_DOM_NODE (table),
+ WEBKIT_DOM_NODE (element),
+ NULL);
+ } else {
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element)),
+ WEBKIT_DOM_NODE (table),
+ webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (element)),
+ NULL);
+ }
+
+ e_editor_dom_selection_restore (editor_page);
+
+ e_editor_page_emit_content_changed (editor_page);
+
+ return table;
+}
+
+gboolean
+e_dialogs_dom_table_show (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMDOMWindow *dom_window = NULL;
+ WebKitDOMDOMSelection *dom_selection = NULL;
+ WebKitDOMElement *table = NULL;
+ EEditorUndoRedoManager *manager;
+ gboolean created = FALSE;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+ document = e_editor_page_get_document (editor_page);
+ dom_window = webkit_dom_document_get_default_view (document);
+ dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+ g_clear_object (&dom_window);
+ if (dom_selection && (webkit_dom_dom_selection_get_range_count (dom_selection) > 0)) {
+ WebKitDOMRange *range = NULL;
+
+ range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+ table = dom_node_find_parent_element (
+ webkit_dom_range_get_start_container (range, NULL), "TABLE");
+ g_clear_object (&range);
+
+ if (table) {
+ webkit_dom_element_set_id (table, "-x-evo-current-table");
+ } else {
+ table = create_table (editor_page);
+ created = TRUE;
+ }
+ }
+
+ manager = e_editor_page_get_undo_redo_manager (editor_page);
+ if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+ EEditorHistoryEvent *ev;
+
+ ev = g_new0 (EEditorHistoryEvent, 1);
+ ev->type = HISTORY_TABLE_DIALOG;
+
+ e_editor_dom_selection_get_coordinates (editor_page, &ev->before.start.x,
&ev->before.start.y, &ev->before.end.x, &ev->before.end.y);
+ if (!created)
+ ev->data.dom.from = webkit_dom_node_clone_node_with_error (
+ WEBKIT_DOM_NODE (table), TRUE, NULL);
+ else
+ ev->data.dom.from = NULL;
+
+ e_editor_undo_redo_manager_insert_history_event (manager, ev);
+ }
+
+ g_clear_object (&dom_selection);
+
+ return created;
+}
+
+void
+e_dialogs_dom_table_save_history_on_exit (EEditorPage *editor_page)
+{
+ EEditorHistoryEvent *ev = NULL;
+ EEditorUndoRedoManager *manager;
+ WebKitDOMDocument *document;
+ WebKitDOMElement *element;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+
+ element = WEBKIT_DOM_ELEMENT (get_current_table_element (document));
+ g_return_if_fail (element != NULL);
+
+ webkit_dom_element_remove_attribute (element, "id");
+
+ manager = e_editor_page_get_undo_redo_manager (editor_page);
+ ev = e_editor_undo_redo_manager_get_current_history_event (manager);
+ ev->data.dom.to = webkit_dom_node_clone_node_with_error (
+ WEBKIT_DOM_NODE (element), TRUE, NULL);
+
+ if (ev->data.dom.from && webkit_dom_node_is_equal_node (ev->data.dom.from, ev->data.dom.to))
+ e_editor_undo_redo_manager_remove_current_history_event (manager);
+ else
+ e_editor_dom_selection_get_coordinates (editor_page, &ev->after.start.x, &ev->after.start.y,
&ev->after.end.x, &ev->after.end.y);
+}
diff --git a/modules/webkit-editor/web-extension/e-dialogs-dom-functions.h
b/modules/webkit-editor/web-extension/e-dialogs-dom-functions.h
new file mode 100644
index 0000000..db28b49
--- /dev/null
+++ b/modules/webkit-editor/web-extension/e-dialogs-dom-functions.h
@@ -0,0 +1,134 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2016 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library 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.
+ *
+ * This library 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 this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef E_DIALOGS_DOM_FUNCTIONS_H
+#define E_DIALOGS_DOM_FUNCTIONS_H
+
+#include <webkit2/webkit-web-extension.h>
+
+#include "e-editor-page.h"
+
+G_BEGIN_DECLS
+
+/* ******************** Cell Dialog ***************** */
+
+void e_dialogs_dom_cell_mark_current_cell_element
+ (EEditorPage *editor_page,
+ const gchar *id);
+void e_dialogs_dom_cell_save_history_on_exit
+ (EEditorPage *editor_page);
+void e_dialogs_dom_cell_set_element_v_align
+ (EEditorPage *editor_page,
+ const gchar *v_align,
+ guint scope);
+void e_dialogs_dom_cell_set_element_align
+ (EEditorPage *editor_page,
+ const gchar *align,
+ guint scope);
+void e_dialogs_dom_cell_set_element_no_wrap
+ (EEditorPage *editor_page,
+ gboolean wrap_text,
+ guint scope);
+void e_dialogs_dom_cell_set_element_header_style
+ (EEditorPage *editor_page,
+ gboolean header_style,
+ guint scope);
+void e_dialogs_dom_cell_set_element_width
+ (EEditorPage *editor_page,
+ const gchar *width,
+ guint scope);
+void e_dialogs_dom_cell_set_element_col_span
+ (EEditorPage *editor_page,
+ glong span,
+ guint scope);
+void e_dialogs_dom_cell_set_element_row_span
+ (EEditorPage *editor_page,
+ glong span,
+ guint scope);
+void e_dialogs_dom_cell_set_element_bg_color
+ (EEditorPage *editor_page,
+ const gchar *color,
+ guint scope);
+
+/* ******************** HRule Dialog ***************** */
+
+gboolean e_dialogs_dom_h_rule_find_hrule (EEditorPage *editor_page);
+void e_dialogs_dom_h_rule_dialog_on_close
+ (EEditorPage *editor_page);
+
+/* ******************** Image Dialog ***************** */
+
+void e_dialogs_dom_image_mark_image (EEditorPage *editor_page);
+void e_dialogs_dom_image_save_history_on_exit
+ (EEditorPage *editor_page);
+void e_dialogs_dom_image_set_element_url
+ (EEditorPage *editor_page,
+ const gchar *url);
+gchar * e_dialogs_dom_image_get_element_url
+ (EEditorPage *editor_page);
+
+/* ******************** Link Dialog ***************** */
+
+void e_dialogs_dom_link_commit (EEditorPage *editor_page,
+ const gchar *url,
+ const gchar *inner_text);
+GVariant * e_dialogs_dom_link_show (EEditorPage *editor_page);
+void e_dialogs_dom_link_dialog_on_open
+ (EEditorPage *editor_page);
+void e_dialogs_dom_link_dialog_on_close
+ (EEditorPage *editor_page);
+
+/* ******************** Page Dialog ***************** */
+
+void e_dialogs_dom_page_save_history (EEditorPage *editor_page);
+void e_dialogs_dom_page_save_history_on_exit
+ (EEditorPage *editor_page);
+
+/* ******************** Spell Check Dialog ***************** */
+
+gchar * e_dialogs_dom_spell_check_prev (EEditorPage *editor_page,
+ const gchar *from_word,
+ const gchar * const *languages);
+
+gchar * e_dialogs_dom_spell_check_next (EEditorPage *editor_page,
+ const gchar *from_word,
+ const gchar * const *languages);
+
+/* ******************** Table Dialog ***************** */
+
+void e_dialogs_dom_table_set_row_count
+ (EEditorPage *editor_page,
+ gulong expected_count);
+
+gulong e_dialogs_dom_table_get_row_count
+ (EEditorPage *editor_page);
+
+void e_dialogs_dom_table_set_column_count
+ (EEditorPage *editor_page,
+ gulong expected_columns);
+
+gulong e_dialogs_dom_table_get_column_count
+ (EEditorPage *editor_page);
+
+gboolean e_dialogs_dom_table_show (EEditorPage *editor_page);
+
+void e_dialogs_dom_table_save_history_on_exit
+ (EEditorPage *editor_page);
+
+G_END_DECLS
+
+#endif /* E_DIALOGS_DOM_FUNCTIONS_H */
diff --git a/modules/webkit-editor/web-extension/e-editor-dom-functions.c
b/modules/webkit-editor/web-extension/e-editor-dom-functions.c
new file mode 100644
index 0000000..ecc833d
--- /dev/null
+++ b/modules/webkit-editor/web-extension/e-editor-dom-functions.c
@@ -0,0 +1,17386 @@
+/*
+ * Copyright (C) 2016 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library 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.
+ *
+ * This library 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 this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#define WEBKIT_DOM_USE_UNSTABLE_API
+#include <webkitdom/WebKitDOMDocumentUnstable.h>
+#include <webkitdom/WebKitDOMDocumentFragmentUnstable.h>
+#include <webkitdom/WebKitDOMDOMSelection.h>
+#include <webkitdom/WebKitDOMDOMWindowUnstable.h>
+#include <webkitdom/WebKitDOMHTMLElementUnstable.h>
+#include <webkitdom/WebKitDOMRangeUnstable.h>
+#undef WEBKIT_DOM_USE_UNSTABLE_API
+
+#include "web-extensions/e-dom-utils.h"
+
+#include "e-editor-page.h"
+#include "e-editor-undo-redo-manager.h"
+
+#include "e-editor-dom-functions.h"
+
+#define HTML_KEY_CODE_BACKSPACE 8
+#define HTML_KEY_CODE_RETURN 13
+#define HTML_KEY_CODE_CONTROL 17
+#define HTML_KEY_CODE_SPACE 32
+#define HTML_KEY_CODE_DELETE 46
+#define HTML_KEY_CODE_TABULATOR 9
+
+/* ******************** Tests ******************** */
+
+static gchar *
+workaround_spaces (const gchar *text)
+{
+ GString *tmp;
+ gchar *str = NULL;
+
+ tmp = e_str_replace_string (text, " ", " ");
+ if (tmp) {
+ str = g_string_free (tmp, FALSE);
+ text = str;
+ }
+
+ tmp = e_str_replace_string (text, "Â ", " ");
+ if (tmp) {
+ g_free (str);
+ str = g_string_free (tmp, FALSE);
+ } else if (!str) {
+ str = g_strdup (text);
+ }
+
+ return str;
+}
+
+gboolean
+e_editor_dom_test_html_equal (WebKitDOMDocument *document,
+ const gchar *html1,
+ const gchar *html2)
+{
+ WebKitDOMElement *elem1, *elem2;
+ gchar *str1, *str2;
+ gboolean res = FALSE;
+ GError *error = NULL;
+
+ g_return_val_if_fail (WEBKIT_DOM_IS_DOCUMENT (document), FALSE);
+ g_return_val_if_fail (html1 != NULL, FALSE);
+ g_return_val_if_fail (html2 != NULL, FALSE);
+
+ elem1 = webkit_dom_document_create_element (document, "TestHtmlEqual", &error);
+ if (error || !elem1) {
+ g_warning ("%s: Failed to create elem1: %s", G_STRFUNC, error ? error->message : "Unknown
error");
+ g_clear_error (&error);
+ return FALSE;
+ }
+
+ elem2 = webkit_dom_document_create_element (document, "TestHtmlEqual", &error);
+ if (error || !elem2) {
+ g_warning ("%s: Failed to create elem2: %s", G_STRFUNC, error ? error->message : "Unknown
error");
+ g_clear_error (&error);
+ return FALSE;
+ }
+
+ /* FIXME WK2: Workaround when is used instead of regular spaces. (Placed by WebKit?) */
+ str1 = workaround_spaces (html1);
+ str2 = workaround_spaces (html2);
+
+ webkit_dom_element_set_inner_html (elem1, str1, &error);
+ if (!error) {
+ webkit_dom_element_set_inner_html (elem2, str2, &error);
+
+ if (!error) {
+ webkit_dom_node_normalize (WEBKIT_DOM_NODE (elem1));
+ webkit_dom_node_normalize (WEBKIT_DOM_NODE (elem2));
+
+ res = webkit_dom_node_is_equal_node (WEBKIT_DOM_NODE (elem1), WEBKIT_DOM_NODE
(elem2));
+ } else {
+ g_warning ("%s: Failed to set inner html2: %s", G_STRFUNC, error->message);
+ }
+ } else {
+ g_warning ("%s: Failed to set inner html1: %s", G_STRFUNC, error->message);
+ }
+
+ if (res && (g_strcmp0 (html1, str1) != 0 || g_strcmp0 (html2, str2) != 0))
+ g_warning ("%s: Applied the ' ' workaround", G_STRFUNC);
+
+ g_clear_error (&error);
+ g_free (str1);
+ g_free (str2);
+
+ return res;
+}
+
+/* ******************** Actions ******************** */
+
+static WebKitDOMElement *
+get_table_cell_element (WebKitDOMDocument *document)
+{
+ return webkit_dom_document_get_element_by_id (document, "-x-evo-current-cell");
+}
+
+static void
+prepare_history_for_table (EEditorPage *editor_page,
+ WebKitDOMElement *table,
+ EEditorHistoryEvent *ev)
+{
+ ev->type = HISTORY_TABLE_DIALOG;
+
+ e_editor_dom_selection_get_coordinates (editor_page, &ev->before.start.x, &ev->before.start.y,
&ev->before.end.x, &ev->before.end.y);
+
+ ev->data.dom.from = webkit_dom_node_clone_node_with_error (
+ WEBKIT_DOM_NODE (table), TRUE, NULL);
+}
+
+
+static void
+save_history_for_table (EEditorPage *editor_page,
+ WebKitDOMElement *table,
+ EEditorHistoryEvent *ev)
+{
+ EEditorUndoRedoManager *manager;
+
+ if (table)
+ ev->data.dom.to = webkit_dom_node_clone_node_with_error (
+ WEBKIT_DOM_NODE (table), TRUE, NULL);
+ else
+ ev->data.dom.to = NULL;
+
+ e_editor_dom_selection_get_coordinates (editor_page,
+ &ev->after.start.x, &ev->after.start.y, &ev->after.end.x, &ev->after.end.y);
+
+ manager = e_editor_page_get_undo_redo_manager (editor_page);
+ e_editor_undo_redo_manager_insert_history_event (manager, ev);
+}
+
+void
+e_editor_dom_delete_cell_contents (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMNode *node;
+ WebKitDOMElement *cell, *table_cell, *table;
+ EEditorHistoryEvent *ev = NULL;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+
+ table_cell = get_table_cell_element (document);
+ g_return_if_fail (table_cell != NULL);
+
+ cell = dom_node_find_parent_element (WEBKIT_DOM_NODE (table_cell), "TD");
+ if (!cell)
+ cell = dom_node_find_parent_element (WEBKIT_DOM_NODE (table_cell), "TH");
+ g_return_if_fail (cell != NULL);
+
+ table = dom_node_find_parent_element (WEBKIT_DOM_NODE (cell), "TABLE");
+ g_return_if_fail (table != NULL);
+
+ ev = g_new0 (EEditorHistoryEvent, 1);
+ prepare_history_for_table (editor_page, table, ev);
+
+ while ((node = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (cell))))
+ remove_node (node);
+
+ save_history_for_table (editor_page, table, ev);
+}
+
+void
+e_editor_dom_delete_column (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *cell, *table, *table_cell;
+ WebKitDOMHTMLCollection *rows = NULL;
+ EEditorHistoryEvent *ev = NULL;
+ gulong index, length, ii;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+
+ table_cell = get_table_cell_element (document);
+ g_return_if_fail (table_cell != NULL);
+
+ /* Find TD in which the selection starts */
+ cell = dom_node_find_parent_element (WEBKIT_DOM_NODE (table_cell), "TD");
+ if (!cell)
+ cell = dom_node_find_parent_element (WEBKIT_DOM_NODE (table_cell), "TH");
+ g_return_if_fail (cell != NULL);
+
+ table = dom_node_find_parent_element (WEBKIT_DOM_NODE (cell), "TABLE");
+ g_return_if_fail (table != NULL);
+
+ ev = g_new0 (EEditorHistoryEvent, 1);
+ prepare_history_for_table (editor_page, table, ev);
+
+ rows = webkit_dom_html_table_element_get_rows (
+ WEBKIT_DOM_HTML_TABLE_ELEMENT (table));
+ length = webkit_dom_html_collection_get_length (rows);
+
+ index = webkit_dom_html_table_cell_element_get_cell_index (
+ WEBKIT_DOM_HTML_TABLE_CELL_ELEMENT (cell));
+
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMNode *row;
+
+ row = webkit_dom_html_collection_item (rows, ii);
+
+ webkit_dom_html_table_row_element_delete_cell (
+ WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (row), index, NULL);
+ g_object_unref (row);
+ }
+
+ g_clear_object (&rows);
+
+ save_history_for_table (editor_page, table, ev);
+}
+
+void
+e_editor_dom_delete_row (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *row, *table, *table_cell;
+ EEditorHistoryEvent *ev = NULL;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+
+ table_cell = get_table_cell_element (document);
+ g_return_if_fail (table_cell != NULL);
+
+ row = dom_node_find_parent_element (WEBKIT_DOM_NODE (table_cell), "TR");
+ g_return_if_fail (row != NULL);
+
+ table = dom_node_find_parent_element (WEBKIT_DOM_NODE (table_cell), "TABLE");
+ g_return_if_fail (table != NULL);
+
+ ev = g_new0 (EEditorHistoryEvent, 1);
+ prepare_history_for_table (editor_page, table, ev);
+
+ remove_node (WEBKIT_DOM_NODE (row));
+
+ save_history_for_table (editor_page, table, ev);
+}
+
+void
+e_editor_dom_delete_table (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *table, *table_cell;
+ EEditorHistoryEvent *ev = NULL;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+
+ table_cell = get_table_cell_element (document);
+ g_return_if_fail (table_cell != NULL);
+
+ table = dom_node_find_parent_element (WEBKIT_DOM_NODE (table_cell), "TABLE");
+ g_return_if_fail (table != NULL);
+
+ ev = g_new0 (EEditorHistoryEvent, 1);
+ prepare_history_for_table (editor_page, table, ev);
+
+ remove_node (WEBKIT_DOM_NODE (table));
+
+ save_history_for_table (editor_page, NULL, ev);
+}
+
+void
+e_editor_dom_insert_column_after (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *cell, *row, *table_cell, *table;
+ EEditorHistoryEvent *ev = NULL;
+ gulong index;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+
+ table_cell = get_table_cell_element (document);
+ g_return_if_fail (table_cell != NULL);
+
+ cell = dom_node_find_parent_element (WEBKIT_DOM_NODE (table_cell), "TD");
+ if (!cell)
+ cell = dom_node_find_parent_element (WEBKIT_DOM_NODE (table_cell), "TH");
+ g_return_if_fail (cell != NULL);
+
+ row = dom_node_find_parent_element (WEBKIT_DOM_NODE (cell), "TR");
+ g_return_if_fail (row != NULL);
+
+ table = dom_node_find_parent_element (WEBKIT_DOM_NODE (table_cell), "TABLE");
+ g_return_if_fail (table != NULL);
+
+ ev = g_new0 (EEditorHistoryEvent, 1);
+ prepare_history_for_table (editor_page, table, ev);
+
+ /* Get the first row in the table */
+ row = WEBKIT_DOM_ELEMENT (
+ webkit_dom_node_get_first_child (
+ webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (row))));
+
+ index = webkit_dom_html_table_cell_element_get_cell_index (
+ WEBKIT_DOM_HTML_TABLE_CELL_ELEMENT (cell));
+
+ while (row) {
+ webkit_dom_html_table_row_element_insert_cell (
+ WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (row), index + 1, NULL);
+
+ row = WEBKIT_DOM_ELEMENT (
+ webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (row)));
+ }
+
+ save_history_for_table (editor_page, table, ev);
+}
+
+void
+e_editor_dom_insert_column_before (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *cell, *row, *table_cell, *table;
+ EEditorHistoryEvent *ev = NULL;
+ gulong index;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+
+ table_cell = get_table_cell_element (document);
+ g_return_if_fail (table_cell != NULL);
+
+ cell = dom_node_find_parent_element (WEBKIT_DOM_NODE (table_cell), "TD");
+ if (!cell) {
+ cell = dom_node_find_parent_element (WEBKIT_DOM_NODE (table_cell), "TH");
+ }
+ g_return_if_fail (cell != NULL);
+
+ row = dom_node_find_parent_element (WEBKIT_DOM_NODE (table_cell), "TR");
+ g_return_if_fail (row != NULL);
+
+ table = dom_node_find_parent_element (WEBKIT_DOM_NODE (table_cell), "TABLE");
+ g_return_if_fail (table != NULL);
+
+ ev = g_new0 (EEditorHistoryEvent, 1);
+ prepare_history_for_table (editor_page, table, ev);
+
+ /* Get the first row in the table */
+ row = WEBKIT_DOM_ELEMENT (
+ webkit_dom_node_get_first_child (
+ webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (row))));
+
+ index = webkit_dom_html_table_cell_element_get_cell_index (
+ WEBKIT_DOM_HTML_TABLE_CELL_ELEMENT (cell));
+
+ while (row) {
+ webkit_dom_html_table_row_element_insert_cell (
+ WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (row), index - 1, NULL);
+
+ row = WEBKIT_DOM_ELEMENT (
+ webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (row)));
+ }
+
+ save_history_for_table (editor_page, table, ev);
+}
+
+void
+e_editor_dom_insert_row_above (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *row, *table, *table_cell;
+ WebKitDOMHTMLCollection *cells = NULL;
+ WebKitDOMHTMLElement *new_row;
+ EEditorHistoryEvent *ev = NULL;
+ gulong index, cell_count, ii;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+
+ table_cell = get_table_cell_element (document);
+ g_return_if_fail (table_cell != NULL);
+
+ row = dom_node_find_parent_element (WEBKIT_DOM_NODE (table_cell), "TR");
+ g_return_if_fail (row != NULL);
+
+ table = dom_node_find_parent_element (WEBKIT_DOM_NODE (row), "TABLE");
+ g_return_if_fail (table != NULL);
+
+ ev = g_new0 (EEditorHistoryEvent, 1);
+ prepare_history_for_table (editor_page, table, ev);
+
+ index = webkit_dom_html_table_row_element_get_row_index (
+ WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (row));
+
+ new_row = webkit_dom_html_table_element_insert_row (
+ WEBKIT_DOM_HTML_TABLE_ELEMENT (table), index, NULL);
+
+ cells = webkit_dom_html_table_row_element_get_cells (
+ WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (row));
+ cell_count = webkit_dom_html_collection_get_length (cells);
+ for (ii = 0; ii < cell_count; ii++) {
+ webkit_dom_html_table_row_element_insert_cell (
+ WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (new_row), -1, NULL);
+ }
+
+ g_clear_object (&cells);
+
+ save_history_for_table (editor_page, table, ev);
+}
+
+void
+e_editor_dom_insert_row_below (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *row, *table, *table_cell;
+ WebKitDOMHTMLCollection *cells = NULL;
+ WebKitDOMHTMLElement *new_row;
+ EEditorHistoryEvent *ev = NULL;
+ gulong index, cell_count, ii;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+
+ table_cell = get_table_cell_element (document);
+ g_return_if_fail (table_cell != NULL);
+
+ row = dom_node_find_parent_element (WEBKIT_DOM_NODE (table_cell), "TR");
+ g_return_if_fail (row != NULL);
+
+ table = dom_node_find_parent_element (WEBKIT_DOM_NODE (row), "TABLE");
+ g_return_if_fail (table != NULL);
+
+ ev = g_new0 (EEditorHistoryEvent, 1);
+ prepare_history_for_table (editor_page, table, ev);
+
+ index = webkit_dom_html_table_row_element_get_row_index (
+ WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (row));
+
+ new_row = webkit_dom_html_table_element_insert_row (
+ WEBKIT_DOM_HTML_TABLE_ELEMENT (table), index + 1, NULL);
+
+ cells = webkit_dom_html_table_row_element_get_cells (
+ WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (row));
+ cell_count = webkit_dom_html_collection_get_length (cells);
+ for (ii = 0; ii < cell_count; ii++) {
+ webkit_dom_html_table_row_element_insert_cell (
+ WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (new_row), -1, NULL);
+ }
+
+ g_clear_object (&cells);
+
+ save_history_for_table (editor_page, table, ev);
+}
+
+void
+e_editor_dom_save_history_for_cut (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMDocumentFragment *fragment;
+ WebKitDOMDOMWindow *dom_window = NULL;
+ WebKitDOMDOMSelection *dom_selection = NULL;
+ WebKitDOMRange *range = NULL;
+ EEditorHistoryEvent *ev;
+ EEditorUndoRedoManager *manager;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+ dom_window = webkit_dom_document_get_default_view (document);
+ dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+ g_clear_object (&dom_window);
+
+ if (!webkit_dom_dom_selection_get_range_count (dom_selection) ||
+ webkit_dom_dom_selection_get_is_collapsed (dom_selection)) {
+ g_clear_object (&dom_selection);
+ return;
+ }
+
+ range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+
+ ev = g_new0 (EEditorHistoryEvent, 1);
+ ev->type = HISTORY_DELETE;
+
+ e_editor_dom_selection_get_coordinates (editor_page,
+ &ev->before.start.x,
+ &ev->before.start.y,
+ &ev->before.end.x,
+ &ev->before.end.y);
+
+ ev->after.start.x = ev->before.start.x;
+ ev->after.start.y = ev->before.start.y;
+ ev->after.end.x = ev->before.start.x;
+ ev->after.end.y = ev->before.start.y;
+
+ /* Save the fragment. */
+ fragment = webkit_dom_range_clone_contents (range, NULL);
+ g_clear_object (&dom_selection);
+ g_clear_object (&range);
+ ev->data.fragment = g_object_ref (fragment);
+
+ manager = e_editor_page_get_undo_redo_manager (editor_page);
+ e_editor_undo_redo_manager_insert_history_event (manager, ev);
+ e_editor_page_set_dont_save_history_in_body_input (editor_page, TRUE);
+}
+
+/* ******************** View ******************** */
+
+/*
+ * e_editor_dom_exec_command:
+ * @document: a #WebKitDOMDocument
+ * @command: an #EContentEditorCommand to execute
+ * @value: value of the command (or @NULL if the command does not require value)
+ *
+ * The function will fail when @value is @NULL or empty but the current @command
+ * requires a value to be passed. The @value is ignored when the @command does
+ * not expect any value.
+ *
+ * Returns: @TRUE when the command was succesfully executed, @FALSE otherwise.
+ */
+gboolean
+e_editor_dom_exec_command (EEditorPage *editor_page,
+ EContentEditorCommand command,
+ const gchar *value)
+{
+ const gchar *cmd_str = 0;
+ gboolean has_value = FALSE;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+#define CHECK_COMMAND(cmd,str,val) case cmd:\
+ if (val) {\
+ g_return_val_if_fail (value && *value, FALSE);\
+ }\
+ has_value = val; \
+ cmd_str = str;\
+ break;
+
+ switch (command) {
+ CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_BACKGROUND_COLOR, "BackColor", TRUE)
+ CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_BOLD, "Bold", FALSE)
+ CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_COPY, "Copy", FALSE)
+ CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_CREATE_LINK, "CreateLink", TRUE)
+ CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_CUT, "Cut", FALSE)
+ CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_DEFAULT_PARAGRAPH_SEPARATOR,
"DefaultParagraphSeparator", FALSE)
+ CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_DELETE, "Delete", FALSE)
+ CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_FIND_STRING, "FindString", TRUE)
+ CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_FONT_NAME, "FontName", TRUE)
+ CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_FONT_SIZE, "FontSize", TRUE)
+ CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_FONT_SIZE_DELTA, "FontSizeDelta", TRUE)
+ CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_FORE_COLOR, "ForeColor", TRUE)
+ CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_FORMAT_BLOCK, "FormatBlock", TRUE)
+ CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_FORWARD_DELETE, "ForwardDelete", FALSE)
+ CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_HILITE_COLOR, "HiliteColor", TRUE)
+ CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_INDENT, "Indent", FALSE)
+ CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_INSERT_HORIZONTAL_RULE, "InsertHorizontalRule", FALSE)
+ CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_INSERT_HTML, "InsertHTML", TRUE)
+ CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_INSERT_IMAGE, "InsertImage", TRUE)
+ CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_INSERT_LINE_BREAK, "InsertLineBreak", FALSE)
+ CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_INSERT_NEW_LINE_IN_QUOTED_CONTENT,
"InsertNewlineInQuotedContent", FALSE)
+ CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_INSERT_ORDERED_LIST, "InsertOrderedList", FALSE)
+ CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_INSERT_PARAGRAPH, "InsertParagraph", FALSE)
+ CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_INSERT_TEXT, "InsertText", TRUE)
+ CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_INSERT_UNORDERED_LIST, "InsertUnorderedList", FALSE)
+ CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_ITALIC, "Italic", FALSE)
+ CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_JUSTIFY_CENTER, "JustifyCenter", FALSE)
+ CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_JUSTIFY_FULL, "JustifyFull", FALSE)
+ CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_JUSTIFY_LEFT, "JustifyLeft", FALSE)
+ CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_JUSTIFY_NONE, "JustifyNone", FALSE)
+ CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_JUSTIFY_RIGHT, "JustifyRight", FALSE)
+ CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_OUTDENT, "Outdent", FALSE)
+ CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_PASTE, "Paste", FALSE)
+ CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_PASTE_AND_MATCH_STYLE, "PasteAndMatchStyle", FALSE)
+ CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_PASTE_AS_PLAIN_TEXT, "PasteAsPlainText", FALSE)
+ CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_PRINT, "Print", FALSE)
+ CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_REDO, "Redo", FALSE)
+ CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_REMOVE_FORMAT, "RemoveFormat", FALSE)
+ CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_SELECT_ALL, "SelectAll", FALSE)
+ CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_STRIKETHROUGH, "Strikethrough", FALSE)
+ CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_STYLE_WITH_CSS, "StyleWithCSS", TRUE)
+ CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_SUBSCRIPT, "Subscript", FALSE)
+ CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_SUPERSCRIPT, "Superscript", FALSE)
+ CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_TRANSPOSE, "Transpose", FALSE)
+ CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_UNDERLINE, "Underline", FALSE)
+ CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_UNDO, "Undo", FALSE)
+ CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_UNLINK, "Unlink", FALSE)
+ CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_UNSELECT, "Unselect", FALSE)
+ CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_USE_CSS, "UseCSS", TRUE)
+ }
+
+ e_editor_page_set_dont_save_history_in_body_input (editor_page, TRUE);
+
+ return webkit_dom_document_exec_command (
+ e_editor_page_get_document (editor_page), cmd_str, FALSE, has_value ? value : "" );
+}
+
+static void
+perform_spell_check (WebKitDOMDOMSelection *dom_selection,
+ WebKitDOMRange *start_range,
+ WebKitDOMRange *end_range)
+{
+ WebKitDOMRange *actual = start_range;
+
+ /* FIXME WK2: this doesn't work, the cursor is moved, but the spellcheck is not updated */
+ /* Go through all words to spellcheck them. To avoid this we have to wait for
+ * http://www.w3.org/html/wg/drafts/html/master/editing.html#dom-forcespellcheck */
+ /* We are moving forward word by word until we hit the text on the end. */
+ while (actual && webkit_dom_range_compare_boundary_points (end_range, WEBKIT_DOM_RANGE_END_TO_END,
actual, NULL) != 0) {
+ if (actual != start_range)
+ g_object_unref (actual);
+ webkit_dom_dom_selection_modify (
+ dom_selection, "move", "forward", "word");
+ actual = webkit_dom_dom_selection_get_range_at (
+ dom_selection, 0, NULL);
+ }
+ g_clear_object (&actual);
+}
+
+void
+e_editor_dom_force_spell_check_for_current_paragraph (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMDOMSelection *dom_selection = NULL;
+ WebKitDOMDOMWindow *dom_window = NULL;
+ WebKitDOMElement *selection_start_marker, *selection_end_marker;
+ WebKitDOMElement *parent, *element;
+ WebKitDOMRange *end_range = NULL, *actual = NULL;
+ WebKitDOMText *text;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+
+ if (!e_editor_page_get_inline_spelling_enabled (editor_page))
+ return;
+
+ document = e_editor_page_get_document (editor_page);
+ element = webkit_dom_document_query_selector (
+ document, "body[spellcheck=true]", NULL);
+
+ if (!element)
+ return;
+
+ if (!webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (element)))
+ return;
+
+ e_editor_dom_selection_save (editor_page);
+
+ selection_start_marker = webkit_dom_document_query_selector (
+ document, "span#-x-evo-selection-start-marker", NULL);
+ selection_end_marker = webkit_dom_document_query_selector (
+ document, "span#-x-evo-selection-end-marker", NULL);
+
+ if (!selection_start_marker || !selection_end_marker)
+ return;
+
+ /* Block callbacks of selection-changed signal as we don't want to
+ * recount all the block format things in EEditorSelection and here as well
+ * when we are moving with caret */
+ e_editor_page_block_selection_changed (editor_page);
+
+ parent = get_parent_block_element (WEBKIT_DOM_NODE (selection_end_marker));
+
+ /* Append some text on the end of the element */
+ text = webkit_dom_document_create_text_node (document, "-x-evo-end");
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (parent),
+ WEBKIT_DOM_NODE (text),
+ NULL);
+
+ parent = get_parent_block_element (WEBKIT_DOM_NODE (selection_start_marker));
+
+ /* Create range that's pointing on the end of this text */
+ end_range = webkit_dom_document_create_range (document);
+ webkit_dom_range_select_node_contents (
+ end_range, WEBKIT_DOM_NODE (text), NULL);
+ webkit_dom_range_collapse (end_range, FALSE, NULL);
+
+ /* Move on the beginning of the paragraph */
+ dom_window = webkit_dom_document_get_default_view (document);
+ dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+
+ actual = webkit_dom_document_create_range (document);
+ webkit_dom_range_select_node_contents (
+ actual, WEBKIT_DOM_NODE (parent), NULL);
+ webkit_dom_range_collapse (actual, TRUE, NULL);
+ webkit_dom_dom_selection_remove_all_ranges (dom_selection);
+ webkit_dom_dom_selection_add_range (dom_selection, actual);
+ g_clear_object (&actual);
+
+ actual = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+ perform_spell_check (dom_selection, actual, end_range);
+
+ g_clear_object (&dom_selection);
+ g_clear_object (&dom_window);
+ g_clear_object (&end_range);
+ g_clear_object (&actual);
+
+ /* Remove the text that we inserted on the end of the paragraph */
+ remove_node (WEBKIT_DOM_NODE (text));
+
+ /* Unblock the callbacks */
+ e_editor_page_unblock_selection_changed (editor_page);
+
+ e_editor_dom_selection_restore (editor_page);
+}
+
+static void
+refresh_spell_check (EEditorPage *editor_page,
+ gboolean enable_spell_check)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMDOMSelection *dom_selection = NULL;
+ WebKitDOMDOMWindow *dom_window = NULL;
+ WebKitDOMElement *selection_start_marker, *selection_end_marker;
+ WebKitDOMHTMLElement *body;
+ WebKitDOMRange *end_range = NULL, *actual = NULL;
+ WebKitDOMText *text;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+ body = webkit_dom_document_get_body (document);
+
+ if (!webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (body)))
+ return;
+
+ /* Enable/Disable spellcheck in composer */
+ webkit_dom_element_set_attribute (
+ WEBKIT_DOM_ELEMENT (body),
+ "spellcheck",
+ enable_spell_check ? "true" : "false",
+ NULL);
+ webkit_dom_html_element_set_spellcheck (body, FALSE);
+ webkit_dom_html_element_set_spellcheck (body, enable_spell_check);
+ return;
+
+ e_editor_dom_selection_save (editor_page);
+
+ selection_start_marker = webkit_dom_document_query_selector (
+ document, "span#-x-evo-selection-start-marker", NULL);
+ selection_end_marker = webkit_dom_document_query_selector (
+ document, "span#-x-evo-selection-end-marker", NULL);
+
+ /* Sometimes the web view is not focused, so we have to save the selection
+ * manually into the body */
+ if (!selection_start_marker || !selection_end_marker) {
+ WebKitDOMNode *child;
+
+ child = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (body));
+ if (!WEBKIT_DOM_IS_HTML_ELEMENT (child))
+ return;
+
+ dom_add_selection_markers_into_element_start (
+ document,
+ WEBKIT_DOM_ELEMENT (child),
+ &selection_start_marker,
+ &selection_end_marker);
+ }
+
+ /* Block callbacks of selection-changed signal as we don't want to
+ * recount all the block format things in EEditorSelection and here as well
+ * when we are moving with caret */
+ e_editor_page_block_selection_changed (editor_page);
+
+ /* Append some text on the end of the body */
+ text = webkit_dom_document_create_text_node (document, "-x-evo-end");
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (body), WEBKIT_DOM_NODE (text), NULL);
+
+ /* Create range that's pointing on the end of this text */
+ end_range = webkit_dom_document_create_range (document);
+ webkit_dom_range_select_node_contents (
+ end_range, WEBKIT_DOM_NODE (text), NULL);
+ webkit_dom_range_collapse (end_range, FALSE, NULL);
+
+ dom_window = webkit_dom_document_get_default_view (document);
+ dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+
+ /* Move on the beginning of the document */
+ webkit_dom_dom_selection_modify (
+ dom_selection, "move", "backward", "documentboundary");
+
+ actual = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+ perform_spell_check (dom_selection, actual, end_range);
+
+ g_clear_object (&dom_selection);
+ g_clear_object (&dom_window);
+ g_clear_object (&end_range);
+ g_clear_object (&actual);
+
+ /* Remove the text that we inserted on the end of the body */
+ remove_node (WEBKIT_DOM_NODE (text));
+
+ /* Unblock the callbacks */
+ e_editor_page_unblock_selection_changed (editor_page);
+
+ e_editor_dom_selection_restore (editor_page);
+}
+
+void
+e_editor_dom_turn_spell_check_off (EEditorPage *editor_page)
+{
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ refresh_spell_check (editor_page, FALSE);
+}
+
+void
+e_editor_dom_force_spell_check_in_viewport (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMDOMSelection *dom_selection = NULL;
+ WebKitDOMDOMWindow *dom_window = NULL;
+ WebKitDOMElement *last_element;
+ WebKitDOMHTMLElement *body;
+ WebKitDOMRange *end_range = NULL, *actual = NULL;
+ WebKitDOMText *text;
+ glong viewport_height;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ if (!e_editor_page_get_inline_spelling_enabled (editor_page))
+ return;
+
+ document = e_editor_page_get_document (editor_page);
+ body = WEBKIT_DOM_HTML_ELEMENT (webkit_dom_document_query_selector (
+ document, "body[spellcheck=true]", NULL));
+
+ if (!body) {
+ body = webkit_dom_document_get_body (document);
+ webkit_dom_element_set_attribute (
+ WEBKIT_DOM_ELEMENT (body), "spellcheck", "true", NULL);
+ }
+
+ if (!webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (body)))
+ return;
+
+ e_editor_dom_selection_save (editor_page);
+
+ /* Block callbacks of selection-changed signal as we don't want to
+ * recount all the block format things in EEditorSelection and here as well
+ * when we are moving with caret */
+ e_editor_page_block_selection_changed (editor_page);
+
+ /* We have to add 10 px offset as otherwise just the HTML element will be returned */
+ actual = webkit_dom_document_caret_range_from_point (document, 10, 10);
+ if (!actual)
+ goto out;
+
+ /* Append some text on the end of the body */
+ text = webkit_dom_document_create_text_node (document, "-x-evo-end");
+
+ dom_window = webkit_dom_document_get_default_view (document);
+ dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+
+ /* We have to add 10 px offset as otherwise just the HTML element will be returned */
+ viewport_height = webkit_dom_dom_window_get_inner_height (dom_window);
+ last_element = webkit_dom_document_element_from_point (document, 10, viewport_height - 10);
+ if (last_element && !WEBKIT_DOM_IS_HTML_HTML_ELEMENT (last_element) &&
+ !WEBKIT_DOM_IS_HTML_BODY_ELEMENT (last_element)) {
+ WebKitDOMElement *parent;
+
+ parent = get_parent_block_element (WEBKIT_DOM_NODE (last_element));
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (parent), WEBKIT_DOM_NODE (text), NULL);
+ } else
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (body), WEBKIT_DOM_NODE (text), NULL);
+
+ /* Create range that's pointing on the end of viewport */
+ end_range = webkit_dom_document_create_range (document);
+ webkit_dom_range_select_node_contents (
+ end_range, WEBKIT_DOM_NODE (text), NULL);
+ webkit_dom_range_collapse (end_range, FALSE, NULL);
+
+ webkit_dom_dom_selection_remove_all_ranges (dom_selection);
+ webkit_dom_dom_selection_add_range (dom_selection, actual);
+ perform_spell_check (dom_selection, actual, end_range);
+
+ g_clear_object (&dom_selection);
+ g_clear_object (&dom_window);
+ g_clear_object (&end_range);
+ g_clear_object (&actual);
+
+ /* Remove the text that we inserted on the end of the body */
+ remove_node (WEBKIT_DOM_NODE (text));
+
+ out:
+ /* Unblock the callbacks */
+ e_editor_page_unblock_selection_changed (editor_page);
+
+ e_editor_dom_selection_restore (editor_page);
+}
+
+void
+e_editor_dom_force_spell_check (EEditorPage *editor_page)
+{
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ if (e_editor_page_get_inline_spelling_enabled (editor_page))
+ refresh_spell_check (editor_page, TRUE);
+}
+
+gboolean
+e_editor_dom_node_is_citation_node (WebKitDOMNode *node)
+{
+ gchar *value;
+
+ if (!WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (node))
+ return FALSE;
+
+ value = webkit_dom_element_get_attribute (WEBKIT_DOM_ELEMENT (node), "type");
+
+ /* citation == <blockquote type='cite'> */
+ if (value && g_strcmp0 (value, "cite") == 0) {
+ g_free (value);
+ return TRUE;
+ } else {
+ g_free (value);
+ return FALSE;
+ }
+}
+
+gint
+e_editor_dom_get_citation_level (WebKitDOMNode *node,
+ gboolean set_plaintext_quoted)
+{
+ WebKitDOMNode *parent = node;
+ gint level = 0;
+
+ while (parent && !WEBKIT_DOM_IS_HTML_BODY_ELEMENT (parent)) {
+ if (WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (parent) &&
+ webkit_dom_element_has_attribute (WEBKIT_DOM_ELEMENT (parent), "type"))
+ level++;
+
+ parent = webkit_dom_node_get_parent_node (parent);
+ }
+
+ return level;
+}
+
+static gchar *
+get_quotation_for_level (gint quote_level)
+{
+ gint ii;
+ GString *output = g_string_new ("");
+
+ for (ii = 0; ii < quote_level; ii++) {
+ g_string_append (output, "<span class=\"-x-evo-quote-character\">");
+ g_string_append (output, QUOTE_SYMBOL);
+ g_string_append (output, " ");
+ g_string_append (output, "</span>");
+ }
+
+ return g_string_free (output, FALSE);
+}
+
+void
+e_editor_dom_quote_plain_text_element_after_wrapping (EEditorPage *editor_page,
+ WebKitDOMElement *element,
+ gint quote_level)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMNodeList *list = NULL;
+ WebKitDOMNode *quoted_node;
+ gint length, ii;
+ gchar *quotation;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+ g_return_if_fail (element != NULL);
+
+ document = e_editor_page_get_document (editor_page);
+
+ quoted_node = WEBKIT_DOM_NODE (
+ webkit_dom_document_create_element (document, "SPAN", NULL));
+ webkit_dom_element_set_class_name (
+ WEBKIT_DOM_ELEMENT (quoted_node), "-x-evo-quoted");
+ quotation = get_quotation_for_level (quote_level);
+ webkit_dom_element_set_inner_html (
+ WEBKIT_DOM_ELEMENT (quoted_node), quotation, NULL);
+
+ list = webkit_dom_element_query_selector_all (
+ element, "br.-x-evo-wrap-br", NULL);
+ webkit_dom_node_insert_before (
+ WEBKIT_DOM_NODE (element),
+ quoted_node,
+ webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (element)),
+ NULL);
+
+ length = webkit_dom_node_list_get_length (list);
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMNode *br = webkit_dom_node_list_item (list, ii);
+
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (br),
+ webkit_dom_node_clone_node_with_error (quoted_node, TRUE, NULL),
+ webkit_dom_node_get_next_sibling (br),
+ NULL);
+ g_object_unref (br);
+ }
+
+ g_clear_object (&list);
+ g_free (quotation);
+}
+
+static gboolean
+return_pressed_in_empty_line (EEditorPage *editor_page)
+{
+ WebKitDOMNode *node;
+ WebKitDOMRange *range = NULL;
+
+ range = e_editor_dom_get_current_range (editor_page);
+ if (!range)
+ return FALSE;
+
+ node = webkit_dom_range_get_start_container (range, NULL);
+ if (!WEBKIT_DOM_IS_TEXT (node)) {
+ WebKitDOMNode *first_child;
+
+ first_child = webkit_dom_node_get_first_child (node);
+ if (first_child && WEBKIT_DOM_IS_ELEMENT (first_child) &&
+ element_has_class (WEBKIT_DOM_ELEMENT (first_child), "-x-evo-quoted")) {
+ WebKitDOMNode *prev_sibling;
+
+ prev_sibling = webkit_dom_node_get_previous_sibling (node);
+ if (!prev_sibling) {
+ gboolean collapsed;
+
+ collapsed = webkit_dom_range_get_collapsed (range, NULL);
+ g_clear_object (&range);
+ return collapsed;
+ }
+ }
+ }
+
+ g_clear_object (&range);
+
+ return FALSE;
+}
+
+WebKitDOMNode *
+e_editor_dom_get_parent_block_node_from_child (WebKitDOMNode *node)
+{
+ WebKitDOMNode *parent = node;
+
+ if (!WEBKIT_DOM_IS_ELEMENT (parent) ||
+ e_editor_dom_is_selection_position_node (parent))
+ parent = webkit_dom_node_get_parent_node (parent);
+
+ if (element_has_class (WEBKIT_DOM_ELEMENT (parent), "-x-evo-quoted") ||
+ element_has_class (WEBKIT_DOM_ELEMENT (parent), "-x-evo-quote-character") ||
+ element_has_class (WEBKIT_DOM_ELEMENT (parent), "-x-evo-signature") ||
+ element_has_class (WEBKIT_DOM_ELEMENT (parent), "-x-evo-resizable-wrapper") ||
+ WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (parent) ||
+ element_has_tag (WEBKIT_DOM_ELEMENT (parent), "b") ||
+ element_has_tag (WEBKIT_DOM_ELEMENT (parent), "i") ||
+ element_has_tag (WEBKIT_DOM_ELEMENT (parent), "u"))
+ parent = webkit_dom_node_get_parent_node (parent);
+
+ if (element_has_class (WEBKIT_DOM_ELEMENT (parent), "-x-evo-quoted") ||
+ element_has_class (WEBKIT_DOM_ELEMENT (parent), "Apple-tab-span") ||
+ element_has_class (WEBKIT_DOM_ELEMENT (parent), "-x-evo-resizable-wrapper"))
+ parent = webkit_dom_node_get_parent_node (parent);
+
+ return parent;
+}
+
+WebKitDOMElement *
+e_editor_dom_wrap_and_quote_element (EEditorPage *editor_page,
+ WebKitDOMElement *element)
+{
+ gint citation_level;
+ WebKitDOMElement *tmp_element = element;
+
+ g_return_val_if_fail (WEBKIT_DOM_IS_ELEMENT (element), element);
+
+ if (e_editor_page_get_html_mode (editor_page))
+ return element;
+
+ citation_level = e_editor_dom_get_citation_level (WEBKIT_DOM_NODE (element), FALSE);
+
+ e_editor_dom_remove_quoting_from_element (element);
+ e_editor_dom_remove_wrapping_from_element (element);
+
+ if (WEBKIT_DOM_IS_HTML_PARAGRAPH_ELEMENT (element) &&
+ webkit_dom_element_has_attribute (element, "data-evo-paragraph")) {
+ gint word_wrap_length, length;
+
+ word_wrap_length = e_editor_page_get_word_wrap_length (editor_page);
+ length = word_wrap_length - 2 * citation_level;
+ tmp_element = e_editor_dom_wrap_paragraph_length (
+ editor_page, element, length);
+ }
+
+ if (citation_level > 0) {
+
+ webkit_dom_node_normalize (WEBKIT_DOM_NODE (tmp_element));
+ e_editor_dom_quote_plain_text_element_after_wrapping (
+ editor_page, tmp_element, citation_level);
+ }
+
+ return tmp_element;
+}
+
+WebKitDOMElement *
+e_editor_dom_insert_new_line_into_citation (EEditorPage *editor_page,
+ const gchar *html_to_insert)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *element, *paragraph = NULL;
+ WebKitDOMNode *last_block;
+ gboolean html_mode = FALSE, ret_val, avoid_editor_call;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+ document = e_editor_page_get_document (editor_page);
+ html_mode = e_editor_page_get_html_mode (editor_page);
+
+ avoid_editor_call = return_pressed_in_empty_line (editor_page);
+
+ if (avoid_editor_call) {
+ WebKitDOMElement *selection_start_marker;
+ WebKitDOMNode *current_block, *parent, *parent_block, *block_clone;
+
+ e_editor_dom_selection_save (editor_page);
+
+ selection_start_marker = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-start-marker");
+
+ current_block = e_editor_dom_get_parent_block_node_from_child (
+ WEBKIT_DOM_NODE (selection_start_marker));
+
+ block_clone = webkit_dom_node_clone_node_with_error (current_block, TRUE, NULL);
+ /* Find selection start marker and restore it after the new line
+ * is inserted */
+ selection_start_marker = webkit_dom_element_query_selector (
+ WEBKIT_DOM_ELEMENT (block_clone), "#-x-evo-selection-start-marker", NULL);
+
+ /* Find parent node that is immediate child of the BODY */
+ /* Build the same structure of parent nodes of the current block */
+ parent_block = current_block;
+ parent = webkit_dom_node_get_parent_node (parent_block);
+ while (parent && !WEBKIT_DOM_IS_HTML_BODY_ELEMENT (parent)) {
+ WebKitDOMNode *node;
+
+ parent_block = parent;
+ node = webkit_dom_node_clone_node_with_error (parent_block, FALSE, NULL);
+ webkit_dom_node_append_child (node, block_clone, NULL);
+ block_clone = node;
+ parent = webkit_dom_node_get_parent_node (parent_block);
+ }
+
+ paragraph = e_editor_dom_get_paragraph_element (editor_page, -1, 0);
+
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (paragraph),
+ WEBKIT_DOM_NODE (
+ webkit_dom_document_create_element (document, "BR", NULL)),
+ NULL);
+
+ /* Insert the selection markers to right place */
+ webkit_dom_node_insert_before (
+ WEBKIT_DOM_NODE (paragraph),
+ webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (selection_start_marker)),
+ webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (paragraph)),
+ NULL);
+ webkit_dom_node_insert_before (
+ WEBKIT_DOM_NODE (paragraph),
+ WEBKIT_DOM_NODE (selection_start_marker),
+ webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (paragraph)),
+ NULL);
+
+ /* Insert the cloned nodes before the BODY parent node */
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (parent_block),
+ block_clone,
+ parent_block,
+ NULL);
+
+ /* Insert the new empty paragraph before the BODY parent node */
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (parent_block),
+ WEBKIT_DOM_NODE (paragraph),
+ parent_block,
+ NULL);
+
+ /* Remove the old block (its copy was moved to the right place) */
+ remove_node (current_block);
+
+ e_editor_dom_selection_restore (editor_page);
+
+ return NULL;
+ } else {
+ e_editor_dom_remove_input_event_listener_from_body (editor_page);
+ e_editor_page_block_selection_changed (editor_page);
+
+ ret_val = e_editor_dom_exec_command (
+ editor_page, E_CONTENT_EDITOR_COMMAND_INSERT_NEW_LINE_IN_QUOTED_CONTENT, NULL);
+
+ e_editor_page_unblock_selection_changed (editor_page);
+ e_editor_dom_register_input_event_listener_on_body (editor_page);
+
+ if (!ret_val)
+ return NULL;
+
+ element = webkit_dom_document_query_selector (
+ document, "body>br", NULL);
+
+ if (!element)
+ return NULL;
+ }
+
+ last_block = webkit_dom_node_get_previous_sibling (WEBKIT_DOM_NODE (element));
+ while (last_block && e_editor_dom_node_is_citation_node (last_block))
+ last_block = webkit_dom_node_get_last_child (last_block);
+
+ if (last_block) {
+ WebKitDOMNode *last_child;
+
+ if ((last_child = webkit_dom_node_get_last_child (last_block))) {
+ if (WEBKIT_DOM_IS_ELEMENT (last_child) &&
+ element_has_class (WEBKIT_DOM_ELEMENT (last_child), "-x-evo-quoted"))
+ webkit_dom_node_append_child (
+ last_block,
+ WEBKIT_DOM_NODE (
+ webkit_dom_document_create_element (
+ document, "br", NULL)),
+ NULL);
+ }
+ }
+
+ if (!html_mode) {
+ WebKitDOMNode *sibling;
+
+ sibling = webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (element));
+
+ if (WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (sibling)) {
+ WebKitDOMNode *node;
+
+ node = webkit_dom_node_get_first_child (sibling);
+ while (node && e_editor_dom_node_is_citation_node (node))
+ node = webkit_dom_node_get_first_child (node);
+
+ /* Rewrap and requote nodes that were created by split. */
+ if (WEBKIT_DOM_IS_ELEMENT (node))
+ e_editor_dom_wrap_and_quote_element (editor_page, WEBKIT_DOM_ELEMENT (node));
+
+ if (WEBKIT_DOM_IS_ELEMENT (last_block))
+ e_editor_dom_wrap_and_quote_element (editor_page, WEBKIT_DOM_ELEMENT
(last_block));
+
+ e_editor_dom_force_spell_check_in_viewport (editor_page);
+ }
+ }
+
+ if (html_to_insert && *html_to_insert) {
+ paragraph = e_editor_dom_prepare_paragraph (editor_page, FALSE);
+ webkit_dom_element_set_inner_html (
+ paragraph, html_to_insert, NULL);
+ if (!webkit_dom_element_query_selector (paragraph, "#-x-evo-selection-start-marker", NULL))
+ dom_add_selection_markers_into_element_end (
+ document, paragraph, NULL, NULL);
+ } else
+ paragraph = e_editor_dom_prepare_paragraph (editor_page, TRUE);
+
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element)),
+ WEBKIT_DOM_NODE (paragraph),
+ WEBKIT_DOM_NODE (element),
+ NULL);
+
+ remove_node (WEBKIT_DOM_NODE (element));
+
+ e_editor_dom_selection_restore (editor_page);
+
+ return paragraph;
+}
+
+/* For purpose of this function see e-mail-formatter-quote.c */
+static void
+put_body_in_citation (WebKitDOMDocument *document)
+{
+ WebKitDOMElement *cite_body = webkit_dom_document_query_selector (
+ document, "span.-x-evo-cite-body", NULL);
+
+ if (cite_body) {
+ WebKitDOMHTMLElement *body = webkit_dom_document_get_body (document);
+ WebKitDOMNode *citation;
+ WebKitDOMNode *sibling;
+
+ citation = WEBKIT_DOM_NODE (
+ webkit_dom_document_create_element (document, "blockquote", NULL));
+ webkit_dom_element_set_id (WEBKIT_DOM_ELEMENT (citation), "-x-evo-main-cite");
+ webkit_dom_element_set_attribute (WEBKIT_DOM_ELEMENT (citation), "type", "cite", NULL);
+
+ webkit_dom_node_insert_before (
+ WEBKIT_DOM_NODE (body),
+ citation,
+ webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (body)),
+ NULL);
+
+ while ((sibling = webkit_dom_node_get_next_sibling (citation)))
+ webkit_dom_node_append_child (citation, sibling, NULL);
+
+ remove_node (WEBKIT_DOM_NODE (cite_body));
+ }
+}
+
+/* For purpose of this function see e-mail-formatter-quote.c */
+static void
+move_elements_to_body (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMHTMLElement *body;
+ WebKitDOMNodeList *list = NULL;
+ gint ii;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+ body = webkit_dom_document_get_body (document);
+ list = webkit_dom_document_query_selector_all (
+ document, "div[data-headers]", NULL);
+ for (ii = webkit_dom_node_list_get_length (list) - 1; ii >= 0; ii--) {
+ WebKitDOMNode *node = webkit_dom_node_list_item (list, ii);
+
+ webkit_dom_element_remove_attribute (
+ WEBKIT_DOM_ELEMENT (node), "data-headers");
+ webkit_dom_node_insert_before (
+ WEBKIT_DOM_NODE (body),
+ node,
+ webkit_dom_node_get_first_child (
+ WEBKIT_DOM_NODE (body)),
+ NULL);
+
+ g_object_unref (node);
+ }
+ g_clear_object (&list);
+
+ list = webkit_dom_document_query_selector_all (
+ document, "span.-x-evo-to-body[data-credits]", NULL);
+ for (ii = webkit_dom_node_list_get_length (list) - 1; ii >= 0; ii--) {
+ char *credits;
+ WebKitDOMElement *element;
+ WebKitDOMNode *node = webkit_dom_node_list_item (list, ii);
+
+ element = e_editor_dom_get_paragraph_element (editor_page, -1, 0);
+ credits = webkit_dom_element_get_attribute (WEBKIT_DOM_ELEMENT (node), "data-credits");
+ if (credits)
+ webkit_dom_html_element_set_inner_text (WEBKIT_DOM_HTML_ELEMENT (element), credits,
NULL);
+ g_free (credits);
+
+ webkit_dom_node_insert_before (
+ WEBKIT_DOM_NODE (body),
+ WEBKIT_DOM_NODE (element),
+ webkit_dom_node_get_first_child (
+ WEBKIT_DOM_NODE (body)),
+ NULL);
+
+ remove_node (node);
+ g_object_unref (node);
+ }
+ g_clear_object (&list);
+}
+
+static void
+repair_gmail_blockquotes (WebKitDOMDocument *document)
+{
+ WebKitDOMNodeList *list = NULL;
+ gint ii, length;
+
+ list = webkit_dom_document_query_selector_all (
+ document, "blockquote.gmail_quote", NULL);
+ length = webkit_dom_node_list_get_length (list);
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMNode *node = webkit_dom_node_list_item (list, ii);
+
+ webkit_dom_element_remove_attribute (WEBKIT_DOM_ELEMENT (node), "class");
+ webkit_dom_element_remove_attribute (WEBKIT_DOM_ELEMENT (node), "style");
+ webkit_dom_element_set_attribute (WEBKIT_DOM_ELEMENT (node), "type", "cite", NULL);
+
+ if (!WEBKIT_DOM_IS_HTML_BR_ELEMENT (webkit_dom_node_get_last_child (node)))
+ webkit_dom_node_append_child (
+ node,
+ WEBKIT_DOM_NODE (
+ webkit_dom_document_create_element (
+ document, "br", NULL)),
+ NULL);
+ g_object_unref (node);
+ }
+ g_clear_object (&list);
+}
+
+static void
+remove_thunderbird_signature (WebKitDOMDocument *document)
+{
+ WebKitDOMElement *signature;
+
+ signature = webkit_dom_document_query_selector (
+ document, "pre.moz-signature", NULL);
+ if (signature)
+ remove_node (WEBKIT_DOM_NODE (signature));
+}
+
+void
+e_editor_dom_check_magic_links (EEditorPage *editor_page,
+ gboolean include_space_by_user)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMNode *node;
+ WebKitDOMRange *range = NULL;
+ gchar *node_text;
+ gchar **urls;
+ gboolean include_space = FALSE;
+ gboolean is_email_address = FALSE;
+ gboolean return_key_pressed;
+ GRegex *regex = NULL;
+ GMatchInfo *match_info;
+ gint start_pos_url, end_pos_url;
+ gboolean has_selection;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ if (!e_editor_page_get_magic_links_enabled (editor_page))
+ return;
+
+ return_key_pressed = e_editor_page_get_return_key_pressed (editor_page);
+ document = e_editor_page_get_document (editor_page);
+
+ if (include_space_by_user)
+ include_space = TRUE;
+ else
+ include_space = e_editor_page_get_space_key_pressed (editor_page);
+
+ range = e_editor_dom_get_current_range (editor_page);
+ node = webkit_dom_range_get_end_container (range, NULL);
+ has_selection = !webkit_dom_range_get_collapsed (range, NULL);
+ g_clear_object (&range);
+
+ if (return_key_pressed) {
+ WebKitDOMNode* block;
+
+ block = e_editor_dom_get_parent_block_node_from_child (node);
+ /* Get previous block */
+ if (!(block = webkit_dom_node_get_previous_sibling (block)))
+ return;
+
+ /* If block is quoted content, get the last block there */
+ while (block && WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (block))
+ block = webkit_dom_node_get_last_child (block);
+
+ /* Get the last non-empty node */
+ node = webkit_dom_node_get_last_child (block);
+ if (WEBKIT_DOM_IS_CHARACTER_DATA (node) &&
+ webkit_dom_character_data_get_length (WEBKIT_DOM_CHARACTER_DATA (node)) == 0)
+ node = webkit_dom_node_get_previous_sibling (node);
+ } else {
+ e_editor_dom_selection_save (editor_page);
+ if (has_selection) {
+ WebKitDOMElement *selection_end_marker;
+
+ selection_end_marker = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-end-marker");
+
+ node = webkit_dom_node_get_previous_sibling (
+ WEBKIT_DOM_NODE (selection_end_marker));
+ }
+ }
+
+ if (!node || WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (node))
+ goto out;
+
+ if (!WEBKIT_DOM_IS_TEXT (node)) {
+ if (webkit_dom_node_has_child_nodes (node))
+ node = webkit_dom_node_get_first_child (node);
+ if (!WEBKIT_DOM_IS_TEXT (node))
+ goto out;
+ }
+
+ node_text = webkit_dom_text_get_whole_text (WEBKIT_DOM_TEXT (node));
+ if (!(node_text && *node_text) || !g_utf8_validate (node_text, -1, NULL)) {
+ g_free (node_text);
+ goto out;
+ }
+
+ if (strstr (node_text, "@") && !strstr (node_text, "://")) {
+ is_email_address = TRUE;
+ regex = g_regex_new (include_space ? E_MAIL_PATTERN_SPACE : E_MAIL_PATTERN, 0, 0, NULL);
+ } else
+ regex = g_regex_new (include_space ? URL_PATTERN_SPACE : URL_PATTERN, 0, 0, NULL);
+
+ if (!regex) {
+ g_free (node_text);
+ goto out;
+ }
+
+ g_regex_match_all (regex, node_text, G_REGEX_MATCH_NOTEMPTY, &match_info);
+ urls = g_match_info_fetch_all (match_info);
+
+ if (urls) {
+ const gchar *end_of_match = NULL;
+ gchar *final_url, *url_end_raw, *url_text;
+ glong url_start, url_end, url_length;
+ WebKitDOMNode *url_text_node;
+ WebKitDOMElement *anchor;
+
+ g_match_info_fetch_pos (match_info, 0, &start_pos_url, &end_pos_url);
+
+ /* Get start and end position of url in node's text because positions
+ * that we get from g_match_info_fetch_pos are not UTF-8 aware */
+ url_end_raw = g_strndup(node_text, end_pos_url);
+ url_end = g_utf8_strlen (url_end_raw, -1);
+ url_length = g_utf8_strlen (urls[0], -1);
+
+ end_of_match = url_end_raw + end_pos_url - (include_space ? 3 : 2);
+ /* URLs are extremely unlikely to end with any punctuation, so
+ * strip any trailing punctuation off from link and put it after
+ * the link. Do the same for any closing double-quotes as well. */
+ while (end_of_match && end_of_match != url_end_raw && strchr (URL_INVALID_TRAILING_CHARS,
*end_of_match)) {
+ url_length--;
+ url_end--;
+ end_of_match--;
+ }
+
+ url_start = url_end - url_length;
+
+ webkit_dom_text_split_text (
+ WEBKIT_DOM_TEXT (node),
+ include_space ? url_end - 1 : url_end,
+ NULL);
+
+ webkit_dom_text_split_text (
+ WEBKIT_DOM_TEXT (node), url_start, NULL);
+ url_text_node = webkit_dom_node_get_next_sibling (node);
+ url_text = webkit_dom_character_data_get_data (
+ WEBKIT_DOM_CHARACTER_DATA (url_text_node));
+
+ if (g_str_has_prefix (url_text, "www."))
+ final_url = g_strconcat ("http://" , url_text, NULL);
+ else if (is_email_address)
+ final_url = g_strconcat ("mailto:" , url_text, NULL);
+ else
+ final_url = g_strdup (url_text);
+
+ /* Create and prepare new anchor element */
+ anchor = webkit_dom_document_create_element (document, "A", NULL);
+
+ webkit_dom_element_set_inner_html (anchor, url_text, NULL);
+
+ webkit_dom_html_anchor_element_set_href (
+ WEBKIT_DOM_HTML_ANCHOR_ELEMENT (anchor),
+ final_url);
+
+ /* Insert new anchor element into document */
+ webkit_dom_node_replace_child (
+ webkit_dom_node_get_parent_node (node),
+ WEBKIT_DOM_NODE (anchor),
+ WEBKIT_DOM_NODE (url_text_node),
+ NULL);
+
+ g_free (url_end_raw);
+ g_free (final_url);
+ g_free (url_text);
+ } else {
+ gboolean appending_to_link = FALSE;
+ gchar *href, *text, *url, *text_to_append = NULL;
+ gint diff;
+ WebKitDOMElement *parent;
+ WebKitDOMNode *prev_sibling;
+
+ parent = webkit_dom_node_get_parent_element (node);
+ prev_sibling = webkit_dom_node_get_previous_sibling (node);
+
+ /* If previous sibling is ANCHOR and actual text node is not beginning with
+ * space => we're appending to link */
+ if (WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (prev_sibling)) {
+ text_to_append = webkit_dom_node_get_text_content (node);
+ if (text_to_append && *text_to_append &&
+ !strstr (text_to_append, " ") &&
+ !(strchr (URL_INVALID_TRAILING_CHARS, *text_to_append) &&
+ !(*text_to_append == '?' && strlen(text_to_append) > 1)) &&
+ !g_str_has_prefix (text_to_append, UNICODE_NBSP)) {
+
+ appending_to_link = TRUE;
+ parent = WEBKIT_DOM_ELEMENT (prev_sibling);
+ /* If the node(text) contains the some of unwanted characters
+ * split it into two nodes and select the right one. */
+ if (g_str_has_suffix (text_to_append, UNICODE_NBSP) ||
+ g_str_has_suffix (text_to_append, UNICODE_ZERO_WIDTH_SPACE)) {
+ webkit_dom_text_split_text (
+ WEBKIT_DOM_TEXT (node),
+ g_utf8_strlen (text_to_append, -1) - 1,
+ NULL);
+ g_free (text_to_append);
+ text_to_append = webkit_dom_node_get_text_content (node);
+ }
+ }
+ }
+
+ /* If parent is ANCHOR => we're editing the link */
+ if ((!WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (parent) && !appending_to_link) || !text_to_append) {
+ g_match_info_free (match_info);
+ g_regex_unref (regex);
+ g_free (node_text);
+ g_free (text_to_append);
+ goto out;
+ }
+
+ /* edit only if href and description are the same */
+ href = webkit_dom_html_anchor_element_get_href (
+ WEBKIT_DOM_HTML_ANCHOR_ELEMENT (parent));
+
+ if (appending_to_link) {
+ gchar *inner_text;
+
+ inner_text =
+ webkit_dom_html_element_get_inner_text (
+ WEBKIT_DOM_HTML_ELEMENT (parent)),
+
+ text = g_strconcat (inner_text, text_to_append, NULL);
+ g_free (inner_text);
+ } else
+ text = webkit_dom_html_element_get_inner_text (
+ WEBKIT_DOM_HTML_ELEMENT (parent));
+
+ element_remove_class (parent, "-x-evo-visited-link");
+
+ if (strstr (href, "://") && !strstr (text, "://")) {
+ url = strstr (href, "://") + 3;
+ diff = strlen (text) - strlen (url);
+
+ if (text [strlen (text) - 1] != '/')
+ diff++;
+
+ if ((g_strcmp0 (url, text) != 0 && ABS (diff) == 1) || appending_to_link) {
+ gchar *inner_html, *protocol, *new_href;
+
+ protocol = g_strndup (href, strstr (href, "://") - href + 3);
+ inner_html = webkit_dom_element_get_inner_html (parent);
+ new_href = g_strconcat (
+ protocol, inner_html, appending_to_link ? text_to_append : "", NULL);
+
+ webkit_dom_html_anchor_element_set_href (
+ WEBKIT_DOM_HTML_ANCHOR_ELEMENT (parent),
+ new_href);
+
+ if (appending_to_link) {
+ webkit_dom_html_element_insert_adjacent_html (
+ WEBKIT_DOM_HTML_ELEMENT (parent),
+ "beforeend",
+ text_to_append,
+ NULL);
+
+ remove_node (node);
+ }
+
+ g_free (new_href);
+ g_free (protocol);
+ g_free (inner_html);
+ }
+ } else {
+ diff = strlen (text) - strlen (href);
+ if (text [strlen (text) - 1] != '/')
+ diff++;
+
+ if ((g_strcmp0 (href, text) != 0 && ABS (diff) == 1) || appending_to_link) {
+ gchar *inner_html;
+ gchar *new_href;
+
+ inner_html = webkit_dom_element_get_inner_html (parent);
+ new_href = g_strconcat (
+ inner_html,
+ appending_to_link ? text_to_append : "",
+ NULL);
+
+ webkit_dom_html_anchor_element_set_href (
+ WEBKIT_DOM_HTML_ANCHOR_ELEMENT (parent),
+ new_href);
+
+ if (appending_to_link) {
+ webkit_dom_html_element_insert_adjacent_html (
+ WEBKIT_DOM_HTML_ELEMENT (parent),
+ "beforeend",
+ text_to_append,
+ NULL);
+
+ remove_node (node);
+ }
+
+ g_free (new_href);
+ g_free (inner_html);
+ }
+
+ }
+ g_free (text_to_append);
+ g_free (text);
+ g_free (href);
+ }
+
+ g_match_info_free (match_info);
+ g_regex_unref (regex);
+ g_free (node_text);
+
+ out:
+ if (!return_key_pressed)
+ e_editor_dom_selection_restore (editor_page);
+}
+
+void
+e_editor_dom_embed_style_sheet (EEditorPage *editor_page,
+ const gchar *style_sheet_content)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *sheet;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+
+ e_dom_utils_create_and_add_css_style_sheet (document, "-x-evo-composer-sheet");
+
+ sheet = webkit_dom_document_get_element_by_id (document, "-x-evo-composer-sheet");
+ webkit_dom_element_set_attribute (
+ sheet,
+ "type",
+ "text/css",
+ NULL);
+
+ webkit_dom_element_set_inner_html (sheet, style_sheet_content, NULL);
+}
+
+void
+e_editor_dom_remove_embedded_style_sheet (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *sheet;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+
+ sheet = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-composer-sheet");
+
+ remove_node (WEBKIT_DOM_NODE (sheet));
+}
+
+static void
+insert_delete_event (EEditorPage *editor_page,
+ WebKitDOMRange *range)
+{
+ EEditorHistoryEvent *ev;
+ WebKitDOMDocumentFragment *fragment;
+ EEditorUndoRedoManager *manager;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ manager = e_editor_page_get_undo_redo_manager (editor_page);
+
+ if (e_editor_undo_redo_manager_is_operation_in_progress (manager))
+ return;
+
+ ev = g_new0 (EEditorHistoryEvent, 1);
+ ev->type = HISTORY_DELETE;
+
+ fragment = webkit_dom_range_clone_contents (range, NULL);
+ ev->data.fragment = fragment;
+
+ e_editor_dom_selection_get_coordinates (editor_page,
+ &ev->before.start.x,
+ &ev->before.start.y,
+ &ev->before.end.x,
+ &ev->before.end.y);
+
+ ev->after.start.x = ev->before.start.x;
+ ev->after.start.y = ev->before.start.y;
+ ev->after.end.x = ev->before.start.x;
+ ev->after.end.y = ev->before.start.y;
+
+ e_editor_undo_redo_manager_insert_history_event (manager, ev);
+
+ ev = g_new0 (EEditorHistoryEvent, 1);
+ ev->type = HISTORY_AND;
+
+ e_editor_undo_redo_manager_insert_history_event (manager, ev);
+}
+
+/* Based on original use_pictograms() from GtkHTML */
+static const gchar *emoticons_chars =
+ /* 0 */ "DO)(|/PQ*!"
+ /* 10 */ "S\0:-\0:\0:-\0"
+ /* 20 */ ":\0:;=-\"\0:;"
+ /* 30 */ "B\"|\0:-'\0:X"
+ /* 40 */ "\0:\0:-\0:\0:-"
+ /* 50 */ "\0:\0:-\0:\0:-"
+ /* 60 */ "\0:\0:\0:-\0:\0"
+ /* 70 */ ":-\0:\0:-\0:\0";
+static gint emoticons_states[] = {
+ /* 0 */ 12, 17, 22, 34, 43, 48, 53, 58, 65, 70,
+ /* 10 */ 75, 0, -15, 15, 0, -15, 0, -17, 20, 0,
+ /* 20 */ -17, 0, -14, -20, -14, 28, 63, 0, -14, -20,
+ /* 30 */ -3, 63, -18, 0, -12, 38, 41, 0, -12, -2,
+ /* 40 */ 0, -4, 0, -10, 46, 0, -10, 0, -19, 51,
+ /* 50 */ 0, -19, 0, -11, 56, 0, -11, 0, -13, 61,
+ /* 60 */ 0, -13, 0, -6, 0, 68, -7, 0, -7, 0,
+ /* 70 */ -16, 73, 0, -16, 0, -21, 78, 0, -21, 0 };
+static const gchar *emoticons_icon_names[] = {
+ "face-angel",
+ "face-angry",
+ "face-cool",
+ "face-crying",
+ "face-devilish",
+ "face-embarrassed",
+ "face-kiss",
+ "face-laugh", /* not used */
+ "face-monkey", /* not used */
+ "face-plain",
+ "face-raspberry",
+ "face-sad",
+ "face-sick",
+ "face-smile",
+ "face-smile-big",
+ "face-smirk",
+ "face-surprise",
+ "face-tired",
+ "face-uncertain",
+ "face-wink",
+ "face-worried"
+};
+
+typedef struct _EmoticonLoadContext {
+ EEmoticon *emoticon;
+ EEditorPage *editor_page;
+ gchar *content_type;
+ gchar *name;
+} EmoticonLoadContext;
+
+static EmoticonLoadContext *
+emoticon_load_context_new (EEditorPage *editor_page,
+ EEmoticon *emoticon)
+{
+ EmoticonLoadContext *load_context;
+
+ load_context = g_slice_new0 (EmoticonLoadContext);
+ load_context->emoticon = emoticon;
+ load_context->editor_page = editor_page;
+
+ return load_context;
+}
+
+static void
+emoticon_load_context_free (EmoticonLoadContext *load_context)
+{
+ g_free (load_context->content_type);
+ g_free (load_context->name);
+ g_slice_free (EmoticonLoadContext, load_context);
+}
+
+static void
+emoticon_insert_span (EEmoticon *emoticon,
+ EmoticonLoadContext *load_context,
+ WebKitDOMElement *span)
+{
+ EEditorHistoryEvent *ev = NULL;
+ EEditorUndoRedoManager *manager;
+ EEditorPage *editor_page = load_context->editor_page;
+ gboolean misplaced_selection = FALSE, smiley_written;
+ gchar *node_text = NULL;
+ const gchar *emoticon_start;
+ WebKitDOMDocument *document;
+ WebKitDOMElement *selection_start_marker, *selection_end_marker;
+ WebKitDOMNode *node, *insert_before, *prev_sibling, *next_sibling;
+ WebKitDOMNode *selection_end_marker_parent, *inserted_node;
+ WebKitDOMRange *range = NULL;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+ smiley_written = e_editor_page_get_is_smiley_written (editor_page);
+ manager = e_editor_page_get_undo_redo_manager (editor_page);
+
+ if (e_editor_dom_selection_is_collapsed (editor_page)) {
+ e_editor_dom_selection_save (editor_page);
+
+ selection_start_marker = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-start-marker");
+ selection_end_marker = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-end-marker");
+
+ if (!smiley_written) {
+ if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+ ev = g_new0 (EEditorHistoryEvent, 1);
+ if (e_editor_page_get_unicode_smileys_enabled (editor_page))
+ ev->type = HISTORY_INPUT;
+ else {
+ ev->type = HISTORY_SMILEY;
+
+ e_editor_dom_selection_get_coordinates (editor_page,
+ &ev->before.start.x,
+ &ev->before.start.y,
+ &ev->before.end.x,
+ &ev->before.end.y);
+ }
+ }
+ }
+ } else {
+ WebKitDOMRange *tmp_range = NULL;
+
+ tmp_range = e_editor_dom_get_current_range (editor_page);
+ insert_delete_event (editor_page, tmp_range);
+ g_clear_object (&tmp_range);
+
+ e_editor_dom_exec_command (editor_page, E_CONTENT_EDITOR_COMMAND_DELETE, NULL);
+
+ if (!smiley_written) {
+ if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+ ev = g_new0 (EEditorHistoryEvent, 1);
+
+ if (e_editor_page_get_unicode_smileys_enabled (editor_page))
+ ev->type = HISTORY_INPUT;
+ else {
+ ev->type = HISTORY_SMILEY;
+
+ e_editor_dom_selection_get_coordinates (editor_page,
+ &ev->before.start.x,
+ &ev->before.start.y,
+ &ev->before.end.x,
+ &ev->before.end.y);
+ }
+ }
+ }
+
+ e_editor_dom_selection_save (editor_page);
+
+ selection_start_marker = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-start-marker");
+ selection_end_marker = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-end-marker");
+ }
+
+ /* If the selection was not saved, move it into the first child of body */
+ if (!selection_start_marker || !selection_end_marker) {
+ WebKitDOMHTMLElement *body;
+ WebKitDOMNode *child;
+
+ body = webkit_dom_document_get_body (document);
+ child = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (body));
+
+ dom_add_selection_markers_into_element_start (
+ document,
+ WEBKIT_DOM_ELEMENT (child),
+ &selection_start_marker,
+ &selection_end_marker);
+
+ if (ev && !e_editor_page_get_unicode_smileys_enabled (editor_page))
+ e_editor_dom_selection_get_coordinates (editor_page,
+ &ev->before.start.x,
+ &ev->before.start.y,
+ &ev->before.end.x,
+ &ev->before.end.y);
+ }
+
+ /* Sometimes selection end marker is in body. Move it into next sibling */
+ selection_end_marker_parent = e_editor_dom_get_parent_block_node_from_child (
+ WEBKIT_DOM_NODE (selection_end_marker));
+ if (WEBKIT_DOM_IS_HTML_BODY_ELEMENT (selection_end_marker_parent)) {
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (
+ WEBKIT_DOM_NODE (selection_start_marker)),
+ WEBKIT_DOM_NODE (selection_end_marker),
+ WEBKIT_DOM_NODE (selection_start_marker),
+ NULL);
+ if (ev && !e_editor_page_get_unicode_smileys_enabled (editor_page))
+ e_editor_dom_selection_get_coordinates (editor_page,
+ &ev->before.start.x,
+ &ev->before.start.y,
+ &ev->before.end.x,
+ &ev->before.end.y);
+ }
+ selection_end_marker_parent = webkit_dom_node_get_parent_node (
+ WEBKIT_DOM_NODE (selection_end_marker));
+
+ /* Determine before what node we have to insert the smiley */
+ insert_before = WEBKIT_DOM_NODE (selection_start_marker);
+ prev_sibling = webkit_dom_node_get_previous_sibling (
+ WEBKIT_DOM_NODE (selection_start_marker));
+ if (prev_sibling) {
+ if (webkit_dom_node_is_same_node (
+ prev_sibling, WEBKIT_DOM_NODE (selection_end_marker))) {
+ insert_before = WEBKIT_DOM_NODE (selection_end_marker);
+ } else {
+ prev_sibling = webkit_dom_node_get_previous_sibling (prev_sibling);
+ if (prev_sibling &&
+ webkit_dom_node_is_same_node (
+ prev_sibling, WEBKIT_DOM_NODE (selection_end_marker))) {
+ insert_before = WEBKIT_DOM_NODE (selection_end_marker);
+ }
+ }
+ } else
+ insert_before = WEBKIT_DOM_NODE (selection_start_marker);
+
+ /* Look if selection is misplaced - that means that the selection was
+ * restored before the previously inserted smiley in situations when we
+ * are writing more smileys in a row */
+ next_sibling = webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (selection_end_marker));
+ if (next_sibling && WEBKIT_DOM_IS_ELEMENT (next_sibling))
+ if (element_has_class (WEBKIT_DOM_ELEMENT (next_sibling), "-x-evo-smiley-wrapper"))
+ misplaced_selection = TRUE;
+
+ range = e_editor_dom_get_current_range (editor_page);
+ node = webkit_dom_range_get_end_container (range, NULL);
+ g_clear_object (&range);
+ if (WEBKIT_DOM_IS_TEXT (node))
+ node_text = webkit_dom_text_get_whole_text (WEBKIT_DOM_TEXT (node));
+
+ if (misplaced_selection) {
+ /* Insert smiley and selection markers after it */
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (insert_before),
+ WEBKIT_DOM_NODE (selection_start_marker),
+ webkit_dom_node_get_next_sibling (next_sibling),
+ NULL);
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (insert_before),
+ WEBKIT_DOM_NODE (selection_end_marker),
+ webkit_dom_node_get_next_sibling (next_sibling),
+ NULL);
+ if (e_editor_page_get_unicode_smileys_enabled (editor_page))
+ inserted_node = webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (insert_before),
+ webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (span)),
+ webkit_dom_node_get_next_sibling (next_sibling),
+ NULL);
+ else
+ inserted_node = webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (insert_before),
+ WEBKIT_DOM_NODE (span),
+ webkit_dom_node_get_next_sibling (next_sibling),
+ NULL);
+ } else {
+ if (e_editor_page_get_unicode_smileys_enabled (editor_page))
+ inserted_node = webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (insert_before),
+ webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (span)),
+ insert_before,
+ NULL);
+ else
+ inserted_node = webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (insert_before),
+ WEBKIT_DOM_NODE (span),
+ insert_before,
+ NULL);
+ }
+
+ if (!e_editor_page_get_unicode_smileys_enabled (editor_page)) {
+ /* ​ == UNICODE_ZERO_WIDTH_SPACE */
+ webkit_dom_html_element_insert_adjacent_html (
+ WEBKIT_DOM_HTML_ELEMENT (span), "afterend", "​", NULL);
+ }
+
+ if (ev) {
+ WebKitDOMDocumentFragment *fragment;
+ WebKitDOMNode *node;
+
+ fragment = webkit_dom_document_create_document_fragment (document);
+ node = webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (fragment),
+ webkit_dom_node_clone_node_with_error (WEBKIT_DOM_NODE (inserted_node), TRUE, NULL),
+ NULL);
+ if (e_editor_page_get_unicode_smileys_enabled (editor_page)) {
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (fragment),
+ WEBKIT_DOM_NODE (
+ dom_create_selection_marker (document, TRUE)),
+ NULL);
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (fragment),
+ WEBKIT_DOM_NODE (
+ dom_create_selection_marker (document, FALSE)),
+ NULL);
+ } else
+ webkit_dom_html_element_insert_adjacent_html (
+ WEBKIT_DOM_HTML_ELEMENT (node), "afterend", "​", NULL);
+ ev->data.fragment = fragment;
+ }
+
+ /* Remove the text that represents the text version of smiley that was
+ * written into the composer. */
+ if (node_text && smiley_written) {
+ emoticon_start = g_utf8_strrchr (
+ node_text, -1, g_utf8_get_char (emoticon->text_face));
+ /* Check if the written smiley is really the one that we inserted. */
+ if (emoticon_start) {
+ /* The written smiley is the same as text version. */
+ if (g_str_has_prefix (emoticon_start, emoticon->text_face)) {
+ webkit_dom_character_data_delete_data (
+ WEBKIT_DOM_CHARACTER_DATA (node),
+ g_utf8_strlen (node_text, -1) - strlen (emoticon_start),
+ strlen (emoticon->text_face),
+ NULL);
+ } else if (strstr (emoticon->text_face, "-")) {
+ gboolean same = TRUE, compensate = FALSE;
+ gint ii = 0, jj = 0;
+
+ /* Try to recognize smileys without the dash e.g. :). */
+ while (emoticon_start[ii] && emoticon->text_face[jj]) {
+ if (emoticon_start[ii] == emoticon->text_face[jj]) {
+ if (emoticon->text_face[jj+1] && emoticon->text_face[jj+1] ==
'-') {
+ ii++;
+ jj+=2;
+ compensate = TRUE;
+ } else {
+ ii++;
+ jj++;
+ }
+ } else {
+ same = FALSE;
+ break;
+ }
+ }
+
+ if (same) {
+ webkit_dom_character_data_delete_data (
+ WEBKIT_DOM_CHARACTER_DATA (node),
+ g_utf8_strlen (node_text, -1) - strlen (emoticon_start),
+ ii,
+ NULL);
+ }
+ /* If we recognize smiley without dash, but we inserted
+ * the text version with dash we need it insert new
+ * history input event with that dash. */
+ if (compensate)
+ e_editor_undo_redo_manager_insert_dash_history_event (manager);
+ }
+ }
+
+ e_editor_page_set_is_smiley_written (editor_page, FALSE);
+ }
+
+ if (ev) {
+ e_editor_dom_selection_get_coordinates (editor_page,
+ &ev->after.start.x,
+ &ev->after.start.y,
+ &ev->after.end.x,
+ &ev->after.end.y);
+ e_editor_undo_redo_manager_insert_history_event (manager, ev);
+ }
+
+ e_editor_dom_selection_restore (editor_page);
+
+ e_editor_page_emit_content_changed (editor_page);
+
+ g_free (node_text);
+}
+
+static void
+emoticon_read_async_cb (GFile *file,
+ GAsyncResult *result,
+ EmoticonLoadContext *load_context)
+{
+ EEmoticon *emoticon = load_context->emoticon;
+ EEditorPage *editor_page = load_context->editor_page;
+ GError *error = NULL;
+ gboolean html_mode;
+ gchar *mime_type;
+ gchar *base64_encoded, *output, *data;
+ GFileInputStream *input_stream;
+ GOutputStream *output_stream;
+ gssize size;
+ WebKitDOMElement *wrapper, *image, *smiley_text;
+ WebKitDOMDocument *document;
+
+ input_stream = g_file_read_finish (file, result, &error);
+ g_return_if_fail (!error && input_stream);
+
+ output_stream = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
+
+ size = g_output_stream_splice (
+ output_stream, G_INPUT_STREAM (input_stream),
+ G_OUTPUT_STREAM_SPLICE_NONE, NULL, &error);
+
+ if (error || (size == -1))
+ goto out;
+
+ mime_type = g_content_type_get_mime_type (load_context->content_type);
+
+ data = g_memory_output_stream_get_data (G_MEMORY_OUTPUT_STREAM (output_stream));
+ base64_encoded = g_base64_encode ((const guchar *) data, size);
+ output = g_strconcat ("data:", mime_type, ";base64,", base64_encoded, NULL);
+
+ html_mode = e_editor_page_get_html_mode (editor_page);
+ document = e_editor_page_get_document (editor_page);
+
+ /* Insert span with image representation and another one with text
+ * representation and hide/show them dependant on active composer mode */
+ wrapper = webkit_dom_document_create_element (document, "SPAN", NULL);
+ if (html_mode)
+ webkit_dom_element_set_attribute (
+ wrapper, "class", "-x-evo-smiley-wrapper -x-evo-resizable-wrapper", NULL);
+ else
+ webkit_dom_element_set_attribute (
+ wrapper, "class", "-x-evo-smiley-wrapper", NULL);
+
+ image = webkit_dom_document_create_element (document, "IMG", NULL);
+ webkit_dom_element_set_attribute (image, "src", output, NULL);
+ webkit_dom_element_set_attribute (image, "data-inline", "", NULL);
+ webkit_dom_element_set_attribute (image, "data-name", load_context->name, NULL);
+ webkit_dom_element_set_attribute (image, "alt", emoticon->text_face, NULL);
+ webkit_dom_element_set_attribute (image, "class", "-x-evo-smiley-img", NULL);
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (wrapper), WEBKIT_DOM_NODE (image), NULL);
+
+ smiley_text = webkit_dom_document_create_element (document, "SPAN", NULL);
+ webkit_dom_element_set_attribute (smiley_text, "class", "-x-evo-smiley-text", NULL);
+ webkit_dom_html_element_set_inner_text (
+ WEBKIT_DOM_HTML_ELEMENT (smiley_text), emoticon->text_face, NULL);
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (wrapper), WEBKIT_DOM_NODE (smiley_text), NULL);
+
+ emoticon_insert_span (emoticon, load_context, wrapper);
+
+ g_free (base64_encoded);
+ g_free (output);
+ g_free (mime_type);
+ g_object_unref (output_stream);
+ out:
+ emoticon_load_context_free (load_context);
+}
+
+static void
+emoticon_query_info_async_cb (GFile *file,
+ GAsyncResult *result,
+ EmoticonLoadContext *load_context)
+{
+ GError *error = NULL;
+ GFileInfo *info;
+
+ info = g_file_query_info_finish (file, result, &error);
+ g_return_if_fail (!error && info);
+
+ load_context->content_type = g_strdup (g_file_info_get_content_type (info));
+ load_context->name = g_strdup (g_file_info_get_name (info));
+
+ g_file_read_async (
+ file, G_PRIORITY_DEFAULT, NULL,
+ (GAsyncReadyCallback) emoticon_read_async_cb, load_context);
+
+ g_object_unref (info);
+}
+
+void
+e_editor_dom_insert_smiley (EEditorPage *editor_page,
+ EEmoticon *emoticon)
+{
+ WebKitDOMDocument *document;
+ GFile *file;
+ gchar *filename_uri;
+ EmoticonLoadContext *load_context;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+
+ if (e_editor_page_get_unicode_smileys_enabled (editor_page)) {
+ WebKitDOMElement *wrapper;
+
+ wrapper = webkit_dom_document_create_element (document, "SPAN", NULL);
+ webkit_dom_html_element_set_inner_text (
+ WEBKIT_DOM_HTML_ELEMENT (wrapper), emoticon->unicode_character, NULL);
+
+ load_context = emoticon_load_context_new (editor_page, emoticon);
+ emoticon_insert_span (emoticon, load_context, wrapper);
+ emoticon_load_context_free (load_context);
+ } else {
+ filename_uri = e_emoticon_get_uri (emoticon);
+ g_return_if_fail (filename_uri != NULL);
+
+ load_context = emoticon_load_context_new (editor_page, emoticon);
+
+ file = g_file_new_for_uri (filename_uri);
+ g_file_query_info_async (
+ file, "standard::*", G_FILE_QUERY_INFO_NONE,
+ G_PRIORITY_DEFAULT, NULL,
+ (GAsyncReadyCallback) emoticon_query_info_async_cb, load_context);
+
+ g_free (filename_uri);
+ g_object_unref (file);
+ }
+}
+
+void
+e_editor_dom_insert_smiley_by_name (EEditorPage *editor_page,
+ const gchar *name)
+{
+ const EEmoticon *emoticon;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ emoticon = e_emoticon_chooser_lookup_emoticon (name);
+ e_editor_page_set_is_smiley_written (editor_page, FALSE);
+ e_editor_dom_insert_smiley (editor_page, (EEmoticon *) emoticon);
+}
+
+void
+e_editor_dom_check_magic_smileys (EEditorPage *editor_page)
+{
+ WebKitDOMNode *node;
+ WebKitDOMRange *range = NULL;
+ gint pos, state, relative, start;
+ gchar *node_text;
+ gunichar uc;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ if (!e_editor_page_get_magic_smileys_enabled (editor_page))
+ return;
+
+ range = e_editor_dom_get_current_range (editor_page);
+ node = webkit_dom_range_get_end_container (range, NULL);
+ if (!WEBKIT_DOM_IS_TEXT (node)) {
+ g_clear_object (&range);
+ return;
+ }
+
+ node_text = webkit_dom_text_get_whole_text (WEBKIT_DOM_TEXT (node));
+ if (node_text == NULL) {
+ g_clear_object (&range);
+ return;
+ }
+
+ start = webkit_dom_range_get_end_offset (range, NULL) - 1;
+ pos = start;
+ state = 0;
+ while (pos >= 0) {
+ uc = g_utf8_get_char (g_utf8_offset_to_pointer (node_text, pos));
+ relative = 0;
+ while (emoticons_chars[state + relative]) {
+ if (emoticons_chars[state + relative] == uc)
+ break;
+ relative++;
+ }
+ state = emoticons_states[state + relative];
+ /* 0 .. not found, -n .. found n-th */
+ if (state <= 0)
+ break;
+ pos--;
+ }
+
+ /* Special case needed to recognize angel and devilish. */
+ if (pos > 0 && state == -14) {
+ uc = g_utf8_get_char (g_utf8_offset_to_pointer (node_text, pos - 1));
+ if (uc == 'O') {
+ state = -1;
+ pos--;
+ } else if (uc == '>') {
+ state = -5;
+ pos--;
+ }
+ }
+
+ if (state < 0) {
+ const EEmoticon *emoticon;
+
+ if (pos > 0) {
+ uc = g_utf8_get_char (g_utf8_offset_to_pointer (node_text, pos - 1));
+ if (!g_unichar_isspace (uc)) {
+ g_free (node_text);
+ g_clear_object (&range);
+ return;
+ }
+ }
+
+ emoticon = e_emoticon_chooser_lookup_emoticon (
+ emoticons_icon_names[-state - 1]);
+ e_editor_page_set_is_smiley_written (editor_page, TRUE);
+ e_editor_dom_insert_smiley (editor_page, (EEmoticon *) emoticon);
+ }
+
+ g_clear_object (&range);
+ g_free (node_text);
+}
+
+static void
+dom_set_links_active (WebKitDOMDocument *document,
+ gboolean active)
+{
+ WebKitDOMElement *style;
+
+ style = webkit_dom_document_get_element_by_id (document, "-x-evo-style-a");
+ if (style)
+ remove_node (WEBKIT_DOM_NODE (style));
+
+ if (!active) {
+ WebKitDOMHTMLHeadElement *head;
+ head = webkit_dom_document_get_head (document);
+
+ style = webkit_dom_document_create_element (document, "STYLE", NULL);
+ webkit_dom_element_set_id (style, "-x-evo-style-a");
+ webkit_dom_element_set_attribute (style, "type", "text/css", NULL);
+ webkit_dom_html_element_set_inner_text (
+ WEBKIT_DOM_HTML_ELEMENT (style), "a { cursor: text; }", NULL);
+
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (head), WEBKIT_DOM_NODE (style), NULL);
+ }
+}
+
+static void
+fix_paragraph_structure_after_pressing_enter_after_smiley (WebKitDOMDocument *document)
+{
+ WebKitDOMElement *element;
+
+ element = webkit_dom_document_query_selector (
+ document, "span.-x-evo-smiley-wrapper > br", NULL);
+
+ if (element) {
+ WebKitDOMNode *parent;
+
+ parent = webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element));
+ webkit_dom_element_set_inner_html (
+ webkit_dom_node_get_parent_element (parent),
+ UNICODE_ZERO_WIDTH_SPACE,
+ NULL);
+ }
+}
+
+static gboolean
+fix_paragraph_structure_after_pressing_enter (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMNode *body;
+ WebKitDOMNodeList *list;
+ gboolean prev_is_heading = FALSE;
+ gint ii, length;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+ document = e_editor_page_get_document (editor_page);
+ body = WEBKIT_DOM_NODE (webkit_dom_document_get_body (document));
+
+ /* When pressing Enter on empty line in the list (or after heading elements)
+ * WebKit will end that list and inserts <div><br></div> so mark it for wrapping. */
+ list = webkit_dom_document_query_selector_all (
+ document, "body > div > br", NULL);
+
+ length = webkit_dom_node_list_get_length (list);
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMNode *prev_sibling;
+ WebKitDOMNode *node = webkit_dom_node_get_parent_node (
+ webkit_dom_node_list_item (list, ii));
+
+ prev_sibling = webkit_dom_node_get_previous_sibling (node);
+ if (prev_sibling && WEBKIT_DOM_IS_HTML_HEADING_ELEMENT (prev_sibling))
+ prev_is_heading = TRUE;
+
+ webkit_dom_node_replace_child (
+ body,
+ WEBKIT_DOM_NODE (e_editor_dom_prepare_paragraph (editor_page, FALSE)),
+ node,
+ NULL);
+
+ g_object_unref (node);
+ }
+ g_object_unref (list);
+
+ return prev_is_heading;
+}
+
+static gboolean
+surround_text_with_paragraph_if_needed (EEditorPage *editor_page,
+ WebKitDOMNode *node)
+{
+ WebKitDOMNode *next_sibling = webkit_dom_node_get_next_sibling (node);
+ WebKitDOMNode *prev_sibling = webkit_dom_node_get_previous_sibling (node);
+ WebKitDOMNode *parent = webkit_dom_node_get_parent_node (node);
+ WebKitDOMElement *element;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+ /* All text in composer has to be written in div elements, so if
+ * we are writing something straight to the body, surround it with
+ * paragraph */
+ if (WEBKIT_DOM_IS_TEXT (node) &&
+ (WEBKIT_DOM_IS_HTML_BODY_ELEMENT (parent) ||
+ WEBKIT_DOM_IS_HTML_TABLE_CELL_ELEMENT (parent))) {
+ element = e_editor_dom_put_node_into_paragraph (editor_page, node, TRUE);
+ if (WEBKIT_DOM_IS_HTML_TABLE_CELL_ELEMENT (parent))
+ webkit_dom_element_remove_attribute (element, "style");
+
+ if (WEBKIT_DOM_IS_HTML_BR_ELEMENT (next_sibling))
+ remove_node (next_sibling);
+
+ /* Tab character */
+ if (WEBKIT_DOM_IS_ELEMENT (prev_sibling) &&
+ element_has_class (WEBKIT_DOM_ELEMENT (prev_sibling), "Apple-tab-span")) {
+ webkit_dom_node_insert_before (
+ WEBKIT_DOM_NODE (element),
+ prev_sibling,
+ webkit_dom_node_get_first_child (
+ WEBKIT_DOM_NODE (element)),
+ NULL);
+ }
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+selection_is_in_table (WebKitDOMDocument *document,
+ gboolean *first_cell,
+ WebKitDOMNode **table_node)
+{
+ WebKitDOMDOMWindow *dom_window = NULL;
+ WebKitDOMDOMSelection *dom_selection = NULL;
+ WebKitDOMNode *node, *parent;
+ WebKitDOMRange *range = NULL;
+
+ dom_window = webkit_dom_document_get_default_view (document);
+ dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+ g_clear_object (&dom_window);
+
+ if (first_cell != NULL)
+ *first_cell = FALSE;
+
+ if (table_node != NULL)
+ *table_node = NULL;
+
+ if (webkit_dom_dom_selection_get_range_count (dom_selection) < 1) {
+ g_clear_object (&dom_selection);
+ return FALSE;
+ }
+
+ range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+ node = webkit_dom_range_get_start_container (range, NULL);
+ g_clear_object (&dom_selection);
+
+ parent = node;
+ while (parent && !WEBKIT_DOM_IS_HTML_BODY_ELEMENT (parent)) {
+ if (WEBKIT_DOM_IS_HTML_TABLE_CELL_ELEMENT (parent)) {
+ if (first_cell != NULL) {
+ if (!webkit_dom_node_get_previous_sibling (parent)) {
+ gboolean on_start = TRUE;
+ WebKitDOMNode *tmp;
+
+ tmp = webkit_dom_node_get_previous_sibling (node);
+ if (!tmp && WEBKIT_DOM_IS_TEXT (node))
+ on_start = webkit_dom_range_get_start_offset (range, NULL) ==
0;
+ else if (tmp)
+ on_start = FALSE;
+
+ if (on_start) {
+ node = webkit_dom_node_get_parent_node (parent);
+ if (node && WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (node))
+ if (!webkit_dom_node_get_previous_sibling (node))
+ *first_cell = TRUE;
+ }
+ }
+ } else {
+ g_clear_object (&range);
+ return TRUE;
+ }
+ }
+ if (WEBKIT_DOM_IS_HTML_TABLE_ELEMENT (parent)) {
+ if (table_node != NULL)
+ *table_node = parent;
+ else {
+ g_clear_object (&range);
+ return TRUE;
+ }
+ }
+ parent = webkit_dom_node_get_parent_node (parent);
+ }
+
+ g_clear_object (&range);
+
+ if (table_node == NULL)
+ return FALSE;
+
+ return *table_node != NULL;
+}
+
+static gboolean
+jump_to_next_table_cell (WebKitDOMDocument *document,
+ gboolean jump_back)
+{
+ WebKitDOMDOMWindow *dom_window = NULL;
+ WebKitDOMDOMSelection *dom_selection = NULL;
+ WebKitDOMNode *node, *cell;
+ WebKitDOMRange *range = NULL;
+
+ if (!selection_is_in_table (document, NULL, NULL))
+ return FALSE;
+
+ dom_window = webkit_dom_document_get_default_view (document);
+ dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+ g_clear_object (&dom_window);
+ range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+ node = webkit_dom_range_get_start_container (range, NULL);
+
+ cell = node;
+ while (cell && !WEBKIT_DOM_IS_HTML_TABLE_CELL_ELEMENT (cell)) {
+ cell = webkit_dom_node_get_parent_node (cell);
+ }
+
+ if (!WEBKIT_DOM_IS_HTML_TABLE_CELL_ELEMENT (cell)) {
+ g_clear_object (&range);
+ g_clear_object (&dom_selection);
+ return FALSE;
+ }
+
+ if (jump_back) {
+ /* Get previous cell */
+ node = webkit_dom_node_get_previous_sibling (cell);
+ if (!node || !WEBKIT_DOM_IS_HTML_TABLE_CELL_ELEMENT (node)) {
+ /* No cell, go one row up. */
+ node = webkit_dom_node_get_parent_node (cell);
+ node = webkit_dom_node_get_previous_sibling (node);
+ if (node && WEBKIT_DOM_IS_HTML_TABLE_ROW_ELEMENT (node)) {
+ node = webkit_dom_node_get_last_child (node);
+ } else {
+ /* No row above, move to the block before table. */
+ node = webkit_dom_node_get_parent_node (cell);
+ while (!WEBKIT_DOM_IS_HTML_BODY_ELEMENT (webkit_dom_node_get_parent_node
(node)))
+ node = webkit_dom_node_get_parent_node (node);
+
+ node = webkit_dom_node_get_previous_sibling (node);
+ }
+ }
+ } else {
+ /* Get next cell */
+ node = webkit_dom_node_get_next_sibling (cell);
+ if (!node || !WEBKIT_DOM_IS_HTML_TABLE_CELL_ELEMENT (node)) {
+ /* No cell, go one row below. */
+ node = webkit_dom_node_get_parent_node (cell);
+ node = webkit_dom_node_get_next_sibling (node);
+ if (node && WEBKIT_DOM_IS_HTML_TABLE_ROW_ELEMENT (node)) {
+ node = webkit_dom_node_get_first_child (node);
+ } else {
+ /* No row below, move to the block after table. */
+ node = webkit_dom_node_get_parent_node (cell);
+ while (!WEBKIT_DOM_IS_HTML_BODY_ELEMENT (webkit_dom_node_get_parent_node
(node)))
+ node = webkit_dom_node_get_parent_node (node);
+
+ node = webkit_dom_node_get_next_sibling (node);
+ }
+ }
+ }
+
+ if (!node) {
+ g_clear_object (&range);
+ g_clear_object (&dom_selection);
+ return FALSE;
+ }
+
+ webkit_dom_range_select_node_contents (range, node, NULL);
+ webkit_dom_range_collapse (range, TRUE, NULL);
+ webkit_dom_dom_selection_remove_all_ranges (dom_selection);
+ webkit_dom_dom_selection_add_range (dom_selection, range);
+ g_clear_object (&range);
+ g_clear_object (&dom_selection);
+
+ return TRUE;
+}
+
+static gboolean
+save_history_before_event_in_table (EEditorPage *editor_page,
+ WebKitDOMRange *range)
+{
+ WebKitDOMNode *node;
+ WebKitDOMElement *block;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+ node = webkit_dom_range_get_start_container (range, NULL);
+ if (WEBKIT_DOM_IS_HTML_TABLE_CELL_ELEMENT (node))
+ block = WEBKIT_DOM_ELEMENT (node);
+ else
+ block = get_parent_block_element (node);
+
+ if (block && WEBKIT_DOM_IS_HTML_TABLE_CELL_ELEMENT (block)) {
+ EEditorUndoRedoManager *manager;
+ EEditorHistoryEvent *ev;
+
+ ev = g_new0 (EEditorHistoryEvent, 1);
+ ev->type = HISTORY_TABLE_INPUT;
+
+ if (block) {
+ e_editor_dom_selection_save (editor_page);
+ ev->data.dom.from = webkit_dom_node_clone_node_with_error (WEBKIT_DOM_NODE (block),
TRUE, NULL);
+ e_editor_dom_selection_restore (editor_page);
+ } else
+ ev->data.dom.from = NULL;
+
+ e_editor_dom_selection_get_coordinates (editor_page,
+ &ev->before.start.x,
+ &ev->before.start.y,
+ &ev->before.end.x,
+ &ev->before.end.y);
+
+ manager = e_editor_page_get_undo_redo_manager (editor_page);
+ e_editor_undo_redo_manager_insert_history_event (manager, ev);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+insert_tabulator (EEditorPage *editor_page)
+{
+ EEditorUndoRedoManager *manager;
+ EEditorHistoryEvent *ev = NULL;
+ gboolean success;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+ manager = e_editor_page_get_undo_redo_manager (editor_page);
+
+ if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+ ev = g_new0 (EEditorHistoryEvent, 1);
+ ev->type = HISTORY_INPUT;
+
+ if (!e_editor_dom_selection_is_collapsed (editor_page)) {
+ WebKitDOMRange *tmp_range = NULL;
+
+ tmp_range = e_editor_dom_get_current_range (editor_page);
+ insert_delete_event (editor_page, tmp_range);
+ g_clear_object (&tmp_range);
+ }
+
+ e_editor_dom_selection_get_coordinates (editor_page,
+ &ev->before.start.x,
+ &ev->before.start.y,
+ &ev->before.end.x,
+ &ev->before.end.y);
+
+ ev->before.end.x = ev->before.start.x;
+ ev->before.end.y = ev->before.start.y;
+ }
+
+ success = e_editor_dom_exec_command (editor_page, E_CONTENT_EDITOR_COMMAND_INSERT_TEXT, "\t");
+
+ if (ev) {
+ if (success) {
+ WebKitDOMDocument *document;
+ WebKitDOMElement *element;
+ WebKitDOMDocumentFragment *fragment;
+
+ document = e_editor_page_get_document (editor_page);
+
+ e_editor_dom_selection_get_coordinates (editor_page,
+ &ev->after.start.x,
+ &ev->after.start.y,
+ &ev->after.end.x,
+ &ev->after.end.y);
+
+ fragment = webkit_dom_document_create_document_fragment (document);
+ element = webkit_dom_document_create_element (document, "span", NULL);
+ webkit_dom_html_element_set_inner_text (
+ WEBKIT_DOM_HTML_ELEMENT (element), "\t", NULL);
+ webkit_dom_element_set_attribute (
+ element, "class", "Apple-tab-span", NULL);
+ webkit_dom_element_set_attribute (
+ element, "style", "white-space:pre", NULL);
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (fragment), WEBKIT_DOM_NODE (element), NULL);
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (fragment),
+ WEBKIT_DOM_NODE (dom_create_selection_marker (document, TRUE)),
+ NULL);
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (fragment),
+ WEBKIT_DOM_NODE (dom_create_selection_marker (document, FALSE)),
+ NULL);
+ ev->data.fragment = fragment;
+
+ e_editor_undo_redo_manager_insert_history_event (manager, ev);
+ e_editor_page_emit_content_changed (editor_page);
+ } else {
+ e_editor_undo_redo_manager_remove_current_history_event (manager);
+ e_editor_undo_redo_manager_remove_current_history_event (manager);
+ g_free (ev);
+ }
+ }
+
+ return success;
+}
+
+static void
+body_keypress_event_cb (WebKitDOMElement *element,
+ WebKitDOMUIEvent *event,
+ EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMDOMWindow *dom_window = NULL;
+ WebKitDOMDOMSelection *dom_selection = NULL;
+ WebKitDOMRange *range = NULL;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = webkit_dom_node_get_owner_document (WEBKIT_DOM_NODE (element));
+ dom_window = webkit_dom_document_get_default_view (document);
+ dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+ g_clear_object (&dom_window);
+ range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+
+ if (!webkit_dom_range_get_collapsed (range, NULL))
+ insert_delete_event (editor_page, range);
+
+ g_clear_object (&dom_selection);
+ g_clear_object (&range);
+}
+
+void
+e_editor_dom_set_monospace_font_family_on_body (WebKitDOMElement *body,
+ gboolean html_mode)
+{
+ /* If copying some content in view, WebKit adds various information about
+ * the content's style (such as color, font size, ..) to the resulting HTML
+ * to correctly apply the style when pasting the content later. The thing
+ * is that in plain text mode the only font allowed is the monospaced one,
+ * but we are forcing it through user style sheet in WebKitWebSettings and
+ * sadly WebKit doesn't count with it, so when the content is pasted,
+ * WebKit wraps it inside SPANs and sets the font-family style on them.
+ * The problem is that when we switch to the HTML mode, the pasted content
+ * will have the monospaced font set. To avoid it we need to set the
+ * font-family style to the body, so WebKit will know about it and will
+ * avoid the described behaviour. */
+ /* When we are deleting a content from the PRE elements we need to turn
+ * this off, otherwise we will end with the same unwanted behavior (the
+ * text between the caret and the end of the element will be wrapped
+ * inside a SPAN element. */
+ if (!html_mode) {
+ element_rename_attribute (WEBKIT_DOM_ELEMENT (body), "data-style", "style");
+ webkit_dom_element_set_attribute (
+ WEBKIT_DOM_ELEMENT (body),
+ "style",
+ "font-family: Monospace;",
+ NULL);
+ } else {
+ element_rename_attribute (WEBKIT_DOM_ELEMENT (body), "style", "data-style");
+ }
+}
+
+static void
+body_keydown_event_cb (WebKitDOMElement *element,
+ WebKitDOMUIEvent *event,
+ EEditorPage *editor_page)
+{
+ gboolean backspace_key, delete_key, space_key, return_key;
+ gboolean shift_key, control_key;
+ glong key_code;
+ WebKitDOMDocument *document;
+ WebKitDOMDOMWindow *dom_window = NULL;
+ WebKitDOMDOMSelection *dom_selection = NULL;
+ WebKitDOMRange *range = NULL;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = webkit_dom_node_get_owner_document (WEBKIT_DOM_NODE (element));
+
+ key_code = webkit_dom_ui_event_get_key_code (event);
+ delete_key = key_code == HTML_KEY_CODE_DELETE;
+ return_key = key_code == HTML_KEY_CODE_RETURN;
+ backspace_key = key_code == HTML_KEY_CODE_BACKSPACE;
+ space_key = key_code == HTML_KEY_CODE_SPACE;
+
+ if (key_code == HTML_KEY_CODE_CONTROL) {
+ dom_set_links_active (document, TRUE);
+ return;
+ }
+
+ e_editor_page_set_dont_save_history_in_body_input (editor_page, delete_key || backspace_key);
+
+ e_editor_page_set_return_key_pressed (editor_page, return_key);
+ e_editor_page_set_space_key_pressed (editor_page, space_key);
+
+ if (!(delete_key || return_key || backspace_key || space_key))
+ return;
+
+ shift_key = webkit_dom_keyboard_event_get_shift_key (WEBKIT_DOM_KEYBOARD_EVENT (event));
+ control_key = webkit_dom_keyboard_event_get_ctrl_key (WEBKIT_DOM_KEYBOARD_EVENT (event));
+
+ if (key_code == HTML_KEY_CODE_TABULATOR) {
+ if (jump_to_next_table_cell (document, shift_key)) {
+ webkit_dom_event_prevent_default (WEBKIT_DOM_EVENT (event));
+ goto out;
+ }
+
+ if (!shift_key && insert_tabulator (editor_page))
+ webkit_dom_event_prevent_default (WEBKIT_DOM_EVENT (event));
+
+ goto out;
+ }
+
+ if (return_key && e_editor_dom_key_press_event_process_return_key (editor_page)) {
+ webkit_dom_event_prevent_default (WEBKIT_DOM_EVENT (event));
+ goto out;
+ }
+
+ if (backspace_key && e_editor_dom_key_press_event_process_backspace_key (editor_page)) {
+ webkit_dom_event_prevent_default (WEBKIT_DOM_EVENT (event));
+ goto out;
+ }
+
+ if (delete_key || backspace_key) {
+ if (e_editor_dom_key_press_event_process_delete_or_backspace_key (editor_page, key_code,
control_key, delete_key))
+ webkit_dom_event_prevent_default (WEBKIT_DOM_EVENT (event));
+ else if (!e_editor_page_get_html_mode (editor_page))
+ e_editor_dom_set_monospace_font_family_on_body (element, TRUE);
+ goto out;
+ }
+
+ dom_window = webkit_dom_document_get_default_view (document);
+ dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+ g_clear_object (&dom_window);
+ range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+
+ if (save_history_before_event_in_table (editor_page, range))
+ goto out;
+
+ if (return_key) {
+ EEditorHistoryEvent *ev;
+ EEditorUndoRedoManager *manager;
+
+ /* Insert new history event for Return to have the right coordinates.
+ * The fragment will be added later. */
+ ev = g_new0 (EEditorHistoryEvent, 1);
+ ev->type = HISTORY_INPUT;
+
+ manager = e_editor_page_get_undo_redo_manager (editor_page);
+
+ e_editor_dom_selection_get_coordinates (editor_page,
+ &ev->before.start.x,
+ &ev->before.start.y,
+ &ev->before.end.x,
+ &ev->before.end.y);
+ e_editor_undo_redo_manager_insert_history_event (manager, ev);
+ }
+ out:
+ g_clear_object (&range);
+ g_clear_object (&dom_selection);
+}
+
+static gboolean
+save_history_after_event_in_table (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMDOMWindow *dom_window = NULL;
+ WebKitDOMDOMSelection *dom_selection = NULL;
+ WebKitDOMElement *element;
+ WebKitDOMNode *node;
+ WebKitDOMRange *range = NULL;
+ EEditorHistoryEvent *ev;
+ EEditorUndoRedoManager *manager;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+ document = e_editor_page_get_document (editor_page);
+ dom_window = webkit_dom_document_get_default_view (document);
+ dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+ g_clear_object (&dom_window);
+
+ if (!webkit_dom_dom_selection_get_range_count (dom_selection)) {
+ g_clear_object (&dom_selection);
+ return FALSE;
+ }
+ range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+
+ /* Find if writing into table. */
+ node = webkit_dom_range_get_start_container (range, NULL);
+ if (WEBKIT_DOM_IS_HTML_TABLE_CELL_ELEMENT (node))
+ element = WEBKIT_DOM_ELEMENT (node);
+ else
+ element = get_parent_block_element (node);
+
+ g_clear_object (&dom_selection);
+ g_clear_object (&range);
+
+ manager = e_editor_page_get_undo_redo_manager (editor_page);
+ /* If writing to table we have to create different history event. */
+ if (WEBKIT_DOM_IS_HTML_TABLE_CELL_ELEMENT (element)) {
+ ev = e_editor_undo_redo_manager_get_current_history_event (manager);
+ if (ev->type != HISTORY_TABLE_INPUT)
+ return FALSE;
+ } else
+ return FALSE;
+
+ e_editor_dom_selection_save (editor_page);
+
+ e_editor_dom_selection_get_coordinates (editor_page,
+ &ev->after.start.x,
+ &ev->after.start.y,
+ &ev->after.end.x,
+ &ev->after.end.y);
+
+ ev->data.dom.to = webkit_dom_node_clone_node_with_error (WEBKIT_DOM_NODE (element), TRUE, NULL);
+
+ e_editor_dom_selection_restore (editor_page);
+
+ return TRUE;
+}
+
+static void
+save_history_for_input (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMDocumentFragment *fragment;
+ WebKitDOMDOMWindow *dom_window = NULL;
+ WebKitDOMDOMSelection *dom_selection = NULL;
+ WebKitDOMRange *range = NULL, *range_clone = NULL;
+ WebKitDOMNode *start_container;
+ EEditorHistoryEvent *ev;
+ EEditorUndoRedoManager *manager;
+ glong offset;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+ manager = e_editor_page_get_undo_redo_manager (editor_page);
+ dom_window = webkit_dom_document_get_default_view (document);
+ dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+ g_clear_object (&dom_window);
+
+ if (!webkit_dom_dom_selection_get_range_count (dom_selection)) {
+ g_clear_object (&dom_selection);
+ return;
+ }
+
+ if (e_editor_page_get_return_key_pressed (editor_page)) {
+ ev = e_editor_undo_redo_manager_get_current_history_event (manager);
+ if (ev->type != HISTORY_INPUT) {
+ g_clear_object (&dom_selection);
+ return;
+ }
+ } else {
+ ev = g_new0 (EEditorHistoryEvent, 1);
+ ev->type = HISTORY_INPUT;
+ }
+
+ e_editor_page_block_selection_changed (editor_page);
+
+ e_editor_dom_selection_get_coordinates (editor_page,
+ &ev->after.start.x,
+ &ev->after.start.y,
+ &ev->after.end.x,
+ &ev->after.end.y);
+
+ range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+ range_clone = webkit_dom_range_clone_range (range, NULL);
+ offset = webkit_dom_range_get_start_offset (range_clone, NULL);
+ start_container = webkit_dom_range_get_start_container (range_clone, NULL);
+ if (offset > 0)
+ webkit_dom_range_set_start (
+ range_clone,
+ start_container,
+ offset - 1,
+ NULL);
+ fragment = webkit_dom_range_clone_contents (range_clone, NULL);
+ /* We have to specially handle Return key press */
+ if (e_editor_page_get_return_key_pressed (editor_page)) {
+ WebKitDOMElement *element_start, *element_end;
+ WebKitDOMNode *parent_start, *parent_end, *node;
+
+ element_start = webkit_dom_document_create_element (document, "span", NULL);
+ webkit_dom_range_surround_contents (range, WEBKIT_DOM_NODE (element_start), NULL);
+ webkit_dom_dom_selection_modify (dom_selection, "move", "left", "character");
+ g_clear_object (&range);
+ range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+ element_end = webkit_dom_document_create_element (document, "span", NULL);
+ webkit_dom_range_surround_contents (range, WEBKIT_DOM_NODE (element_end), NULL);
+
+ parent_start = webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element_start));
+ parent_end = webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element_end));
+
+ while (parent_start && parent_end && !webkit_dom_node_is_same_node (parent_start,
parent_end)) {
+ webkit_dom_node_insert_before (
+ WEBKIT_DOM_NODE (fragment),
+ webkit_dom_node_clone_node_with_error (parent_start, FALSE, NULL),
+ webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (fragment)),
+ NULL);
+ parent_start = webkit_dom_node_get_parent_node (parent_start);
+ parent_end = webkit_dom_node_get_parent_node (parent_end);
+ }
+
+ node = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (fragment));
+ while (webkit_dom_node_get_next_sibling (node)) {
+ WebKitDOMNode *last_child;
+
+ last_child = webkit_dom_node_get_last_child (WEBKIT_DOM_NODE (fragment));
+ webkit_dom_node_append_child (
+ webkit_dom_node_get_previous_sibling (last_child),
+ last_child,
+ NULL);
+ }
+
+ node = webkit_dom_node_get_last_child (WEBKIT_DOM_NODE (fragment));
+ while (webkit_dom_node_get_last_child (node)) {
+ node = webkit_dom_node_get_last_child (node);
+ }
+
+ webkit_dom_node_append_child (
+ node,
+ WEBKIT_DOM_NODE (
+ webkit_dom_document_create_element (document, "br", NULL)),
+ NULL);
+ webkit_dom_node_append_child (
+ node,
+ WEBKIT_DOM_NODE (
+ dom_create_selection_marker (document, TRUE)),
+ NULL);
+ webkit_dom_node_append_child (
+ node,
+ WEBKIT_DOM_NODE (
+ dom_create_selection_marker (document, FALSE)),
+ NULL);
+
+ remove_node (WEBKIT_DOM_NODE (element_start));
+ remove_node (WEBKIT_DOM_NODE (element_end));
+
+ g_object_set_data (
+ G_OBJECT (fragment), "history-return-key", GINT_TO_POINTER (1));
+
+ webkit_dom_dom_selection_modify (dom_selection, "move", "right", "character");
+ } else {
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (fragment),
+ WEBKIT_DOM_NODE (
+ dom_create_selection_marker (document, TRUE)),
+ NULL);
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (fragment),
+ WEBKIT_DOM_NODE (
+ dom_create_selection_marker (document, FALSE)),
+ NULL);
+ }
+
+ g_clear_object (&dom_selection);
+ g_clear_object (&range);
+ g_clear_object (&range_clone);
+
+ e_editor_page_unblock_selection_changed (editor_page);
+
+ ev->data.fragment = fragment;
+
+ if (!e_editor_page_get_return_key_pressed (editor_page))
+ e_editor_undo_redo_manager_insert_history_event (manager, ev);
+}
+
+typedef struct _TimeoutContext TimeoutContext;
+
+struct _TimeoutContext {
+ EEditorPage *editor_page;
+};
+
+static void
+timeout_context_free (TimeoutContext *context)
+{
+ g_slice_free (TimeoutContext, context);
+}
+
+static gboolean
+force_spell_check_on_timeout (TimeoutContext *context)
+{
+ e_editor_dom_force_spell_check_in_viewport (context->editor_page);
+ e_editor_page_set_spell_check_on_scroll_event_source_id (context->editor_page, 0);
+ return FALSE;
+}
+
+static void
+body_scroll_event_cb (WebKitDOMElement *element,
+ WebKitDOMEvent *event,
+ EEditorPage *editor_page)
+{
+ TimeoutContext *context;
+ guint id;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ if (!e_editor_page_get_inline_spelling_enabled (editor_page))
+ return;
+
+ context = g_slice_new0 (TimeoutContext);
+ context->editor_page = editor_page;
+
+ id = e_editor_page_get_spell_check_on_scroll_event_source_id (editor_page);
+ if (id > 0)
+ g_source_remove (id);
+
+ id = g_timeout_add_seconds_full (
+ 1,
+ G_PRIORITY_DEFAULT,
+ (GSourceFunc)force_spell_check_on_timeout,
+ context,
+ (GDestroyNotify)timeout_context_free);
+
+ e_editor_page_set_spell_check_on_scroll_event_source_id (editor_page, id);
+}
+
+void
+e_editor_dom_body_input_event_process (EEditorPage *editor_page,
+ WebKitDOMEvent *event)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMNode *node;
+ WebKitDOMRange *range = NULL;
+ EEditorUndoRedoManager *manager;
+ gboolean do_spell_check = FALSE;
+ gboolean html_mode;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+ range = e_editor_dom_get_current_range (editor_page);
+
+ manager = e_editor_page_get_undo_redo_manager (editor_page);
+
+ html_mode = e_editor_page_get_html_mode (editor_page);
+ e_editor_page_emit_content_changed (editor_page);
+
+ if (e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+ e_editor_undo_redo_manager_set_operation_in_progress (manager, FALSE);
+ e_editor_page_set_dont_save_history_in_body_input (editor_page, FALSE);
+ do_spell_check = TRUE;
+ goto out;
+ }
+
+ /* When the Backspace is pressed in a bulleted list item with just one
+ * character left in it, WebKit will create another BR element in the
+ * item. */
+ if (!html_mode) {
+ WebKitDOMElement *element;
+
+ element = webkit_dom_document_query_selector (
+ document, "ul > li > br + br", NULL);
+
+ if (element)
+ remove_node (WEBKIT_DOM_NODE (element));
+ }
+
+ if (!save_history_after_event_in_table (editor_page)) {
+ if (!e_editor_page_get_dont_save_history_in_body_input (editor_page))
+ save_history_for_input (editor_page);
+ else
+ do_spell_check = TRUE;
+ }
+
+ /* Don't try to look for smileys if we are deleting text. */
+ if (!e_editor_page_get_dont_save_history_in_body_input (editor_page))
+ e_editor_dom_check_magic_smileys (editor_page);
+
+ e_editor_page_set_dont_save_history_in_body_input (editor_page, FALSE);
+
+ if (e_editor_page_get_return_key_pressed (editor_page) ||
+ e_editor_page_get_space_key_pressed (editor_page)) {
+ e_editor_dom_check_magic_links (editor_page, FALSE);
+ if (e_editor_page_get_return_key_pressed (editor_page)) {
+ if (fix_paragraph_structure_after_pressing_enter (editor_page) &&
+ html_mode) {
+ /* When the return is pressed in a H1-6 element, WebKit doesn't
+ * continue with the same element, but creates normal paragraph,
+ * so we have to unset the bold font. */
+ e_editor_undo_redo_manager_set_operation_in_progress (manager, TRUE);
+ e_editor_dom_selection_set_bold (editor_page, FALSE);
+ e_editor_undo_redo_manager_set_operation_in_progress (manager, FALSE);
+ }
+
+ fix_paragraph_structure_after_pressing_enter_after_smiley (document);
+
+ do_spell_check = TRUE;
+ }
+ } else {
+ WebKitDOMNode *node;
+
+ node = webkit_dom_range_get_end_container (range, NULL);
+
+ if (surround_text_with_paragraph_if_needed (editor_page, node)) {
+ WebKitDOMElement *element;
+
+ element = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-start-marker");
+ node = webkit_dom_node_get_previous_sibling (WEBKIT_DOM_NODE (element));
+ e_editor_dom_selection_restore (editor_page);
+ }
+
+ if (WEBKIT_DOM_IS_TEXT (node)) {
+ gchar *text;
+
+ text = webkit_dom_node_get_text_content (node);
+
+ if (text && *text && *text != ' ' && !g_str_has_prefix (text, UNICODE_NBSP)) {
+ gboolean valid = FALSE;
+
+ if (*text == '?' && strlen (text) > 1)
+ valid = TRUE;
+ else if (!strchr (URL_INVALID_TRAILING_CHARS, *text))
+ valid = TRUE;
+
+ if (valid) {
+ WebKitDOMNode *prev_sibling;
+
+ prev_sibling = webkit_dom_node_get_previous_sibling (node);
+
+ if (WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (prev_sibling))
+ e_editor_dom_check_magic_links (editor_page, FALSE);
+ }
+ }
+ g_free (text);
+ }
+ }
+
+ node = webkit_dom_range_get_end_container (range, NULL);
+
+ /* After toggling monospaced format, we are using UNICODE_ZERO_WIDTH_SPACE
+ * to move caret into right space. When this callback is called it is not
+ * necessary anymore so remove it */
+ if (html_mode) {
+ WebKitDOMElement *parent = webkit_dom_node_get_parent_element (node);
+
+ if (parent) {
+ WebKitDOMNode *prev_sibling;
+
+ prev_sibling = webkit_dom_node_get_previous_sibling (
+ WEBKIT_DOM_NODE (parent));
+
+ if (prev_sibling && WEBKIT_DOM_IS_TEXT (prev_sibling)) {
+ gchar *text = webkit_dom_node_get_text_content (
+ prev_sibling);
+
+ if (g_strcmp0 (text, UNICODE_ZERO_WIDTH_SPACE) == 0)
+ remove_node (prev_sibling);
+
+ g_free (text);
+ }
+
+ }
+ }
+
+ /* If text before caret includes UNICODE_ZERO_WIDTH_SPACE character, remove it */
+ if (WEBKIT_DOM_IS_TEXT (node)) {
+ gchar *text = webkit_dom_character_data_get_data (WEBKIT_DOM_CHARACTER_DATA (node));
+ glong length = webkit_dom_character_data_get_length (WEBKIT_DOM_CHARACTER_DATA (node));
+ WebKitDOMNode *parent;
+
+ /* We have to preserve empty paragraphs with just UNICODE_ZERO_WIDTH_SPACE
+ * character as when we will remove it it will collapse */
+ if (length > 1) {
+ if (g_str_has_prefix (text, UNICODE_ZERO_WIDTH_SPACE))
+ webkit_dom_character_data_replace_data (
+ WEBKIT_DOM_CHARACTER_DATA (node), 0, 1, "", NULL);
+ else if (g_str_has_suffix (text, UNICODE_ZERO_WIDTH_SPACE))
+ webkit_dom_character_data_replace_data (
+ WEBKIT_DOM_CHARACTER_DATA (node), length - 1, 1, "", NULL);
+ }
+ g_free (text);
+
+ parent = webkit_dom_node_get_parent_node (node);
+ if (WEBKIT_DOM_IS_HTML_PARAGRAPH_ELEMENT (parent) &&
+ !webkit_dom_element_has_attribute (WEBKIT_DOM_ELEMENT (parent), "data-evo-paragraph")) {
+ if (html_mode)
+ webkit_dom_element_set_attribute (
+ WEBKIT_DOM_ELEMENT (parent),
+ "data-evo-paragraph",
+ "",
+ NULL);
+ else
+ e_editor_dom_set_paragraph_style (
+ editor_page, WEBKIT_DOM_ELEMENT (parent), -1, 0, NULL);
+ }
+
+ /* When new smiley is added we have to use UNICODE_HIDDEN_SPACE to set the
+ * caret position to right place. It is removed when user starts typing. But
+ * when the user will press left arrow he will move the caret into
+ * smiley wrapper. If he will start to write there we have to move the written
+ * text out of the wrapper and move caret to right place */
+ if (WEBKIT_DOM_IS_ELEMENT (parent) &&
+ element_has_class (WEBKIT_DOM_ELEMENT (parent), "-x-evo-smiley-text")) {
+ gchar *text;
+ WebKitDOMCharacterData *data;
+ WebKitDOMText *text_node;
+
+ /* Split out the newly written character to its own text node, */
+ data = WEBKIT_DOM_CHARACTER_DATA (node);
+ parent = webkit_dom_node_get_parent_node (parent);
+ text = webkit_dom_character_data_substring_data (
+ data,
+ webkit_dom_character_data_get_length (data) - 1,
+ 1,
+ NULL);
+ webkit_dom_character_data_delete_data (
+ data,
+ webkit_dom_character_data_get_length (data) - 1,
+ 1,
+ NULL);
+ text_node = webkit_dom_document_create_text_node (document, text);
+ g_free (text);
+
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (parent),
+ WEBKIT_DOM_NODE (
+ dom_create_selection_marker (document, FALSE)),
+ webkit_dom_node_get_next_sibling (parent),
+ NULL);
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (parent),
+ WEBKIT_DOM_NODE (
+ dom_create_selection_marker (document, TRUE)),
+ webkit_dom_node_get_next_sibling (parent),
+ NULL);
+ /* Move the text node outside of smiley. */
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (parent),
+ WEBKIT_DOM_NODE (text_node),
+ webkit_dom_node_get_next_sibling (parent),
+ NULL);
+ e_editor_dom_selection_restore (editor_page);
+ }
+ }
+
+ /* Writing into quoted content */
+ if (html_mode) {
+ gint citation_level;
+ WebKitDOMElement *selection_start_marker, *selection_end_marker;
+ WebKitDOMNode *node, *parent;
+
+ node = webkit_dom_range_get_end_container (range, NULL);
+
+ citation_level = e_editor_dom_get_citation_level (node, FALSE);
+ if (citation_level == 0)
+ goto out;
+
+ selection_start_marker = webkit_dom_document_query_selector (
+ document, "span#-x-evo-selection-start-marker", NULL);
+ if (selection_start_marker)
+ goto out;
+
+ e_editor_dom_selection_save (editor_page);
+
+ selection_start_marker = webkit_dom_document_query_selector (
+ document, "span#-x-evo-selection-start-marker", NULL);
+ selection_end_marker = webkit_dom_document_query_selector (
+ document, "span#-x-evo-selection-end-marker", NULL);
+ /* If the selection was not saved, move it into the first child of body */
+ if (!selection_start_marker || !selection_end_marker) {
+ WebKitDOMHTMLElement *body;
+ WebKitDOMNode *child;
+
+ body = webkit_dom_document_get_body (document);
+ child = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (body));
+
+ dom_add_selection_markers_into_element_start (
+ document,
+ WEBKIT_DOM_ELEMENT (child),
+ &selection_start_marker,
+ &selection_end_marker);
+ }
+
+ /* We have to process elements only inside normal block */
+ parent = WEBKIT_DOM_NODE (get_parent_block_element (
+ WEBKIT_DOM_NODE (selection_start_marker)));
+ if (WEBKIT_DOM_IS_HTML_PRE_ELEMENT (parent)) {
+ e_editor_dom_selection_restore (editor_page);
+ goto out;
+ }
+
+ if (selection_start_marker) {
+ gchar *content;
+ gint text_length, word_wrap_length, length;
+ WebKitDOMElement *block;
+ gboolean remove_quoting = FALSE;
+
+ word_wrap_length = e_editor_page_get_word_wrap_length (editor_page);
+ length = word_wrap_length - 2 * citation_level;
+
+ block = WEBKIT_DOM_ELEMENT (parent);
+ if (webkit_dom_element_query_selector (
+ WEBKIT_DOM_ELEMENT (block), ".-x-evo-quoted", NULL)) {
+ WebKitDOMNode *prev_sibling;
+
+ prev_sibling = webkit_dom_node_get_previous_sibling (
+ WEBKIT_DOM_NODE (selection_end_marker));
+
+ if (WEBKIT_DOM_IS_ELEMENT (prev_sibling))
+ remove_quoting = element_has_class (
+ WEBKIT_DOM_ELEMENT (prev_sibling), "-x-evo-quoted");
+ }
+
+ content = webkit_dom_node_get_text_content (WEBKIT_DOM_NODE (block));
+ text_length = g_utf8_strlen (content, -1);
+ g_free (content);
+
+ /* Wrap and quote the line */
+ if (!remove_quoting && text_length >= word_wrap_length) {
+ e_editor_dom_remove_quoting_from_element (block);
+
+ block = e_editor_dom_wrap_paragraph_length (editor_page, block, length);
+ webkit_dom_node_normalize (WEBKIT_DOM_NODE (block));
+ e_editor_dom_quote_plain_text_element_after_wrapping (
+ editor_page, WEBKIT_DOM_ELEMENT (block), citation_level);
+ selection_start_marker = webkit_dom_document_query_selector (
+ document, "span#-x-evo-selection-start-marker", NULL);
+ if (!selection_start_marker)
+ dom_add_selection_markers_into_element_end (
+ document,
+ WEBKIT_DOM_ELEMENT (block),
+ NULL,
+ NULL);
+
+ e_editor_dom_selection_restore (editor_page);
+ do_spell_check = TRUE;
+ goto out;
+ }
+ }
+ e_editor_dom_selection_restore (editor_page);
+ }
+ out:
+ if (do_spell_check)
+ e_editor_dom_force_spell_check_for_current_paragraph (editor_page);
+
+ g_clear_object (&range);
+}
+
+static void
+body_input_event_cb (WebKitDOMElement *element,
+ WebKitDOMEvent *event,
+ EEditorPage *editor_page)
+{
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ e_editor_dom_body_input_event_process (editor_page, event);
+}
+
+void
+e_editor_dom_remove_input_event_listener_from_body (EEditorPage *editor_page)
+{
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ if (!e_editor_page_get_body_input_event_removed (editor_page)) {
+ WebKitDOMDocument *document;
+
+ document = e_editor_page_get_document (editor_page);
+
+ webkit_dom_event_target_remove_event_listener (
+ WEBKIT_DOM_EVENT_TARGET (webkit_dom_document_get_body (document)),
+ "input",
+ G_CALLBACK (body_input_event_cb),
+ FALSE);
+
+ e_editor_page_set_body_input_event_removed (editor_page, TRUE);
+ }
+}
+
+void
+e_editor_dom_register_input_event_listener_on_body (EEditorPage *editor_page)
+{
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ if (e_editor_page_get_body_input_event_removed (editor_page)) {
+ WebKitDOMDocument *document;
+
+ document = e_editor_page_get_document (editor_page);
+
+ webkit_dom_event_target_add_event_listener (
+ WEBKIT_DOM_EVENT_TARGET (webkit_dom_document_get_body (document)),
+ "input",
+ G_CALLBACK (body_input_event_cb),
+ FALSE,
+ editor_page);
+
+ e_editor_page_set_body_input_event_removed (editor_page, FALSE);
+ }
+}
+
+static void
+remove_empty_blocks (WebKitDOMDocument *document)
+{
+ gint ii, length;
+ WebKitDOMNodeList *list = NULL;
+
+ list = webkit_dom_document_query_selector_all (
+ document, "blockquote[type=cite] > :empty", NULL);
+
+ length = webkit_dom_node_list_get_length (list);
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMNode *node = webkit_dom_node_list_item (list, ii);
+ remove_node (node);
+ g_object_unref (node);
+ }
+ g_clear_object (&list);
+
+ list = webkit_dom_document_query_selector_all (
+ document, "blockquote[type=cite]:empty", NULL);
+
+ length = webkit_dom_node_list_get_length (list);
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMNode *node = webkit_dom_node_list_item (list, ii);
+ remove_node (node);
+ g_object_unref (node);
+ }
+ g_clear_object (&list);
+}
+
+/* Following two functions are used when deleting the selection inside
+ * the quoted content. The thing is that normally the quote marks are not
+ * selectable by user. But this caused a lof of problems for WebKit when removing
+ * the selection. This will avoid it as when the delete or backspace key is pressed
+ * we will make the quote marks user selectable so they will act as any other text.
+ * On HTML keyup event callback we will make them again non-selectable. */
+void
+e_editor_dom_disable_quote_marks_select (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMHTMLHeadElement *head;
+ WebKitDOMElement *style_element;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+ head = webkit_dom_document_get_head (document);
+
+ if (!webkit_dom_document_get_element_by_id (document, "-x-evo-quote-style")) {
+ style_element = webkit_dom_document_create_element (document, "style", NULL);
+ webkit_dom_element_set_id (style_element, "-x-evo-quote-style");
+ webkit_dom_element_set_attribute (style_element, "type", "text/css", NULL);
+ webkit_dom_element_set_inner_html (
+ style_element,
+ ".-x-evo-quoted { -webkit-user-select: none; }",
+ NULL);
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (head), WEBKIT_DOM_NODE (style_element), NULL);
+ }
+}
+
+static void
+enable_quote_marks_select (WebKitDOMDocument *document)
+{
+ WebKitDOMElement *style_element;
+
+ if ((style_element = webkit_dom_document_get_element_by_id (document, "-x-evo-quote-style")))
+ remove_node (WEBKIT_DOM_NODE (style_element));
+}
+
+void
+e_editor_dom_remove_node_and_parents_if_empty (WebKitDOMNode *node)
+{
+ WebKitDOMNode *parent;
+
+ parent = webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (node));
+
+ remove_node (WEBKIT_DOM_NODE (node));
+
+ while (parent && !WEBKIT_DOM_IS_HTML_BODY_ELEMENT (parent)) {
+ WebKitDOMNode *tmp;
+
+ tmp = webkit_dom_node_get_parent_node (parent);
+ remove_node_if_empty (parent);
+ parent = tmp;
+ }
+}
+
+void
+e_editor_dom_merge_siblings_if_necessary (EEditorPage *editor_page,
+ WebKitDOMDocumentFragment *deleted_content)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *element, *prev_element;
+ WebKitDOMNode *child;
+ WebKitDOMNodeList *list = NULL;
+ gboolean equal_nodes;
+ gint ii, length;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+
+ if ((element = webkit_dom_document_get_element_by_id (document, "-x-evo-main-cite")))
+ webkit_dom_element_remove_attribute (element, "id");
+
+ element = webkit_dom_document_query_selector (document, "blockquote:not([data-evo-query-skip]) +
blockquote", NULL);
+ if (!element)
+ goto signature;
+ repeat:
+ child = webkit_dom_node_get_previous_sibling (WEBKIT_DOM_NODE (element));
+ if (WEBKIT_DOM_IS_ELEMENT (child))
+ prev_element = WEBKIT_DOM_ELEMENT (child);
+ else
+ goto signature;
+
+ equal_nodes = webkit_dom_node_is_equal_node (
+ webkit_dom_node_clone_node_with_error (WEBKIT_DOM_NODE (element), FALSE, NULL),
+ webkit_dom_node_clone_node_with_error (WEBKIT_DOM_NODE (prev_element), FALSE, NULL));
+
+ if (equal_nodes) {
+ if (webkit_dom_element_get_child_element_count (element) >
+ webkit_dom_element_get_child_element_count (prev_element)) {
+ while ((child = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (element))))
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (prev_element), child, NULL);
+ remove_node (WEBKIT_DOM_NODE (element));
+ } else {
+ while ((child = webkit_dom_node_get_last_child (WEBKIT_DOM_NODE (prev_element))))
+ webkit_dom_node_insert_before (
+ WEBKIT_DOM_NODE (element),
+ child,
+ webkit_dom_node_get_first_child (
+ WEBKIT_DOM_NODE (element)),
+ NULL);
+ remove_node (WEBKIT_DOM_NODE (prev_element));
+ }
+ } else
+ webkit_dom_element_set_attribute (element, "data-evo-query-skip", "", NULL);
+
+ element = webkit_dom_document_query_selector (document, "blockquote:not([data-evo-query-skip]) +
blockquote", NULL);
+ if (element)
+ goto repeat;
+
+ signature:
+ list = webkit_dom_document_query_selector_all (
+ document, "blockquote[data-evo-query-skip]", NULL);
+ length = webkit_dom_node_list_get_length (list);
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMNode *node = webkit_dom_node_list_item (list, ii);
+ webkit_dom_element_remove_attribute (
+ WEBKIT_DOM_ELEMENT (node), "data-evo-query-skip");
+ g_object_unref (node);
+ }
+ g_clear_object (&list);
+
+ if (!deleted_content)
+ return;
+
+ /* Replace the corrupted signatures with the right one. */
+ element = webkit_dom_document_query_selector (
+ document, ".-x-evo-signature-wrapper + .-x-evo-signature-wrapper", NULL);
+ if (element) {
+ WebKitDOMElement *right_signature;
+
+ right_signature = webkit_dom_document_fragment_query_selector (
+ deleted_content, ".-x-evo-signature-wrapper", NULL);
+ remove_node (webkit_dom_node_get_previous_sibling (WEBKIT_DOM_NODE (element)));
+ webkit_dom_node_replace_child (
+ webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element)),
+ webkit_dom_node_clone_node_with_error (WEBKIT_DOM_NODE (right_signature), TRUE, NULL),
+ WEBKIT_DOM_NODE (element),
+ NULL);
+ }
+}
+
+/* This will fix the structure after the situations where some text
+ * inside the quoted content is selected and afterwards deleted with
+ * BackSpace or Delete. */
+void
+e_editor_dom_body_key_up_event_process_backspace_or_delete (EEditorPage *editor_page,
+ gboolean delete)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *selection_start_marker, *selection_end_marker;
+ WebKitDOMNode *parent, *node;
+ gint level;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ if (e_editor_page_get_html_mode (editor_page))
+ return;
+
+ document = e_editor_page_get_document (editor_page);
+ e_editor_dom_disable_quote_marks_select (editor_page);
+ /* Remove empty blocks if presented. */
+ remove_empty_blocks (document);
+
+ e_editor_dom_selection_save (editor_page);
+ selection_start_marker = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-start-marker");
+ selection_end_marker = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-end-marker");
+
+ /* If we deleted a selection the caret will be inside the quote marks, fix it. */
+ parent = webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (selection_start_marker));
+ if (element_has_class (WEBKIT_DOM_ELEMENT (parent), "-x-evo-quote-character")) {
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (
+ webkit_dom_node_get_parent_node (parent)),
+ WEBKIT_DOM_NODE (selection_end_marker),
+ webkit_dom_node_get_next_sibling (
+ webkit_dom_node_get_parent_node (parent)),
+ NULL);
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (
+ webkit_dom_node_get_parent_node (parent)),
+ WEBKIT_DOM_NODE (selection_start_marker),
+ webkit_dom_node_get_next_sibling (
+ webkit_dom_node_get_parent_node (parent)),
+ NULL);
+ }
+
+ /* Under some circumstances we will end with block inside the citation
+ * that has the quote marks removed and we have to reinsert them back. */
+ level = e_editor_dom_get_citation_level (WEBKIT_DOM_NODE (selection_start_marker), FALSE);
+ node = webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (selection_end_marker));
+ if (level > 0 && node && !WEBKIT_DOM_IS_HTML_BR_ELEMENT (node)) {
+ WebKitDOMElement *block;
+
+ block = WEBKIT_DOM_ELEMENT (e_editor_dom_get_parent_block_node_from_child (
+ WEBKIT_DOM_NODE (selection_start_marker)));
+
+ e_editor_dom_remove_quoting_from_element (block);
+ if (webkit_dom_element_has_attribute (block, "data-evo-paragraph")) {
+ gint length, word_wrap_length;
+
+ word_wrap_length = e_editor_page_get_word_wrap_length (editor_page);
+ length = word_wrap_length - 2 * level;
+ block = e_editor_dom_wrap_paragraph_length (editor_page, block, length);
+ webkit_dom_node_normalize (WEBKIT_DOM_NODE (block));
+ }
+ e_editor_dom_quote_plain_text_element_after_wrapping (editor_page, block, level);
+ } else if (level > 0 && !node) {
+ WebKitDOMNode *prev_sibling;
+
+ prev_sibling = webkit_dom_node_get_previous_sibling (
+ WEBKIT_DOM_NODE (selection_start_marker));
+ if (WEBKIT_DOM_IS_ELEMENT (prev_sibling) &&
+ element_has_class (WEBKIT_DOM_ELEMENT (prev_sibling), "-x-evo-quoted") &&
+ !webkit_dom_node_get_previous_sibling (prev_sibling))
+ webkit_dom_node_append_child (
+ parent,
+ WEBKIT_DOM_NODE (webkit_dom_document_create_element (document, "br", NULL)),
+ NULL);
+ }
+
+ e_editor_dom_merge_siblings_if_necessary (editor_page, NULL);
+
+ e_editor_dom_selection_restore (editor_page);
+ e_editor_dom_force_spell_check_for_current_paragraph (editor_page);
+}
+
+void
+e_editor_dom_body_key_up_event_process_return_key (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *selection_start_marker, *selection_end_marker;
+ WebKitDOMNode *parent;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ /* If the return is pressed in an unordered list in plain text mode
+ * the caret is moved to the "*" character before the newly inserted
+ * item. It looks like it is not enough that the item has BR element
+ * inside, but we have to again use the zero width space character
+ * to fix the situation. */
+ if (e_editor_page_get_html_mode (editor_page))
+ return;
+
+ /* FIXME WK2 this is called twice */
+ /* e_editor_dom_selection_save (editor_page); */
+
+ document = e_editor_page_get_document (editor_page);
+ e_editor_dom_selection_save (editor_page);
+
+ selection_start_marker = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-start-marker");
+ selection_end_marker = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-end-marker");
+
+ parent = webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (selection_start_marker));
+ if (!WEBKIT_DOM_IS_HTML_LI_ELEMENT (parent) ||
+ !WEBKIT_DOM_IS_HTML_U_LIST_ELEMENT (webkit_dom_node_get_parent_node (parent))) {
+ e_editor_dom_selection_restore (editor_page);
+ return;
+ }
+
+ if (!webkit_dom_node_get_previous_sibling (WEBKIT_DOM_NODE (selection_start_marker)) &&
+ (!webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (selection_end_marker)) ||
+ WEBKIT_DOM_IS_HTML_BR_ELEMENT (webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE
(selection_end_marker)))))
+ webkit_dom_html_element_insert_adjacent_text (
+ WEBKIT_DOM_HTML_ELEMENT (parent),
+ "afterbegin",
+ UNICODE_ZERO_WIDTH_SPACE,
+ NULL);
+
+ e_editor_dom_selection_restore (editor_page);
+}
+
+static void
+body_keyup_event_cb (WebKitDOMElement *element,
+ WebKitDOMUIEvent *event,
+ EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ glong key_code;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = webkit_dom_node_get_owner_document (WEBKIT_DOM_NODE (element));
+ if (!e_editor_page_is_composition_in_progress (editor_page))
+ e_editor_dom_register_input_event_listener_on_body (editor_page);
+
+ if (!e_editor_dom_selection_is_collapsed (editor_page))
+ return;
+
+ key_code = webkit_dom_ui_event_get_key_code (event);
+ if (key_code == HTML_KEY_CODE_BACKSPACE || key_code == HTML_KEY_CODE_DELETE) {
+ if (!e_editor_page_get_html_mode (editor_page)) {
+ WebKitDOMHTMLElement *body;
+
+ body = webkit_dom_document_get_body (document);
+
+ e_editor_dom_set_monospace_font_family_on_body (WEBKIT_DOM_ELEMENT (body), FALSE);
+ }
+ e_editor_dom_body_key_up_event_process_backspace_or_delete (editor_page, key_code ==
HTML_KEY_CODE_DELETE);
+
+ /* The content was wrapped and the coordinates
+ * of caret could be changed, so renew them. But
+ * only do that when we are not redoing a history
+ * event, otherwise it would modify the history. */
+ if (e_editor_page_get_renew_history_after_coordinates (editor_page)) {
+ EEditorHistoryEvent *ev = NULL;
+ EEditorUndoRedoManager *manager;
+
+ manager = e_editor_page_get_undo_redo_manager (editor_page);
+ ev = e_editor_undo_redo_manager_get_current_history_event (manager);
+ e_editor_dom_selection_get_coordinates (editor_page,
+ &ev->after.start.x,
+ &ev->after.start.y,
+ &ev->after.end.x,
+ &ev->after.end.y);
+ }
+ } else if (key_code == HTML_KEY_CODE_CONTROL)
+ dom_set_links_active (document, FALSE);
+ else if (key_code == HTML_KEY_CODE_RETURN)
+ e_editor_dom_body_key_up_event_process_return_key (editor_page);
+}
+
+static void
+fix_structure_after_pasting_multiline_content (WebKitDOMNode *node)
+{
+ WebKitDOMNode *first_child, *parent;
+
+ /* When pasting content that does not contain just the
+ * one line text WebKit inserts all the content after the
+ * first line into one element. So we have to take it out
+ * of this element and insert it after that element. */
+ parent = webkit_dom_node_get_parent_node (node);
+ if (WEBKIT_DOM_IS_HTML_BODY_ELEMENT (parent))
+ return;
+ first_child = webkit_dom_node_get_first_child (parent);
+ while (first_child) {
+ WebKitDOMNode *next_child =
+ webkit_dom_node_get_next_sibling (first_child);
+ if (webkit_dom_node_has_child_nodes (first_child))
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (parent),
+ first_child,
+ parent,
+ NULL);
+ first_child = next_child;
+ }
+}
+
+static gboolean
+delete_hidden_space (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *selection_start_marker, *selection_end_marker, *block;
+ gint citation_level;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+ document = e_editor_page_get_document (editor_page);
+
+ selection_start_marker = webkit_dom_document_query_selector (
+ document, "span#-x-evo-selection-start-marker", NULL);
+ selection_end_marker = webkit_dom_document_query_selector (
+ document, "span#-x-evo-selection-end-marker", NULL);
+
+ if (!selection_start_marker || !selection_end_marker)
+ return FALSE;
+
+ block = WEBKIT_DOM_ELEMENT (e_editor_dom_get_parent_block_node_from_child (
+ WEBKIT_DOM_NODE (selection_start_marker)));
+
+ citation_level = e_editor_dom_get_citation_level (
+ WEBKIT_DOM_NODE (selection_start_marker), FALSE);
+
+ if (selection_start_marker && citation_level > 0) {
+ EEditorUndoRedoManager *manager;
+ EEditorHistoryEvent *ev = NULL;
+ WebKitDOMNode *node;
+ WebKitDOMDocumentFragment *fragment;
+
+ manager = e_editor_page_get_undo_redo_manager (editor_page);
+
+ node = webkit_dom_node_get_previous_sibling (WEBKIT_DOM_NODE (selection_start_marker));
+ if (!(WEBKIT_DOM_IS_ELEMENT (node) &&
+ element_has_class (WEBKIT_DOM_ELEMENT (node), "-x-evo-quoted")))
+ return FALSE;
+
+ node = webkit_dom_node_get_previous_sibling (node);
+ if (!(WEBKIT_DOM_IS_ELEMENT (node) &&
+ element_has_class (WEBKIT_DOM_ELEMENT (node), "-x-evo-wrap-br")))
+ return FALSE;
+
+ node = webkit_dom_node_get_previous_sibling (node);
+ if (!(WEBKIT_DOM_IS_ELEMENT (node) &&
+ webkit_dom_element_has_attribute (WEBKIT_DOM_ELEMENT (node), "data-hidden-space")))
+ return FALSE;
+
+ ev = g_new0 (EEditorHistoryEvent, 1);
+ ev->type = HISTORY_DELETE;
+
+ e_editor_dom_selection_get_coordinates (editor_page, &ev->before.start.x,
&ev->before.start.y, &ev->before.end.x, &ev->before.end.y);
+
+ remove_node (node);
+
+ e_editor_dom_wrap_and_quote_element (editor_page, block);
+
+ fragment = webkit_dom_document_create_document_fragment (document);
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (fragment),
+ WEBKIT_DOM_NODE (
+ webkit_dom_document_create_text_node (document, " ")),
+ NULL);
+ ev->data.fragment = fragment;
+
+ e_editor_dom_selection_get_coordinates (editor_page, &ev->after.start.x, &ev->after.start.y,
&ev->after.end.x, &ev->after.end.y);
+
+ e_editor_undo_redo_manager_insert_history_event (manager, ev);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+gboolean
+e_editor_dom_move_quoted_block_level_up (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *selection_start_marker, *selection_end_marker;
+ WebKitDOMNode *block;
+ EEditorHistoryEvent *ev = NULL;
+ EEditorUndoRedoManager *manager;
+ gboolean html_mode;
+ gint citation_level, success = FALSE;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+ document = e_editor_page_get_document (editor_page);
+ manager = e_editor_page_get_undo_redo_manager (editor_page);
+ html_mode = e_editor_page_get_html_mode (editor_page);
+
+ selection_start_marker = webkit_dom_document_query_selector (
+ document, "span#-x-evo-selection-start-marker", NULL);
+ selection_end_marker = webkit_dom_document_query_selector (
+ document, "span#-x-evo-selection-end-marker", NULL);
+
+ if (!selection_start_marker || !selection_end_marker)
+ return FALSE;
+
+ block = e_editor_dom_get_parent_block_node_from_child (WEBKIT_DOM_NODE (selection_start_marker));
+
+ citation_level = e_editor_dom_get_citation_level (
+ WEBKIT_DOM_NODE (selection_start_marker), FALSE);
+
+ if (selection_start_marker && citation_level > 0) {
+ if (webkit_dom_element_query_selector (
+ WEBKIT_DOM_ELEMENT (block), ".-x-evo-quoted", NULL)) {
+
+ WebKitDOMNode *prev_sibling;
+
+ webkit_dom_node_normalize (block);
+
+ prev_sibling = webkit_dom_node_get_previous_sibling (
+ WEBKIT_DOM_NODE (selection_start_marker));
+
+ if (!prev_sibling) {
+ WebKitDOMNode *parent;
+
+ parent = webkit_dom_node_get_parent_node (
+ WEBKIT_DOM_NODE (selection_start_marker));
+ if (WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (parent))
+ prev_sibling = webkit_dom_node_get_previous_sibling (parent);
+ }
+
+ if (WEBKIT_DOM_IS_ELEMENT (prev_sibling))
+ success = element_has_class (
+ WEBKIT_DOM_ELEMENT (prev_sibling), "-x-evo-quoted");
+
+ /* We really have to be in the beginning of paragraph and
+ * not on the beginning of some line in the paragraph */
+ if (success && webkit_dom_node_get_previous_sibling (prev_sibling))
+ success = FALSE;
+ }
+
+ if (html_mode)
+ success = WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (
+ webkit_dom_node_get_parent_element (block));
+ }
+
+ if (!success)
+ return FALSE;
+
+ if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+ ev = g_new0 (EEditorHistoryEvent, 1);
+ ev->type = HISTORY_UNQUOTE;
+
+ e_editor_dom_selection_get_coordinates (editor_page, &ev->before.start.x,
&ev->before.start.y, &ev->before.end.x, &ev->before.end.y);
+ ev->data.dom.from = webkit_dom_node_clone_node_with_error (block, TRUE, NULL);
+ }
+
+ if (citation_level == 1) {
+ gchar *inner_html;
+ WebKitDOMElement *paragraph, *element;
+
+ inner_html = webkit_dom_element_get_inner_html (WEBKIT_DOM_ELEMENT (block));
+ webkit_dom_element_set_id (WEBKIT_DOM_ELEMENT (block), "-x-evo-to-remove");
+
+ paragraph = e_editor_dom_insert_new_line_into_citation (editor_page, inner_html);
+ g_free (inner_html);
+
+ if (paragraph) {
+ webkit_dom_node_insert_before (
+ WEBKIT_DOM_NODE (paragraph),
+ WEBKIT_DOM_NODE (selection_start_marker),
+ webkit_dom_node_get_first_child (
+ WEBKIT_DOM_NODE (paragraph)),
+ NULL);
+ webkit_dom_node_insert_before (
+ WEBKIT_DOM_NODE (paragraph),
+ WEBKIT_DOM_NODE (selection_end_marker),
+ webkit_dom_node_get_first_child (
+ WEBKIT_DOM_NODE (paragraph)),
+ NULL);
+
+ e_editor_dom_remove_quoting_from_element (paragraph);
+ e_editor_dom_remove_wrapping_from_element (paragraph);
+
+ /* Moving PRE block from citation to body */
+ if (WEBKIT_DOM_IS_HTML_PRE_ELEMENT (block)) {
+ WebKitDOMElement *pre;
+ WebKitDOMNode *child;
+
+ pre = webkit_dom_document_create_element (document, "pre", NULL);
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (
+ WEBKIT_DOM_NODE (paragraph)),
+ WEBKIT_DOM_NODE (pre),
+ WEBKIT_DOM_NODE (paragraph),
+ NULL);
+
+ while ((child = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE
(paragraph))))
+ webkit_dom_node_append_child (WEBKIT_DOM_NODE (pre), child, NULL);
+
+ remove_node (WEBKIT_DOM_NODE (paragraph));
+ paragraph = pre;
+ }
+ }
+
+ if (block)
+ remove_node (block);
+
+ while ((element = webkit_dom_document_get_element_by_id (document, "-x-evo-to-remove")))
+ remove_node (WEBKIT_DOM_NODE (element));
+
+ if (paragraph)
+ remove_node_if_empty (
+ webkit_dom_node_get_next_sibling (
+ WEBKIT_DOM_NODE (paragraph)));
+ }
+
+ if (citation_level > 1) {
+ WebKitDOMNode *parent;
+
+ if (html_mode) {
+ webkit_dom_node_insert_before (
+ block,
+ WEBKIT_DOM_NODE (selection_start_marker),
+ webkit_dom_node_get_first_child (block),
+ NULL);
+ webkit_dom_node_insert_before (
+ block,
+ WEBKIT_DOM_NODE (selection_end_marker),
+ webkit_dom_node_get_first_child (block),
+ NULL);
+
+ }
+
+ e_editor_dom_remove_quoting_from_element (WEBKIT_DOM_ELEMENT (block));
+ e_editor_dom_remove_wrapping_from_element (WEBKIT_DOM_ELEMENT (block));
+
+ parent = webkit_dom_node_get_parent_node (block);
+
+ if (!webkit_dom_node_get_previous_sibling (block)) {
+ /* Currect block is in the beginning of citation, just move it
+ * before the citation where already is */
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (parent),
+ block,
+ parent,
+ NULL);
+ } else if (!webkit_dom_node_get_next_sibling (block)) {
+ /* Currect block is at the end of the citation, just move it
+ * after the citation where already is */
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (parent),
+ block,
+ webkit_dom_node_get_next_sibling (parent),
+ NULL);
+ } else {
+ /* Current block is somewhere in the middle of the citation
+ * so we need to split the citation and insert the block into
+ * the citation that is one level lower */
+ WebKitDOMNode *clone, *child;
+
+ clone = webkit_dom_node_clone_node_with_error (parent, FALSE, NULL);
+
+ /* Move nodes that are after the currect block into the
+ * new blockquote */
+ child = webkit_dom_node_get_next_sibling (block);
+ while (child) {
+ WebKitDOMNode *next = webkit_dom_node_get_next_sibling (child);
+ webkit_dom_node_append_child (clone, child, NULL);
+ child = next;
+ }
+
+ clone = webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (parent),
+ clone,
+ webkit_dom_node_get_next_sibling (parent),
+ NULL);
+
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (parent),
+ block,
+ clone,
+ NULL);
+ }
+
+ e_editor_dom_wrap_and_quote_element (editor_page, WEBKIT_DOM_ELEMENT (block));
+ }
+
+ if (ev) {
+ e_editor_dom_selection_get_coordinates (editor_page,
+ &ev->after.start.x,
+ &ev->after.start.y,
+ &ev->after.end.x,
+ &ev->after.end.y);
+ e_editor_undo_redo_manager_insert_history_event (manager, ev);
+ }
+
+ return success;
+}
+
+static gboolean
+prevent_from_deleting_last_element_in_body (WebKitDOMDocument *document)
+{
+ gboolean ret_val = FALSE;
+ WebKitDOMHTMLElement *body;
+ WebKitDOMNode *node;
+
+ body = webkit_dom_document_get_body (document);
+
+ node = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (body));
+ if (!node || !webkit_dom_node_get_next_sibling (node)) {
+ gchar *content;
+
+ content = webkit_dom_node_get_text_content (WEBKIT_DOM_NODE (body));
+
+ if (!content || !*content)
+ ret_val = TRUE;
+
+ g_free (content);
+
+ if (webkit_dom_element_query_selector (WEBKIT_DOM_ELEMENT (body), "img", NULL))
+ ret_val = FALSE;
+ }
+
+ return ret_val;
+}
+
+static void
+insert_quote_symbols (WebKitDOMDocument *document,
+ WebKitDOMHTMLElement *element,
+ gint quote_level)
+{
+ gchar *quotation;
+ WebKitDOMElement *quote_element;
+
+ if (!WEBKIT_DOM_IS_ELEMENT (element))
+ return;
+
+ quotation = get_quotation_for_level (quote_level);
+
+ quote_element = webkit_dom_document_create_element (document, "span", NULL);
+ element_add_class (quote_element, "-x-evo-quoted");
+
+ webkit_dom_element_set_inner_html (quote_element, quotation, NULL);
+ webkit_dom_node_insert_before (
+ WEBKIT_DOM_NODE (element),
+ WEBKIT_DOM_NODE (quote_element),
+ webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (element)),
+ NULL);
+
+ g_free (quotation);
+}
+
+static void
+quote_node (WebKitDOMDocument *document,
+ WebKitDOMNode *node,
+ gint quote_level)
+{
+ WebKitDOMNode *parent, *next_sibling;
+
+ /* Don't quote when we are not in citation */
+ if (quote_level == 0)
+ return;
+
+ if (WEBKIT_DOM_IS_COMMENT (node))
+ return;
+
+ if (WEBKIT_DOM_IS_ELEMENT (node)) {
+ insert_quote_symbols (document, WEBKIT_DOM_HTML_ELEMENT (node), quote_level);
+ return;
+ }
+
+ next_sibling = webkit_dom_node_get_next_sibling (node);
+
+ /* Skip the BR between first blockquote and pre */
+ if (quote_level == 1 && next_sibling && WEBKIT_DOM_IS_HTML_PRE_ELEMENT (next_sibling))
+ return;
+
+ parent = webkit_dom_node_get_parent_node (node);
+
+ insert_quote_symbols (
+ document, WEBKIT_DOM_HTML_ELEMENT (parent), quote_level);
+}
+
+static void
+insert_quote_symbols_before_node (WebKitDOMDocument *document,
+ WebKitDOMNode *node,
+ gint quote_level,
+ gboolean is_html_node)
+{
+ gboolean skip, wrap_br;
+ gchar *quotation;
+ WebKitDOMElement *element;
+
+ quotation = get_quotation_for_level (quote_level);
+ element = webkit_dom_document_create_element (document, "SPAN", NULL);
+ element_add_class (element, "-x-evo-quoted");
+ webkit_dom_element_set_inner_html (element, quotation, NULL);
+
+ /* Don't insert temporary BR before BR that is used for wrapping */
+ skip = WEBKIT_DOM_IS_HTML_BR_ELEMENT (node);
+ wrap_br = element_has_class (WEBKIT_DOM_ELEMENT (node), "-x-evo-wrap-br");
+ skip = skip && wrap_br;
+
+ if (is_html_node && !skip) {
+ WebKitDOMElement *new_br;
+
+ new_br = webkit_dom_document_create_element (document, "br", NULL);
+ element_add_class (new_br, "-x-evo-temp-br");
+
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (node),
+ WEBKIT_DOM_NODE (new_br),
+ node,
+ NULL);
+ }
+
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (node),
+ WEBKIT_DOM_NODE (element),
+ node,
+ NULL);
+
+ if (is_html_node && !wrap_br)
+ remove_node (node);
+
+ g_free (quotation);
+}
+
+static gboolean
+check_if_suppress_next_node (WebKitDOMNode *node)
+{
+ if (!node)
+ return FALSE;
+
+ if (node && WEBKIT_DOM_IS_ELEMENT (node))
+ if (e_editor_dom_is_selection_position_node (node))
+ if (!webkit_dom_node_get_previous_sibling (node))
+ return FALSE;
+
+ return TRUE;
+}
+
+static void
+quote_br_node (WebKitDOMNode *node,
+ gint quote_level)
+{
+ gchar *quotation, *content;
+
+ quotation = get_quotation_for_level (quote_level);
+
+ content = g_strconcat (
+ "<span class=\"-x-evo-quoted\">",
+ quotation,
+ "</span><br class=\"-x-evo-temp-br\">",
+ NULL);
+
+ webkit_dom_element_set_outer_html (
+ WEBKIT_DOM_ELEMENT (node),
+ content,
+ NULL);
+
+ g_free (content);
+ g_free (quotation);
+}
+
+static void
+quote_plain_text_recursive (WebKitDOMDocument *document,
+ WebKitDOMNode *block,
+ WebKitDOMNode *start_node,
+ gint quote_level)
+{
+ gboolean skip_node = FALSE;
+ gboolean move_next = FALSE;
+ gboolean suppress_next = FALSE;
+ gboolean is_html_node = FALSE;
+ gboolean next = FALSE;
+ WebKitDOMNode *node, *next_sibling, *prev_sibling;
+
+ node = webkit_dom_node_get_first_child (block);
+
+ while (node) {
+ gchar *text_content;
+
+ skip_node = FALSE;
+ move_next = FALSE;
+ is_html_node = FALSE;
+
+ if (WEBKIT_DOM_IS_COMMENT (node) ||
+ WEBKIT_DOM_IS_HTML_META_ELEMENT (node) ||
+ WEBKIT_DOM_IS_HTML_STYLE_ELEMENT (node) ||
+ WEBKIT_DOM_IS_HTML_IMAGE_ELEMENT (node)) {
+
+ move_next = TRUE;
+ goto next_node;
+ }
+
+ prev_sibling = webkit_dom_node_get_previous_sibling (node);
+ next_sibling = webkit_dom_node_get_next_sibling (node);
+
+ if (WEBKIT_DOM_IS_TEXT (node)) {
+ /* Start quoting after we are in blockquote */
+ if (quote_level > 0 && !suppress_next) {
+ /* When quoting text node, we are wrappering it and
+ * afterwards replacing it with that wrapper, thus asking
+ * for next_sibling after quoting will return NULL bacause
+ * that node don't exist anymore */
+ quote_node (document, node, quote_level);
+ node = next_sibling;
+ skip_node = TRUE;
+ }
+
+ goto next_node;
+ }
+
+ if (!(WEBKIT_DOM_IS_ELEMENT (node) || WEBKIT_DOM_IS_HTML_ELEMENT (node)))
+ goto next_node;
+
+ if (e_editor_dom_is_selection_position_node (node)) {
+ /* If there is collapsed selection in the beginning of line
+ * we cannot suppress first text that is after the end of
+ * selection */
+ suppress_next = check_if_suppress_next_node (prev_sibling);
+ if (suppress_next)
+ next = FALSE;
+ move_next = TRUE;
+ goto next_node;
+ }
+
+ if (!WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (node) &&
+ webkit_dom_element_get_child_element_count (WEBKIT_DOM_ELEMENT (node)) != 0)
+ goto with_children;
+
+ /* Even in plain text mode we can have some basic html element
+ * like anchor and others. When Forwaring e-mail as Quoted EMFormat
+ * generates header that contatains <b> tags (bold font).
+ * We have to treat these elements separately to avoid
+ * modifications of theirs inner texts */
+ is_html_node =
+ WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (node) ||
+ element_has_tag (WEBKIT_DOM_ELEMENT (node), "b") ||
+ element_has_tag (WEBKIT_DOM_ELEMENT (node), "i") ||
+ element_has_tag (WEBKIT_DOM_ELEMENT (node), "u") ||
+ element_has_class (WEBKIT_DOM_ELEMENT (node), "Apple-tab-span");
+
+ if (is_html_node) {
+ gboolean wrap_br;
+
+ wrap_br =
+ prev_sibling &&
+ WEBKIT_DOM_IS_HTML_BR_ELEMENT (prev_sibling) &&
+ element_has_class (
+ WEBKIT_DOM_ELEMENT (prev_sibling), "-x-evo-wrap-br");
+
+ if (!prev_sibling || wrap_br) {
+ insert_quote_symbols_before_node (
+ document, node, quote_level, FALSE);
+ if (!prev_sibling && next_sibling && WEBKIT_DOM_IS_TEXT (next_sibling))
+ suppress_next = TRUE;
+ }
+
+ if (WEBKIT_DOM_IS_HTML_BR_ELEMENT (prev_sibling) && !wrap_br)
+ insert_quote_symbols_before_node (
+ document, prev_sibling, quote_level, TRUE);
+
+ move_next = TRUE;
+ goto next_node;
+ }
+
+ /* If element doesn't have children, we can quote it */
+ if (e_editor_dom_node_is_citation_node (node)) {
+ /* Citation with just text inside */
+ quote_node (document, node, quote_level + 1);
+
+ move_next = TRUE;
+ goto next_node;
+ }
+
+ if (!WEBKIT_DOM_IS_HTML_BR_ELEMENT (node)) {
+ if (WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (prev_sibling)) {
+ move_next = TRUE;
+ goto next_node;
+ }
+ goto not_br;
+ } else if (element_has_id (WEBKIT_DOM_ELEMENT (node), "-x-evo-first-br") ||
+ element_has_id (WEBKIT_DOM_ELEMENT (node), "-x-evo-last-br")) {
+ quote_br_node (node, quote_level);
+ node = next_sibling;
+ skip_node = TRUE;
+ goto next_node;
+ }
+
+ if (WEBKIT_DOM_IS_HTML_BR_ELEMENT (prev_sibling)) {
+ quote_br_node (prev_sibling, quote_level);
+ node = next_sibling;
+ skip_node = TRUE;
+ goto next_node;
+ }
+
+ if (!prev_sibling && !next_sibling) {
+ WebKitDOMNode *parent = webkit_dom_node_get_parent_node (node);
+
+ if (WEBKIT_DOM_IS_HTML_DIV_ELEMENT (parent) ||
+ WEBKIT_DOM_IS_HTML_PRE_ELEMENT (parent) ||
+ (WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (parent) &&
+ !e_editor_dom_node_is_citation_node (parent))) {
+ insert_quote_symbols_before_node (
+ document, node, quote_level, FALSE);
+
+ goto next_node;
+ }
+ }
+
+ if (e_editor_dom_node_is_citation_node (prev_sibling)) {
+ insert_quote_symbols_before_node (
+ document, node, quote_level, FALSE);
+ goto next_node;
+ }
+
+ if (WEBKIT_DOM_IS_HTML_BR_ELEMENT (node) &&
+ !next_sibling && WEBKIT_DOM_IS_ELEMENT (prev_sibling) &&
+ e_editor_dom_is_selection_position_node (prev_sibling)) {
+ insert_quote_symbols_before_node (
+ document, node, quote_level, FALSE);
+ goto next_node;
+ }
+
+ if (WEBKIT_DOM_IS_HTML_BR_ELEMENT (node)) {
+ move_next = TRUE;
+ goto next_node;
+ }
+
+ not_br:
+ text_content = webkit_dom_node_get_text_content (node);
+ if (text_content && !*text_content) {
+ g_free (text_content);
+ move_next = TRUE;
+ goto next_node;
+ }
+ g_free (text_content);
+
+ quote_node (document, node, quote_level);
+
+ move_next = TRUE;
+ goto next_node;
+
+ with_children:
+ if (e_editor_dom_node_is_citation_node (node)) {
+ /* Go deeper and increase level */
+ quote_plain_text_recursive (
+ document, node, start_node, quote_level + 1);
+ move_next = TRUE;
+ } else {
+ quote_plain_text_recursive (
+ document, node, start_node, quote_level);
+ move_next = TRUE;
+ }
+ next_node:
+ if (next) {
+ suppress_next = FALSE;
+ next = FALSE;
+ }
+
+ if (suppress_next)
+ next = TRUE;
+
+ if (!skip_node) {
+ /* Move to next node */
+ if (!move_next && webkit_dom_node_has_child_nodes (node)) {
+ node = webkit_dom_node_get_first_child (node);
+ } else if (webkit_dom_node_get_next_sibling (node)) {
+ node = webkit_dom_node_get_next_sibling (node);
+ } else {
+ return;
+ }
+ }
+ }
+}
+
+WebKitDOMElement *
+e_editor_dom_quote_plain_text_element (EEditorPage *editor_page,
+ WebKitDOMElement *element)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMNode *element_clone;
+ WebKitDOMNodeList *list = NULL;
+ gint ii, length, level;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+ document = e_editor_page_get_document (editor_page);
+ element_clone = webkit_dom_node_clone_node_with_error (WEBKIT_DOM_NODE (element), TRUE, NULL);
+ level = e_editor_dom_get_citation_level (WEBKIT_DOM_NODE (element), TRUE);
+
+ /* Remove old quote characters if the exists */
+ list = webkit_dom_element_query_selector_all (
+ WEBKIT_DOM_ELEMENT (element_clone), "span.-x-evo-quoted", NULL);
+ length = webkit_dom_node_list_get_length (list);
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMNode *node = webkit_dom_node_list_item (list, ii);
+ remove_node (node);
+ g_object_unref (node);
+ }
+ g_clear_object (&list);
+
+ webkit_dom_node_normalize (element_clone);
+ quote_plain_text_recursive (
+ document, element_clone, element_clone, level);
+
+ /* Replace old element with one, that is quoted */
+ webkit_dom_node_replace_child (
+ webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element)),
+ element_clone,
+ WEBKIT_DOM_NODE (element),
+ NULL);
+
+ return WEBKIT_DOM_ELEMENT (element_clone);
+}
+
+/*
+ * dom_quote_plain_text:
+ *
+ * Quote text inside citation blockquotes in plain text mode.
+ *
+ * As this function is cloning and replacing all citation blockquotes keep on
+ * mind that any pointers to nodes inside these blockquotes will be invalidated.
+ */
+static WebKitDOMElement *
+dom_quote_plain_text (WebKitDOMDocument *document)
+{
+ WebKitDOMHTMLElement *body;
+ WebKitDOMNode *body_clone;
+ WebKitDOMNamedNodeMap *attributes = NULL;
+ WebKitDOMNodeList *list = NULL;
+ WebKitDOMElement *element;
+ gint ii, length;
+ gulong attributes_length;
+
+ /* Check if the document is already quoted */
+ element = webkit_dom_document_query_selector (
+ document, ".-x-evo-quoted", NULL);
+ if (element)
+ return NULL;
+
+ body = webkit_dom_document_get_body (document);
+ body_clone = webkit_dom_node_clone_node_with_error (WEBKIT_DOM_NODE (body), TRUE, NULL);
+
+ /* Clean unwanted spaces before and after blockquotes */
+ list = webkit_dom_element_query_selector_all (
+ WEBKIT_DOM_ELEMENT (body_clone), "blockquote[type|=cite]", NULL);
+ length = webkit_dom_node_list_get_length (list);
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMNode *blockquote = webkit_dom_node_list_item (list, ii);
+ WebKitDOMNode *prev_sibling = webkit_dom_node_get_previous_sibling (blockquote);
+ WebKitDOMNode *next_sibling = webkit_dom_node_get_next_sibling (blockquote);
+
+ if (prev_sibling && WEBKIT_DOM_IS_HTML_BR_ELEMENT (prev_sibling))
+ remove_node (prev_sibling);
+
+ if (next_sibling && WEBKIT_DOM_IS_HTML_BR_ELEMENT (next_sibling))
+ remove_node (next_sibling);
+
+ if (webkit_dom_node_has_child_nodes (blockquote)) {
+ WebKitDOMNode *child = webkit_dom_node_get_first_child (blockquote);
+ if (WEBKIT_DOM_IS_HTML_BR_ELEMENT (child))
+ remove_node (child);
+ }
+ g_object_unref (blockquote);
+ }
+ g_clear_object (&list);
+
+ webkit_dom_node_normalize (body_clone);
+ quote_plain_text_recursive (document, body_clone, body_clone, 0);
+
+ /* Copy attributes */
+ attributes = webkit_dom_element_get_attributes (WEBKIT_DOM_ELEMENT (body));
+ attributes_length = webkit_dom_named_node_map_get_length (attributes);
+ for (ii = 0; ii < attributes_length; ii++) {
+ gchar *name, *value;
+ WebKitDOMNode *node = webkit_dom_named_node_map_item (attributes, ii);
+
+ name = webkit_dom_node_get_local_name (node);
+ value = webkit_dom_node_get_node_value (node);
+
+ webkit_dom_element_set_attribute (
+ WEBKIT_DOM_ELEMENT (body_clone), name, value, NULL);
+
+ g_object_unref (node);
+ g_free (name);
+ g_free (value);
+ }
+ g_clear_object (&attributes);
+
+ /* Replace old BODY with one, that is quoted */
+ webkit_dom_node_replace_child (
+ webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (body)),
+ body_clone,
+ WEBKIT_DOM_NODE (body),
+ NULL);
+
+ return WEBKIT_DOM_ELEMENT (body_clone);
+}
+
+/*
+ * dom_dequote_plain_text:
+ *
+ * Dequote already quoted plain text in editor.
+ * Editor have to be quoted with e_html_editor_view_quote_plain_text otherwise
+ * it's not working.
+ */
+static void
+dom_dequote_plain_text (WebKitDOMDocument *document)
+{
+ WebKitDOMNodeList *paragraphs = NULL;
+ gint length, ii;
+
+ paragraphs = webkit_dom_document_query_selector_all (
+ document, "blockquote[type=cite]", NULL);
+ length = webkit_dom_node_list_get_length (paragraphs);
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMElement *element;
+
+ element = WEBKIT_DOM_ELEMENT (webkit_dom_node_list_item (paragraphs, ii));
+
+ if (e_editor_dom_node_is_citation_node (WEBKIT_DOM_NODE (element)))
+ e_editor_dom_remove_quoting_from_element (element);
+
+ g_object_unref (element);
+ }
+ g_clear_object (¶graphs);
+}
+
+static gboolean
+create_anchor_for_link (const GMatchInfo *info,
+ GString *res,
+ gpointer data)
+{
+ gboolean link_surrounded, with_nbsp = FALSE;
+ gint offset = 0, truncate_from_end = 0;
+ gint match_start, match_end;
+ gchar *match_with_nbsp, *match_without_nbsp;
+ const gchar *end_of_match = NULL;
+ const gchar *match, *match_extra_characters;
+
+ match_with_nbsp = g_match_info_fetch (info, 1);
+ /* E-mail addresses will be here. */
+ match_without_nbsp = g_match_info_fetch (info, 0);
+
+ if (!match_with_nbsp || (strstr (match_with_nbsp, " ") && !g_str_has_prefix (match_with_nbsp,
" "))) {
+ match = match_without_nbsp;
+ match_extra_characters = match_with_nbsp;
+ g_match_info_fetch_pos (info, 0, &match_start, &match_end);
+ with_nbsp = TRUE;
+ } else {
+ match = match_with_nbsp;
+ match_extra_characters = match_without_nbsp;
+ g_match_info_fetch_pos (info, 1, &match_start, &match_end);
+ }
+
+ if (g_str_has_prefix (match, " "))
+ offset += 6;
+
+ end_of_match = match + match_end - match_start - 1;
+ /* Taken from camel-url-scanner.c */
+ /* URLs are extremely unlikely to end with any punctuation, so
+ * strip any trailing punctuation off from link and put it after
+ * the link. Do the same for any closing double-quotes as well. */
+ while (end_of_match && end_of_match != match && strchr (URL_INVALID_TRAILING_CHARS, *end_of_match)) {
+ truncate_from_end++;
+ end_of_match--;
+ }
+ end_of_match++;
+
+ link_surrounded =
+ g_str_has_suffix (res->str, "<");
+
+ if (link_surrounded) {
+ if (end_of_match && *end_of_match && strlen (match) > strlen (end_of_match) + 3)
+ link_surrounded = link_surrounded && g_str_has_prefix (end_of_match - 3, ">");
+ else
+ link_surrounded = link_surrounded && g_str_has_suffix (match, ">");
+
+ if (link_surrounded) {
+ /* ";" is already counted by code above */
+ truncate_from_end += 3;
+ end_of_match -= 3;
+ }
+ }
+
+ g_string_append (res, "<a href=\"");
+ if (strstr (match, "@") && !strstr (match, "://"))
+ g_string_append (res, "mailto:");
+ g_string_append (res, match + offset);
+ if (truncate_from_end > 0)
+ g_string_truncate (res, res->len - truncate_from_end);
+
+ g_string_append (res, "\">");
+ g_string_append (res, match + offset);
+ if (truncate_from_end > 0)
+ g_string_truncate (res, res->len - truncate_from_end);
+
+ g_string_append (res, "</a>");
+
+ if (truncate_from_end > 0)
+ g_string_append (res, end_of_match);
+
+ if (!with_nbsp && match_extra_characters)
+ g_string_append (res, match_extra_characters + (match_end - match_start));
+
+ g_free (match_with_nbsp);
+ g_free (match_without_nbsp);
+
+ return FALSE;
+}
+
+static gboolean
+replace_to_nbsp (const GMatchInfo *info,
+ GString *res)
+{
+ gchar *match;
+ gint ii = 0;
+
+ match = g_match_info_fetch (info, 0);
+
+ while (match[ii] != '\0') {
+ if (match[ii] == ' ') {
+ /* Alone spaces or spaces before/after tabulator. */
+ g_string_append (res, " ");
+ } else if (match[ii] == '\t') {
+ /* Replace tabs with their WebKit HTML representation. */
+ g_string_append (res, "<span class=\"Apple-tab-span\"
style=\"white-space:pre\">\t</span>");
+ }
+
+ ii++;
+ }
+
+ g_free (match);
+
+ return FALSE;
+}
+
+static gboolean
+surround_links_with_anchor (const gchar *text)
+{
+ return (strstr (text, "http") || strstr (text, "ftp") ||
+ strstr (text, "www") || strstr (text, "@"));
+}
+
+static void
+append_new_block (WebKitDOMElement *parent,
+ WebKitDOMElement **block)
+{
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (parent),
+ WEBKIT_DOM_NODE (*block),
+ NULL);
+
+ *block = NULL;
+}
+
+static WebKitDOMElement *
+create_and_append_new_block (EEditorPage *editor_page,
+ WebKitDOMElement *parent,
+ WebKitDOMElement *block_template,
+ const gchar *content)
+{
+ WebKitDOMElement *block;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+ block = WEBKIT_DOM_ELEMENT (webkit_dom_node_clone_node_with_error (
+ WEBKIT_DOM_NODE (block_template), FALSE, NULL));
+
+ webkit_dom_element_set_inner_html (block, content, NULL);
+
+ append_new_block (parent, &block);
+
+ return block;
+}
+
+static void
+append_citation_mark (WebKitDOMDocument *document,
+ WebKitDOMElement *parent,
+ const gchar *citation_mark_text)
+{
+ WebKitDOMText *text;
+
+ text = webkit_dom_document_create_text_node (document, citation_mark_text);
+
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (parent),
+ WEBKIT_DOM_NODE (text),
+ NULL);
+}
+
+static void
+replace_selection_markers (gchar **text)
+{
+ if (!text)
+ return;
+
+ if (strstr (*text, "##SELECTION_START##")) {
+ GString *tmp;
+
+ tmp = e_str_replace_string (
+ *text,
+ "##SELECTION_START##",
+ "<span id=\"-x-evo-selection-start-marker\"></span>");
+
+ g_free (*text);
+ *text = g_string_free (tmp, FALSE);
+ }
+
+ if (strstr (*text, "##SELECTION_END##")) {
+ GString *tmp;
+
+ tmp = e_str_replace_string (
+ *text,
+ "##SELECTION_END##",
+ "<span id=\"-x-evo-selection-end-marker\"></span>");
+
+ g_free (*text);
+ *text = g_string_free (tmp, FALSE);
+ }
+}
+
+static GString *
+remove_new_lines_around_citations (const gchar *input)
+{
+ GString *str = NULL;
+ const gchar *p, *next;
+
+ str = g_string_new ("");
+
+ /* Remove the new lines around citations:
+ * Replace <br><br>##CITATION_START## with <br>##CITATION_START##
+ * Replace ##CITATION_START##<br><br> with ##CITATION_START##<br>
+ * Replace <br>##CITATION_END## with ##CITATION_END## */
+ p = input;
+ while (next = strstr (p, "##CITATION_"), next) {
+ gchar citation_type = 0;
+
+ if (p < next)
+ g_string_append_len (str, p, next - p);
+
+ if (next + 11)
+ citation_type = next[11];
+ /* ##CITATION_START## */
+ if (citation_type == 'S') {
+ if (g_str_has_suffix (str->str, "<br><br>") ||
+ g_str_has_suffix (str->str, "<br><br>"))
+ g_string_truncate (str, str->len - 4);
+
+ if (g_str_has_prefix (next + 11, "START##<br><br>")) {
+ g_string_append (str, "##CITATION_START##<br>");
+ p = next + 26;
+ continue;
+ }
+ } else if (citation_type == 'E') {
+ if (g_str_has_suffix (str->str, "<br>"))
+ g_string_truncate (str, str->len - 4);
+ }
+
+ g_string_append (str, "##CITATION_");
+
+ p = next + 11;
+ }
+
+ g_string_append (str, p);
+
+ return str;
+}
+
+static GString *
+replace_citation_marks_to_citations (const gchar *input)
+{
+ GString *str = NULL;
+ const gchar *p, *next;
+
+ str = g_string_new ("");
+
+ /* Replaces text markers with actual HTML blockquotes */
+ p = input;
+ while (next = strstr (p, "##CITATION_"), next) {
+ gchar citation_type = 0;
+
+ if (p < next)
+ g_string_append_len (str, p, next - p);
+
+ if (next + 11)
+ citation_type = next[11];
+ /* ##CITATION_START## */
+ if (citation_type == 'S') {
+ g_string_append (str, "<blockquote type=\"cite\">");
+ p = next + 18;
+ } else if (citation_type == 'E') {
+ g_string_append (str, "</blockquote>");
+ p = next + 16;
+ } else
+ p = next + 11;
+ }
+
+ g_string_append (str, p);
+
+ return str;
+}
+
+/* This parses the HTML code (that contains just text, and BR elements)
+ * into blocks.
+ * HTML code in that format we can get by taking innerText from some element,
+ * setting it to another one and finally getting innerHTML from it */
+static void
+parse_html_into_blocks (EEditorPage *editor_page,
+ WebKitDOMElement *parent,
+ WebKitDOMElement *passed_block_template,
+ const gchar *input)
+{
+ gboolean has_citation = FALSE, processing_last = FALSE;
+ const gchar *prev_br, *next_br;
+ GString *html = NULL;
+ GRegex *regex_nbsp = NULL, *regex_link = NULL, *regex_email = NULL;
+ WebKitDOMDocument *document;
+ WebKitDOMElement *block_template = passed_block_template;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+ webkit_dom_element_set_inner_html (parent, "", NULL);
+
+ if (!block_template) {
+ gboolean use_paragraphs;
+ GSettings *settings;
+
+ settings = e_util_ref_settings ("org.gnome.evolution.mail");
+
+ use_paragraphs = g_settings_get_boolean (
+ settings, "composer-wrap-quoted-text-in-replies");
+
+ if (use_paragraphs)
+ block_template = e_editor_dom_get_paragraph_element (editor_page, -1, 0);
+ else
+ block_template = webkit_dom_document_create_element (document, "pre", NULL);
+
+ g_object_unref (settings);
+ }
+
+ /* Replace the tabulators with SPAN elements that corresponds to them.
+ * If not inserting the content into the PRE element also replace single
+ * spaces on the beginning of line, 2+ spaces and with non breaking
+ * spaces. */
+ if (WEBKIT_DOM_IS_HTML_PRE_ELEMENT (block_template))
+ regex_nbsp = g_regex_new ("\x9", 0, 0, NULL);
+ else
+ regex_nbsp = g_regex_new ("^\\s{1}|\\s{2,}|\x9|\\s$", 0, 0, NULL);
+
+
+ html = remove_new_lines_around_citations (input);
+
+ prev_br = html->str;
+ next_br = strstr (prev_br, "<br>");
+ processing_last = !next_br;
+
+ while (next_br || processing_last) {
+ const gchar *citation_start = NULL, *citation_end = NULL;
+ const gchar *rest = NULL, *with_br = NULL;
+ gchar *to_process = NULL, *to_insert = NULL;
+ guint to_insert_start = 0, to_insert_end = 0;
+
+ if (!next_br) {
+ to_process = g_strdup (prev_br);
+ processing_last = TRUE;
+ } else if ((to_process = g_utf8_substring (prev_br, 0, g_utf8_pointer_to_offset (prev_br,
next_br))) && !*to_process && !processing_last) {
+ g_free (to_process);
+ to_process = g_strdup (next_br);
+ processing_last = TRUE;
+ }
+ to_insert_end = g_utf8_strlen (to_process, -1);
+
+ if ((with_br = strstr (to_process, "<br>"))) {
+ if (with_br == to_process)
+ to_insert_start += 4;
+ }
+ if ((citation_start = strstr (to_process, "##CITATION_START"))) {
+ if (with_br && citation_start == with_br + 4)
+ to_insert_start += 18; /* + ## */
+ else
+ to_insert_end -= 18; /* + ## */
+ has_citation = TRUE;
+ }
+ if ((citation_end = strstr (to_process, "##CITATION_END")))
+ to_insert_end -= 16; /* + ## */
+
+ /* First BR */
+ if (with_br && prev_br == html->str)
+ create_and_append_new_block (
+ editor_page, parent, block_template, "<br id=\"-x-evo-first-br\">");
+
+ if (with_br && citation_start && citation_start == with_br + 4) {
+ create_and_append_new_block (
+ editor_page, parent, block_template, "<br>");
+
+ append_citation_mark (document, parent, "##CITATION_START##");
+ }
+
+ if ((to_insert = g_utf8_substring (to_process, to_insert_start, to_insert_end)) &&
*to_insert) {
+ gboolean empty = FALSE;
+ gchar *truncated = g_strdup (to_insert);
+ gchar *rest_to_insert;
+
+ empty = !*truncated && strlen (to_insert) > 0;
+
+ rest_to_insert = g_regex_replace_eval (
+ regex_nbsp,
+ empty ? rest : truncated,
+ -1,
+ 0,
+ 0,
+ (GRegexEvalCallback) replace_to_nbsp,
+ NULL,
+ NULL);
+ g_free (truncated);
+
+ replace_selection_markers (&rest_to_insert);
+
+ if (surround_links_with_anchor (rest_to_insert)) {
+ gboolean is_email_address =
+ strstr (rest_to_insert, "@") &&
+ !strstr (rest_to_insert, "://");
+
+ if (is_email_address && !regex_email)
+ regex_email = g_regex_new (E_MAIL_PATTERN, 0, 0, NULL);
+ if (!is_email_address && !regex_link)
+ regex_link = g_regex_new (URL_PATTERN, 0, 0, NULL);
+
+ truncated = g_regex_replace_eval (
+ is_email_address ? regex_email : regex_link,
+ rest_to_insert,
+ -1,
+ 0,
+ G_REGEX_MATCH_NOTEMPTY,
+ create_anchor_for_link,
+ NULL,
+ NULL);
+
+ g_free (rest_to_insert);
+ rest_to_insert = truncated;
+ }
+
+ create_and_append_new_block (
+ editor_page, parent, block_template, rest_to_insert);
+
+ g_free (rest_to_insert);
+ } else if (to_insert && !citation_start)
+ create_and_append_new_block (
+ editor_page, parent, block_template, "<br>");
+
+ g_free (to_insert);
+
+ if (with_br && citation_start && citation_start != with_br + 4)
+ append_citation_mark (document, parent, "##CITATION_START##");
+
+ if (citation_end)
+ append_citation_mark (document, parent, "##CITATION_END##");
+
+ g_free (to_process);
+
+ prev_br = next_br;
+ next_br = (prev_br && *prev_br) ? strstr (prev_br + 1, "<br>") : NULL;
+ if (!next_br && !processing_last) {
+ if (!prev_br)
+ break;
+
+ if (g_utf8_strlen (prev_br, -1) > 4) {
+ next_br = prev_br;
+ } else {
+ WebKitDOMNode *child;
+
+ child = webkit_dom_node_get_last_child (
+ WEBKIT_DOM_NODE (parent));
+ if (child) {
+ child = webkit_dom_node_get_first_child (child);
+ if (child && WEBKIT_DOM_IS_HTML_BR_ELEMENT (child)) {
+ /* If the processed HTML contained just
+ * the BR don't overwrite its id. */
+ if (!element_has_id (WEBKIT_DOM_ELEMENT (child),
"-x-evo-first-br"))
+ webkit_dom_element_set_id (
+ WEBKIT_DOM_ELEMENT (child),
+ "-x-evo-last-br");
+ } else if (!webkit_dom_document_query_selector (document,
".-x-evo-signature-wrapper", NULL)) {
+ /* FIXME WK2 - the signature could not be inserted at this
point
+ * this is the reason why there is an extra NL on the very
end of
+ * quoted text in reply. */
+ create_and_append_new_block (
+ editor_page, parent, block_template, "<br>");
+ }
+ } else {
+ create_and_append_new_block (
+ editor_page, parent, block_template, "<br>");
+ }
+ break;
+ }
+ processing_last = TRUE;
+ } else if (processing_last && !prev_br && !next_br) {
+ break;
+ }
+ }
+
+ if (has_citation) {
+ gchar *inner_html;
+ GString *parsed;
+
+ /* Replace text markers with actual HTML blockquotes */
+ inner_html = webkit_dom_element_get_inner_html (parent);
+ parsed = replace_citation_marks_to_citations (inner_html);
+ webkit_dom_element_set_inner_html (parent, parsed->str, NULL);
+
+ g_free (inner_html);
+ g_string_free (parsed, TRUE);
+ }
+
+ g_string_free (html, TRUE);
+
+ if (regex_email != NULL)
+ g_regex_unref (regex_email);
+ if (regex_link != NULL)
+ g_regex_unref (regex_link);
+ g_regex_unref (regex_nbsp);
+}
+
+void
+e_editor_dom_quote_and_insert_text_into_selection (EEditorPage *editor_page,
+ const gchar *text,
+ gboolean is_html)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *blockquote, *element, *selection_start;
+ WebKitDOMNode *node;
+ EEditorHistoryEvent *ev = NULL;
+ EEditorUndoRedoManager *manager;
+ gchar *inner_html;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ if (!text || !*text)
+ return;
+
+ document = e_editor_page_get_document (editor_page);
+
+ if (is_html) {
+ element = webkit_dom_document_create_element (document, "div", NULL);
+
+ if (strstr (text, "\n")) {
+ GRegex *regex;
+ gchar *tmp;
+
+ /* Strip new lines between tags to avoid unwanted line breaks. */
+ regex = g_regex_new ("\\>[\\s]+\\<", 0, 0, NULL);
+ tmp = g_regex_replace (regex, text, -1, 0, "> <", 0, NULL);
+ webkit_dom_element_set_inner_html (element, tmp, NULL);
+ g_free (tmp);
+ g_regex_unref (regex);
+ } else {
+ webkit_dom_element_set_inner_html (element, text, NULL);
+ }
+ } else {
+ /* This is a trick to escape any HTML characters (like <, > or &).
+ * <textarea> automatically replaces all these unsafe characters
+ * by <, > etc. */
+ element = webkit_dom_document_create_element (document, "textarea", NULL);
+ webkit_dom_html_element_set_inner_text (WEBKIT_DOM_HTML_ELEMENT (element), text, NULL);
+ }
+
+ inner_html = webkit_dom_element_get_inner_html (element);
+
+ e_editor_dom_selection_save (editor_page);
+
+ manager = e_editor_page_get_undo_redo_manager (editor_page);
+ if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+ ev = g_new0 (EEditorHistoryEvent, 1);
+ ev->type = HISTORY_PASTE_QUOTED;
+
+ e_editor_dom_selection_get_coordinates (editor_page,
+ &ev->before.start.x,
+ &ev->before.start.y,
+ &ev->before.end.x,
+ &ev->before.end.y);
+
+ ev->data.string.from = NULL;
+ ev->data.string.to = g_strdup (text);
+ }
+
+ blockquote = webkit_dom_document_create_element (document, "blockquote", NULL);
+ webkit_dom_element_set_attribute (blockquote, "type", "cite", NULL);
+
+ selection_start = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-start-marker");
+ node = webkit_dom_node_get_previous_sibling (WEBKIT_DOM_NODE (selection_start));
+ /* Check if block is empty. If so, replace it otherwise insert the quoted
+ * content after current block. */
+ if (!node || WEBKIT_DOM_IS_HTML_BR_ELEMENT (node)) {
+ node = webkit_dom_node_get_next_sibling (
+ WEBKIT_DOM_NODE (selection_start));
+ node = webkit_dom_node_get_next_sibling (node);
+ if (!node || WEBKIT_DOM_IS_HTML_BR_ELEMENT (node)) {
+ webkit_dom_node_replace_child (
+ webkit_dom_node_get_parent_node (
+ webkit_dom_node_get_parent_node (
+ WEBKIT_DOM_NODE (selection_start))),
+ WEBKIT_DOM_NODE (blockquote),
+ webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (selection_start)),
+ NULL);
+ }
+ } else {
+ webkit_dom_node_insert_before (
+ WEBKIT_DOM_NODE (webkit_dom_document_get_body (document)),
+ WEBKIT_DOM_NODE (blockquote),
+ webkit_dom_node_get_next_sibling (
+ webkit_dom_node_get_parent_node (
+ WEBKIT_DOM_NODE (selection_start))),
+ NULL);
+ }
+
+ parse_html_into_blocks (editor_page, blockquote, NULL, inner_html);
+
+ if (e_editor_page_get_html_mode (editor_page)) {
+ node = webkit_dom_node_get_last_child (WEBKIT_DOM_NODE (blockquote));
+ } else {
+ gint word_wrap_length;
+
+ word_wrap_length = e_editor_page_get_word_wrap_length (editor_page);
+ node = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (blockquote));
+ while (node) {
+ WebKitDOMNode *next_sibling;
+
+ node = WEBKIT_DOM_NODE (e_editor_dom_wrap_paragraph_length (editor_page,
WEBKIT_DOM_ELEMENT (node), word_wrap_length - 2));
+
+ webkit_dom_node_normalize (node);
+ e_editor_dom_quote_plain_text_element_after_wrapping (editor_page, WEBKIT_DOM_ELEMENT
(node), 1);
+
+ next_sibling = webkit_dom_node_get_next_sibling (node);
+ if (!next_sibling)
+ break;
+
+ node = next_sibling;
+ }
+ }
+
+ dom_add_selection_markers_into_element_end (
+ document, WEBKIT_DOM_ELEMENT (node), NULL, NULL);
+
+ e_editor_dom_selection_restore (editor_page);
+
+ if (ev) {
+ e_editor_dom_selection_get_coordinates (editor_page,
+ &ev->after.start.x,
+ &ev->after.start.y,
+ &ev->after.end.x,
+ &ev->after.end.y);
+ e_editor_undo_redo_manager_insert_history_event (manager, ev);
+ }
+
+ e_editor_dom_force_spell_check_in_viewport (editor_page);
+ e_editor_page_emit_content_changed (editor_page);
+
+ g_free (inner_html);
+}
+
+static void
+mark_citation (WebKitDOMElement *citation)
+{
+ webkit_dom_html_element_insert_adjacent_text (
+ WEBKIT_DOM_HTML_ELEMENT (citation),
+ "beforebegin",
+ "##CITATION_START##",
+ NULL);
+
+ webkit_dom_html_element_insert_adjacent_text (
+ WEBKIT_DOM_HTML_ELEMENT (citation),
+ "afterend",
+ "##CITATION_END##",
+ NULL);
+
+ element_add_class (citation, "marked");
+}
+
+static gint
+create_text_markers_for_citations_in_element (WebKitDOMElement *element)
+{
+ gint count = 0;
+ WebKitDOMElement *citation;
+
+ citation = webkit_dom_element_query_selector (
+ element, "blockquote[type=cite]:not(.marked)", NULL);
+
+ while (citation) {
+ mark_citation (citation);
+ count ++;
+
+ citation = webkit_dom_element_query_selector (
+ element, "blockquote[type=cite]:not(.marked)", NULL);
+ }
+
+ return count;
+}
+
+static void
+create_text_markers_for_selection_in_element (WebKitDOMElement *element)
+{
+ WebKitDOMElement *selection_marker;
+
+ selection_marker = webkit_dom_element_query_selector (
+ element, "#-x-evo-selection-start-marker", NULL);
+ if (selection_marker)
+ webkit_dom_html_element_insert_adjacent_text (
+ WEBKIT_DOM_HTML_ELEMENT (selection_marker),
+ "afterend",
+ "##SELECTION_START##",
+ NULL);
+
+ selection_marker = webkit_dom_element_query_selector (
+ element, "#-x-evo-selection-end-marker", NULL);
+ if (selection_marker)
+ webkit_dom_html_element_insert_adjacent_text (
+ WEBKIT_DOM_HTML_ELEMENT (selection_marker),
+ "afterend",
+ "##SELECTION_END##",
+ NULL);
+}
+
+static void
+quote_plain_text_elements_after_wrapping_in_document (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMNodeList *list = NULL;
+ gint length, ii;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+
+ /* Also quote the PRE elements as well. */
+ list = webkit_dom_document_query_selector_all (
+ document, "blockquote[type=cite] > p[data-evo-paragraph], blockquote[type=cite] > pre", NULL);
+
+ length = webkit_dom_node_list_get_length (list);
+ for (ii = 0; ii < length; ii++) {
+ gint citation_level;
+ WebKitDOMNode *child;
+
+ child = webkit_dom_node_list_item (list, ii);
+ citation_level = e_editor_dom_get_citation_level (child, TRUE);
+ e_editor_dom_quote_plain_text_element_after_wrapping (editor_page, WEBKIT_DOM_ELEMENT
(child), citation_level);
+ g_object_unref (child);
+ }
+ g_clear_object (&list);
+}
+
+static void
+clear_attributes (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMNamedNodeMap *attributes = NULL;
+ WebKitDOMHTMLElement *body;
+ WebKitDOMHTMLHeadElement *head;
+ WebKitDOMElement *document_element;
+ gint length, ii;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+ body = webkit_dom_document_get_body (document);
+ head = webkit_dom_document_get_head (document);
+ document_element = webkit_dom_document_get_document_element (document);
+
+ /* Remove all attributes from HTML element */
+ attributes = webkit_dom_element_get_attributes (document_element);
+ length = webkit_dom_named_node_map_get_length (attributes);
+ for (ii = length - 1; ii >= 0; ii--) {
+ WebKitDOMNode *node = webkit_dom_named_node_map_item (attributes, ii);
+
+ webkit_dom_element_remove_attribute_node (
+ document_element, WEBKIT_DOM_ATTR (node), NULL);
+ g_object_unref (node);
+ }
+ g_clear_object (&attributes);
+
+ /* Remove everything from HEAD element */
+ while (webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (head)))
+ remove_node (webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (head)));
+
+ /* Make the quote marks non-selectable. */
+ e_editor_dom_disable_quote_marks_select (editor_page);
+
+ /* Remove non Evolution attributes from BODY element */
+ attributes = webkit_dom_element_get_attributes (WEBKIT_DOM_ELEMENT (body));
+ length = webkit_dom_named_node_map_get_length (attributes);
+ for (ii = length - 1; ii >= 0; ii--) {
+ gchar *name;
+ WebKitDOMNode *node = webkit_dom_named_node_map_item (attributes, ii);
+
+ name = webkit_dom_node_get_local_name (node);
+
+ if (!g_str_has_prefix (name, "data-") && (g_strcmp0 (name, "spellcheck") != 0))
+ webkit_dom_element_remove_attribute_node (
+ WEBKIT_DOM_ELEMENT (body),
+ WEBKIT_DOM_ATTR (node),
+ NULL);
+
+ g_object_unref (node);
+ g_free (name);
+ }
+ g_clear_object (&attributes);
+}
+
+static void
+body_compositionstart_event_cb (WebKitDOMElement *element,
+ WebKitDOMUIEvent *event,
+ EEditorPage *editor_page)
+{
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ e_editor_page_set_composition_in_progress (editor_page, TRUE);
+ e_editor_dom_remove_input_event_listener_from_body (editor_page);
+}
+
+static void
+body_compositionend_event_cb (WebKitDOMElement *element,
+ WebKitDOMUIEvent *event,
+ EEditorPage *editor_page)
+{
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ e_editor_page_set_composition_in_progress (editor_page, FALSE);
+ e_editor_dom_remove_input_event_listener_from_body (editor_page);
+}
+
+static void
+register_html_events_handlers (EEditorPage *editor_page,
+ WebKitDOMHTMLElement *body)
+{
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ webkit_dom_event_target_add_event_listener (
+ WEBKIT_DOM_EVENT_TARGET (body),
+ "keydown",
+ G_CALLBACK (body_keydown_event_cb),
+ FALSE,
+ editor_page);
+
+ webkit_dom_event_target_add_event_listener (
+ WEBKIT_DOM_EVENT_TARGET (body),
+ "keypress",
+ G_CALLBACK (body_keypress_event_cb),
+ FALSE,
+ editor_page);
+
+ webkit_dom_event_target_add_event_listener (
+ WEBKIT_DOM_EVENT_TARGET (body),
+ "keyup",
+ G_CALLBACK (body_keyup_event_cb),
+ FALSE,
+ editor_page);
+
+ webkit_dom_event_target_add_event_listener (
+ WEBKIT_DOM_EVENT_TARGET (body),
+ "compositionstart",
+ G_CALLBACK (body_compositionstart_event_cb),
+ FALSE,
+ editor_page);
+
+ webkit_dom_event_target_add_event_listener (
+ WEBKIT_DOM_EVENT_TARGET (body),
+ "compositionend",
+ G_CALLBACK (body_compositionend_event_cb),
+ FALSE,
+ editor_page);
+}
+
+void
+e_editor_dom_convert_content (EEditorPage *editor_page,
+ const gchar *preferred_text)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *paragraph, *content_wrapper, *top_signature;
+ WebKitDOMElement *cite_body, *signature, *wrapper;
+ WebKitDOMHTMLElement *body;
+ WebKitDOMNodeList *list = NULL;
+ WebKitDOMNode *node;
+ WebKitDOMDOMWindow *dom_window = NULL;
+ gboolean start_bottom, empty = FALSE;
+ gchar *inner_html;
+ gint ii, length;
+ GSettings *settings;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+ settings = e_util_ref_settings ("org.gnome.evolution.mail");
+ start_bottom = g_settings_get_boolean (settings, "composer-reply-start-bottom");
+ g_object_unref (settings);
+
+ dom_window = webkit_dom_document_get_default_view (document);
+ body = webkit_dom_document_get_body (document);
+ /* Wrapper that will represent the new body. */
+ wrapper = webkit_dom_document_create_element (document, "div", NULL);
+
+ cite_body = webkit_dom_document_query_selector (
+ document, "span.-x-evo-cite-body", NULL);
+
+ /* content_wrapper when the processed text will be placed. */
+ content_wrapper = webkit_dom_document_create_element (
+ document, cite_body ? "blockquote" : "div", NULL);
+ if (cite_body) {
+ webkit_dom_element_set_attribute (content_wrapper, "type", "cite", NULL);
+ webkit_dom_element_set_attribute (content_wrapper, "id", "-x-evo-main-cite", NULL);
+ }
+
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (wrapper), WEBKIT_DOM_NODE (content_wrapper), NULL);
+
+ /* Remove all previously inserted paragraphs. */
+ list = webkit_dom_document_query_selector_all (
+ document, "p[data-evo-paragraph]:not([data-headers])", NULL);
+ length = webkit_dom_node_list_get_length (list);
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMNode *node = webkit_dom_node_list_item (list, ii);
+ remove_node (node);
+ g_object_unref (node);
+ }
+ g_clear_object (&list);
+
+ /* Insert the paragraph where the caret will be. */
+ paragraph = e_editor_dom_prepare_paragraph (editor_page, TRUE);
+ webkit_dom_element_set_id (paragraph, "-x-evo-input-start");
+ webkit_dom_node_insert_before (
+ WEBKIT_DOM_NODE (wrapper),
+ WEBKIT_DOM_NODE (paragraph),
+ start_bottom ?
+ webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (content_wrapper)) :
+ WEBKIT_DOM_NODE (content_wrapper),
+ NULL);
+
+ /* Insert signature (if presented) to the right position. */
+ top_signature = webkit_dom_document_query_selector (
+ document, ".-x-evo-top-signature", NULL);
+ signature = webkit_dom_document_query_selector (
+ document, ".-x-evo-signature-wrapper", NULL);
+ if (signature) {
+ if (top_signature) {
+ WebKitDOMElement *spacer;
+
+ webkit_dom_node_insert_before (
+ WEBKIT_DOM_NODE (wrapper),
+ WEBKIT_DOM_NODE (signature),
+ start_bottom ?
+ WEBKIT_DOM_NODE (content_wrapper) :
+ webkit_dom_node_get_next_sibling (
+ WEBKIT_DOM_NODE (paragraph)),
+ NULL);
+ /* Insert NL after the signature */
+ spacer = e_editor_dom_prepare_paragraph (editor_page, FALSE);
+ element_add_class (spacer, "-x-evo-top-signature-spacer");
+ webkit_dom_node_insert_before (
+ WEBKIT_DOM_NODE (wrapper),
+ WEBKIT_DOM_NODE (spacer),
+ webkit_dom_node_get_next_sibling (
+ WEBKIT_DOM_NODE (signature)),
+ NULL);
+ } else {
+ webkit_dom_node_insert_before (
+ WEBKIT_DOM_NODE (wrapper),
+ WEBKIT_DOM_NODE (signature),
+ webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (
+ start_bottom ? paragraph : content_wrapper)),
+ NULL);
+ }
+ }
+
+ /* Move credits to the body */
+ list = webkit_dom_document_query_selector_all (
+ document, "span.-x-evo-to-body[data-credits]", NULL);
+ length = webkit_dom_node_list_get_length (list);
+ for (ii = 0; ii < length; ii++) {
+ char *credits;
+ WebKitDOMElement *element;
+ WebKitDOMNode *node = webkit_dom_node_list_item (list, ii);
+
+ element = e_editor_dom_get_paragraph_element (editor_page, -1, 0);
+ credits = webkit_dom_element_get_attribute (WEBKIT_DOM_ELEMENT (node), "data-credits");
+ if (credits)
+ webkit_dom_html_element_set_inner_text (WEBKIT_DOM_HTML_ELEMENT (element), credits,
NULL);
+ g_free (credits);
+
+ webkit_dom_node_insert_before (
+ WEBKIT_DOM_NODE (wrapper),
+ WEBKIT_DOM_NODE (element),
+ WEBKIT_DOM_NODE (content_wrapper),
+ NULL);
+
+ remove_node (node);
+ g_object_unref (node);
+ }
+ g_clear_object (&list);
+
+ /* Move headers to body */
+ list = webkit_dom_document_query_selector_all (
+ document, "div[data-headers]", NULL);
+ length = webkit_dom_node_list_get_length (list);
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMNode *node;
+
+ node = webkit_dom_node_list_item (list, ii);
+ webkit_dom_element_remove_attribute (
+ WEBKIT_DOM_ELEMENT (node), "data-headers");
+ e_editor_dom_set_paragraph_style (editor_page, WEBKIT_DOM_ELEMENT (node), -1, 0, NULL);
+ webkit_dom_node_insert_before (
+ WEBKIT_DOM_NODE (wrapper),
+ node,
+ WEBKIT_DOM_NODE (content_wrapper),
+ NULL);
+
+ g_object_unref (node);
+ }
+ g_clear_object (&list);
+
+ repair_gmail_blockquotes (document);
+ remove_thunderbird_signature (document);
+ create_text_markers_for_citations_in_element (WEBKIT_DOM_ELEMENT (body));
+
+ if (preferred_text && *preferred_text)
+ webkit_dom_html_element_set_inner_text (
+ WEBKIT_DOM_HTML_ELEMENT (content_wrapper), preferred_text, NULL);
+ else {
+ gchar *inner_text;
+
+ inner_text = webkit_dom_html_element_get_inner_text (body);
+ webkit_dom_html_element_set_inner_text (
+ WEBKIT_DOM_HTML_ELEMENT (content_wrapper), inner_text, NULL);
+
+ g_free (inner_text);
+ }
+
+ inner_html = webkit_dom_element_get_inner_html (content_wrapper);
+
+ /* Replace the old body with the new one. */
+ node = webkit_dom_node_clone_node_with_error (WEBKIT_DOM_NODE (body), FALSE, NULL);
+ webkit_dom_node_replace_child (
+ webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (body)),
+ node,
+ WEBKIT_DOM_NODE (body),
+ NULL);
+ body = WEBKIT_DOM_HTML_ELEMENT (node);
+
+ /* Copy all to nodes to the new body. */
+ while ((node = webkit_dom_node_get_last_child (WEBKIT_DOM_NODE (wrapper)))) {
+ webkit_dom_node_insert_before (
+ WEBKIT_DOM_NODE (body),
+ WEBKIT_DOM_NODE (node),
+ webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (body)),
+ NULL);
+ }
+ remove_node (WEBKIT_DOM_NODE (wrapper));
+
+ if (inner_html && !*inner_html)
+ empty = TRUE;
+
+ length = webkit_dom_element_get_child_element_count (WEBKIT_DOM_ELEMENT (body));
+ if (length <= 1) {
+ empty = TRUE;
+ if (length == 1) {
+ WebKitDOMNode *child;
+
+ child = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (body));
+ empty = child && WEBKIT_DOM_IS_HTML_BR_ELEMENT (child);
+ }
+ }
+
+ if (preferred_text && *preferred_text)
+ empty = FALSE;
+
+ if (!empty)
+ parse_html_into_blocks (editor_page, content_wrapper, NULL, inner_html);
+ else
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (content_wrapper),
+ WEBKIT_DOM_NODE (e_editor_dom_prepare_paragraph (editor_page, FALSE)),
+ NULL);
+
+ if (!cite_body) {
+ if (!empty) {
+ WebKitDOMNode *child;
+
+ while ((child = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (content_wrapper))))
{
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (content_wrapper)),
+ child,
+ WEBKIT_DOM_NODE (content_wrapper),
+ NULL);
+ }
+ }
+
+ remove_node (WEBKIT_DOM_NODE (content_wrapper));
+ }
+
+ /* If not editing a message, don't add any new block and just place
+ * the caret in the beginning of content. We want to have the same
+ * behaviour when editing message as new or we start replying on top. */
+ if (!signature && !start_bottom) {
+ WebKitDOMNode *child;
+
+ remove_node (WEBKIT_DOM_NODE (paragraph));
+ child = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (body));
+ if (child)
+ dom_add_selection_markers_into_element_start (
+ document, WEBKIT_DOM_ELEMENT (child), NULL, NULL);
+ }
+
+ if ((paragraph = webkit_dom_document_get_element_by_id (document, "-x-evo-last-br")))
+ webkit_dom_element_remove_attribute (paragraph, "id");
+ if ((paragraph = webkit_dom_document_get_element_by_id (document, "-x-evo-first-br")))
+ webkit_dom_element_remove_attribute (paragraph, "id");
+
+ e_editor_dom_merge_siblings_if_necessary (editor_page, NULL);
+
+ if (!e_editor_page_get_html_mode (editor_page)) {
+ e_editor_dom_wrap_paragraphs_in_document (editor_page);
+
+ quote_plain_text_elements_after_wrapping_in_document (editor_page);
+ }
+
+ clear_attributes (editor_page);
+
+ e_editor_dom_selection_restore (editor_page);
+ e_editor_dom_force_spell_check_in_viewport (editor_page);
+
+ /* Register on input event that is called when the content (body) is modified */
+ webkit_dom_event_target_add_event_listener (
+ WEBKIT_DOM_EVENT_TARGET (body),
+ "input",
+ G_CALLBACK (body_input_event_cb),
+ FALSE,
+ editor_page);
+
+ webkit_dom_event_target_add_event_listener (
+ WEBKIT_DOM_EVENT_TARGET (dom_window),
+ "scroll",
+ G_CALLBACK (body_scroll_event_cb),
+ FALSE,
+ editor_page);
+
+ /* Intentionally leak the WebKitDOMDOMWindow object here as otherwise the
+ * callback won't be set up. */
+
+ register_html_events_handlers (editor_page, body);
+ e_editor_dom_set_monospace_font_family_on_body (
+ WEBKIT_DOM_ELEMENT (body), e_editor_page_get_html_mode (editor_page));
+
+ g_free (inner_html);
+}
+
+void
+e_editor_dom_convert_and_insert_html_into_selection (EEditorPage *editor_page,
+ const gchar *html,
+ gboolean is_html)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *selection_start_marker, *selection_end_marker, *element;
+ WebKitDOMNode *node, *current_block;
+ EEditorHistoryEvent *ev = NULL;
+ EEditorUndoRedoManager *manager;
+ gboolean has_selection;
+ gchar *inner_html;
+ gint citation_level;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+
+ e_editor_dom_remove_input_event_listener_from_body (editor_page);
+
+ e_editor_dom_selection_save (editor_page);
+ selection_start_marker = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-start-marker");
+ selection_end_marker = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-end-marker");
+ current_block = e_editor_dom_get_parent_block_node_from_child (
+ WEBKIT_DOM_NODE (selection_start_marker));
+ if (WEBKIT_DOM_IS_HTML_BODY_ELEMENT (current_block))
+ current_block = NULL;
+
+ manager = e_editor_page_get_undo_redo_manager (editor_page);
+ if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+ gboolean collapsed;
+
+ ev = g_new0 (EEditorHistoryEvent, 1);
+ ev->type = HISTORY_PASTE;
+/* FIXME WK2
+ ev->type = HISTORY_PASTE_AS_TEXT;*/
+
+ collapsed = e_editor_dom_selection_is_collapsed (editor_page);
+ e_editor_dom_selection_get_coordinates (editor_page,
+ &ev->before.start.x,
+ &ev->before.start.y,
+ &ev->before.end.x,
+ &ev->before.end.y);
+
+ if (!collapsed) {
+ ev->before.end.x = ev->before.start.x;
+ ev->before.end.y = ev->before.start.y;
+ }
+
+ ev->data.string.from = NULL;
+ ev->data.string.to = g_strdup (html);
+ }
+
+ element = webkit_dom_document_create_element (document, "div", NULL);
+ if (is_html) {
+ gchar *inner_text;
+
+ if (strstr (html, "\n")) {
+ GRegex *regex;
+ gchar *tmp;
+
+ /* Strip new lines between tags to avoid unwanted line breaks. */
+ regex = g_regex_new ("\\>[\\s]+\\<", 0, 0, NULL);
+ tmp = g_regex_replace (
+ regex, html, -1, 0, "> <", 0, NULL);
+ webkit_dom_element_set_inner_html (element, tmp, NULL);
+ g_free (tmp);
+ g_regex_unref (regex);
+ } else {
+ webkit_dom_element_set_inner_html (element, html, NULL);
+ }
+
+ inner_text = webkit_dom_html_element_get_inner_text (
+ WEBKIT_DOM_HTML_ELEMENT (element));
+ webkit_dom_html_element_set_inner_text (
+ WEBKIT_DOM_HTML_ELEMENT (element), inner_text, NULL);
+
+ g_free (inner_text);
+ } else
+ webkit_dom_html_element_set_inner_text (
+ WEBKIT_DOM_HTML_ELEMENT (element), html, NULL);
+
+ inner_html = webkit_dom_element_get_inner_html (element);
+ parse_html_into_blocks (editor_page, element, WEBKIT_DOM_ELEMENT (current_block), inner_html);
+
+ g_free (inner_html);
+
+ has_selection = !e_editor_dom_selection_is_collapsed (editor_page);
+ if (has_selection && !e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+ WebKitDOMRange *range = NULL;
+
+ range = e_editor_dom_get_current_range (editor_page);
+ insert_delete_event (editor_page, range);
+ g_clear_object (&range);
+
+ /* Remove the text that was meant to be replaced by the pasted text */
+ e_editor_dom_exec_command (editor_page, E_CONTENT_EDITOR_COMMAND_DELETE, NULL);
+
+ e_editor_dom_selection_save (editor_page);
+
+ selection_start_marker = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-start-marker");
+ selection_end_marker = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-end-marker");
+ current_block = e_editor_dom_get_parent_block_node_from_child (
+ WEBKIT_DOM_NODE (selection_start_marker));
+ if (WEBKIT_DOM_IS_HTML_BODY_ELEMENT (current_block))
+ current_block = NULL;
+ }
+
+ citation_level = e_editor_dom_get_citation_level (WEBKIT_DOM_NODE (selection_end_marker), FALSE);
+ /* Pasting into the citation */
+ if (citation_level > 0) {
+ gint length;
+ gint word_wrap_length;
+ WebKitDOMElement *br;
+ WebKitDOMNode *first_paragraph, *last_paragraph;
+ WebKitDOMNode *child, *parent, *current_block;
+
+ first_paragraph = webkit_dom_node_get_first_child (
+ WEBKIT_DOM_NODE (element));
+ last_paragraph = webkit_dom_node_get_last_child (
+ WEBKIT_DOM_NODE (element));
+
+ word_wrap_length = e_editor_page_get_word_wrap_length (editor_page);
+ length = word_wrap_length - 2 * citation_level;
+
+ /* Pasting text that was parsed just into one paragraph */
+ if (webkit_dom_node_is_same_node (first_paragraph, last_paragraph)) {
+ WebKitDOMNode *child, *parent, *parent_block;
+
+ parent_block = e_editor_dom_get_parent_block_node_from_child (
+ WEBKIT_DOM_NODE (selection_start_marker));
+
+ e_editor_dom_remove_quoting_from_element (WEBKIT_DOM_ELEMENT (parent_block));
+ e_editor_dom_remove_wrapping_from_element (WEBKIT_DOM_ELEMENT (parent_block));
+
+ parent = webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (selection_start_marker));
+ while ((child = webkit_dom_node_get_first_child (first_paragraph))) {
+ if (WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (parent) &&
+ WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (child)) {
+ WebKitDOMNode *anchor_child;
+
+ while ((anchor_child = webkit_dom_node_get_first_child (child)))
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (
+ WEBKIT_DOM_NODE (selection_start_marker)),
+ anchor_child,
+ WEBKIT_DOM_NODE (selection_start_marker),
+ NULL);
+ remove_node (child);
+ } else
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (
+ WEBKIT_DOM_NODE (selection_start_marker)),
+ child,
+ WEBKIT_DOM_NODE (selection_start_marker),
+ NULL);
+ }
+
+ if (WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (parent)) {
+ gchar *text_content;
+
+ text_content = webkit_dom_node_get_text_content (parent);
+
+ webkit_dom_element_set_attribute (
+ WEBKIT_DOM_ELEMENT (parent),
+ "href",
+ text_content,
+ NULL);
+ g_free (text_content);
+ }
+
+ parent_block = WEBKIT_DOM_NODE (
+ e_editor_dom_wrap_paragraph_length (editor_page, WEBKIT_DOM_ELEMENT
(parent_block), length));
+ webkit_dom_node_normalize (parent_block);
+ e_editor_dom_quote_plain_text_element_after_wrapping (editor_page, WEBKIT_DOM_ELEMENT
(parent_block), citation_level);
+
+ e_editor_dom_selection_restore (editor_page);
+
+ g_object_unref (element);
+ goto out;
+ }
+
+ /* Pasting content parsed into the multiple paragraphs */
+ parent = e_editor_dom_get_parent_block_node_from_child (
+ WEBKIT_DOM_NODE (selection_start_marker));
+
+ e_editor_dom_remove_quoting_from_element (WEBKIT_DOM_ELEMENT (parent));
+ e_editor_dom_remove_wrapping_from_element (WEBKIT_DOM_ELEMENT (parent));
+
+ /* Move the elements from the first paragraph before the selection start element */
+ while ((child = webkit_dom_node_get_first_child (first_paragraph)))
+ webkit_dom_node_insert_before (
+ parent,
+ child,
+ WEBKIT_DOM_NODE (selection_start_marker),
+ NULL);
+
+ remove_node (first_paragraph);
+
+ /* If the BR element is on the last position, remove it as we don't need it */
+ child = webkit_dom_node_get_last_child (parent);
+ if (WEBKIT_DOM_IS_HTML_BR_ELEMENT (child))
+ remove_node (child);
+
+ parent = e_editor_dom_get_parent_block_node_from_child (
+ WEBKIT_DOM_NODE (selection_end_marker));
+
+ child = webkit_dom_node_get_next_sibling (
+ WEBKIT_DOM_NODE (selection_end_marker));
+ /* Move the elements that are in the same paragraph as the selection end
+ * on the end of pasted text, but avoid BR on the end of paragraph */
+ while (child) {
+ WebKitDOMNode *next_child =
+ webkit_dom_node_get_next_sibling (child);
+ if (!(!next_child && WEBKIT_DOM_IS_HTML_BR_ELEMENT (child)))
+ webkit_dom_node_append_child (last_paragraph, child, NULL);
+ child = next_child;
+ }
+
+ current_block = e_editor_dom_get_parent_block_node_from_child (
+ WEBKIT_DOM_NODE (selection_start_marker));
+
+ dom_remove_selection_markers (document);
+
+ /* Caret will be restored on the end of pasted text */
+ webkit_dom_node_append_child (
+ last_paragraph,
+ WEBKIT_DOM_NODE (dom_create_selection_marker (document, TRUE)),
+ NULL);
+
+ webkit_dom_node_append_child (
+ last_paragraph,
+ WEBKIT_DOM_NODE (dom_create_selection_marker (document, FALSE)),
+ NULL);
+
+ /* Insert the paragraph with the end of the pasted text after
+ * the paragraph that contains the selection end */
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (parent),
+ last_paragraph,
+ webkit_dom_node_get_next_sibling (parent),
+ NULL);
+
+ /* Wrap, quote and move all paragraphs from pasted text into the body */
+ while ((child = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (element)))) {
+ child = WEBKIT_DOM_NODE (e_editor_dom_wrap_paragraph_length (
+ editor_page, WEBKIT_DOM_ELEMENT (child), length));
+ e_editor_dom_quote_plain_text_element_after_wrapping (editor_page, WEBKIT_DOM_ELEMENT
(child), citation_level);
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (last_paragraph),
+ child,
+ last_paragraph,
+ NULL);
+ }
+
+ webkit_dom_node_normalize (last_paragraph);
+
+ last_paragraph = WEBKIT_DOM_NODE (
+ e_editor_dom_wrap_paragraph_length (
+ editor_page, WEBKIT_DOM_ELEMENT (last_paragraph), length));
+ e_editor_dom_quote_plain_text_element_after_wrapping (editor_page, WEBKIT_DOM_ELEMENT
(last_paragraph), citation_level);
+
+ e_editor_dom_remove_quoting_from_element (WEBKIT_DOM_ELEMENT (parent));
+ e_editor_dom_remove_wrapping_from_element (WEBKIT_DOM_ELEMENT (parent));
+
+ current_block = WEBKIT_DOM_NODE (e_editor_dom_wrap_paragraph_length (
+ editor_page, WEBKIT_DOM_ELEMENT (current_block), length));
+ e_editor_dom_quote_plain_text_element_after_wrapping (editor_page, WEBKIT_DOM_ELEMENT
(current_block), citation_level);
+
+ if ((br = webkit_dom_document_get_element_by_id (document, "-x-evo-last-br")))
+ webkit_dom_element_remove_attribute (br, "class");
+
+ if ((br = webkit_dom_document_get_element_by_id (document, "-x-evo-first-br")))
+ webkit_dom_element_remove_attribute (br, "class");
+
+ if (ev) {
+ e_editor_dom_selection_get_coordinates (editor_page,
+ &ev->after.start.x,
+ &ev->after.start.y,
+ &ev->after.end.x,
+ &ev->after.end.y);
+ e_editor_undo_redo_manager_insert_history_event (manager, ev);
+ }
+
+ e_editor_dom_selection_restore (editor_page);
+
+ g_object_unref (element);
+ goto out;
+ }
+
+ remove_node (WEBKIT_DOM_NODE (selection_start_marker));
+ remove_node (WEBKIT_DOM_NODE (selection_end_marker));
+
+ /* If the text to insert was converted just to one block, pass just its
+ * text to WebKit otherwise WebKit will insert unwanted block with
+ * extra new line. */
+ if (!webkit_dom_node_get_next_sibling (webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (element))))
+ inner_html = webkit_dom_element_get_inner_html (
+ WEBKIT_DOM_ELEMENT (webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (element))));
+ else
+ inner_html = webkit_dom_element_get_inner_html (WEBKIT_DOM_ELEMENT (element));
+
+ e_editor_dom_exec_command (editor_page, E_CONTENT_EDITOR_COMMAND_INSERT_HTML, inner_html);
+
+ if (g_str_has_suffix (inner_html, " "))
+ e_editor_dom_exec_command (editor_page, E_CONTENT_EDITOR_COMMAND_INSERT_TEXT, " ");
+
+ g_free (inner_html);
+
+ g_object_unref (element);
+ e_editor_dom_selection_save (editor_page);
+
+ element = webkit_dom_document_query_selector (
+ document, "* > br#-x-evo-first-br", NULL);
+ if (element) {
+ WebKitDOMNode *sibling;
+ WebKitDOMNode *parent;
+
+ parent = webkit_dom_node_get_parent_node (
+ WEBKIT_DOM_NODE (element));
+
+ sibling = webkit_dom_node_get_previous_sibling (parent);
+ if (sibling)
+ remove_node (WEBKIT_DOM_NODE (parent));
+ else
+ webkit_dom_element_remove_attribute (element, "class");
+ }
+
+ element = webkit_dom_document_query_selector (
+ document, "* > br#-x-evo-last-br", NULL);
+ if (element) {
+ WebKitDOMNode *parent;
+ WebKitDOMNode *child;
+
+ parent = webkit_dom_node_get_parent_node (
+ WEBKIT_DOM_NODE (element));
+
+ node = webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (parent));
+ if (node) {
+ node = webkit_dom_node_get_first_child (node);
+ if (node) {
+ inner_html = webkit_dom_node_get_text_content (node);
+ if (g_str_has_prefix (inner_html, UNICODE_NBSP))
+ webkit_dom_character_data_replace_data (
+ WEBKIT_DOM_CHARACTER_DATA (node), 0, 1, "", NULL);
+ g_free (inner_html);
+ }
+ }
+
+ selection_end_marker = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-end-marker");
+
+ if (has_selection) {
+ /* Everything after the selection end marker have to be in separate
+ * paragraph */
+ child = webkit_dom_node_get_next_sibling (
+ WEBKIT_DOM_NODE (selection_end_marker));
+ /* Move the elements that are in the same paragraph as the selection end
+ * on the end of pasted text, but avoid BR on the end of paragraph */
+ while (child) {
+ WebKitDOMNode *next_child =
+ webkit_dom_node_get_next_sibling (child);
+ if (!(!next_child && WEBKIT_DOM_IS_HTML_BR_ELEMENT (child)))
+ webkit_dom_node_append_child (parent, child, NULL);
+ child = next_child;
+ }
+
+ remove_node (WEBKIT_DOM_NODE (element));
+
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (
+ webkit_dom_node_get_parent_node (
+ WEBKIT_DOM_NODE (selection_end_marker))),
+ parent,
+ webkit_dom_node_get_next_sibling (
+ webkit_dom_node_get_parent_node (
+ WEBKIT_DOM_NODE (selection_end_marker))),
+ NULL);
+ node = parent;
+ } else {
+ node = webkit_dom_node_get_next_sibling (parent);
+ if (!node) {
+ fix_structure_after_pasting_multiline_content (parent);
+ if (!webkit_dom_node_get_first_child (parent))
+ remove_node (parent);
+ }
+ }
+
+ if (node) {
+ /* Restore caret on the end of pasted text */
+ webkit_dom_node_insert_before (
+ node,
+ WEBKIT_DOM_NODE (selection_end_marker),
+ webkit_dom_node_get_first_child (node),
+ NULL);
+
+ selection_start_marker = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-start-marker");
+ webkit_dom_node_insert_before (
+ node,
+ WEBKIT_DOM_NODE (selection_start_marker),
+ webkit_dom_node_get_first_child (node),
+ NULL);
+ }
+
+ if (element)
+ webkit_dom_element_remove_attribute (element, "class");
+
+ if (webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (parent)) && !has_selection)
+ remove_node (parent);
+ } else {
+ /* When pasting the content that was copied from the composer, WebKit
+ * restores the selection wrongly, thus is saved wrongly and we have
+ * to fix it */
+ WebKitDOMNode *block, *parent, *clone1, *clone2;
+
+ selection_start_marker = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-start-marker");
+ selection_end_marker = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-end-marker");
+
+ block = e_editor_dom_get_parent_block_node_from_child (
+ WEBKIT_DOM_NODE (selection_start_marker));
+ parent = webkit_dom_node_get_parent_node (block);
+ webkit_dom_element_remove_attribute (WEBKIT_DOM_ELEMENT (parent), "id");
+
+ /* Check if WebKit created wrong structure */
+ clone1 = webkit_dom_node_clone_node_with_error (WEBKIT_DOM_NODE (block), FALSE, NULL);
+ clone2 = webkit_dom_node_clone_node_with_error (WEBKIT_DOM_NODE (parent), FALSE, NULL);
+ if (webkit_dom_node_is_equal_node (clone1, clone2) ||
+ (WEBKIT_DOM_IS_HTML_DIV_ELEMENT (clone1) && WEBKIT_DOM_IS_HTML_DIV_ELEMENT (clone2) &&
+ !element_has_class (WEBKIT_DOM_ELEMENT (clone2), "-x-evo-indented"))) {
+ fix_structure_after_pasting_multiline_content (block);
+ if (g_strcmp0 (html, "\n") == 0) {
+ WebKitDOMElement *br;
+
+ br = webkit_dom_document_create_element (document, "br", NULL);
+ webkit_dom_node_append_child (
+ parent, WEBKIT_DOM_NODE (br), NULL);
+
+ webkit_dom_node_insert_before (
+ parent,
+ WEBKIT_DOM_NODE (selection_start_marker),
+ webkit_dom_node_get_last_child (parent),
+ NULL);
+ } else if (!webkit_dom_node_get_first_child (parent))
+ remove_node (parent);
+ }
+
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (
+ WEBKIT_DOM_NODE (selection_start_marker)),
+ WEBKIT_DOM_NODE (selection_end_marker),
+ webkit_dom_node_get_next_sibling (
+ WEBKIT_DOM_NODE (selection_start_marker)),
+ NULL);
+ }
+
+ if (ev) {
+ e_editor_dom_selection_get_coordinates (editor_page,
+ &ev->after.start.x,
+ &ev->after.start.y,
+ &ev->after.end.x,
+ &ev->after.end.y);
+ e_editor_undo_redo_manager_insert_history_event (manager, ev);
+ }
+
+ e_editor_dom_selection_restore (editor_page);
+ out:
+ e_editor_dom_check_magic_links (editor_page, FALSE);
+ e_editor_dom_force_spell_check_in_viewport (editor_page);
+ e_editor_dom_scroll_to_caret (editor_page);
+
+ e_editor_dom_register_input_event_listener_on_body (editor_page);
+
+ e_editor_page_emit_content_changed (editor_page);
+}
+
+static gint
+get_indentation_level (WebKitDOMElement *element)
+{
+ WebKitDOMElement *parent;
+ gint level = 0;
+
+ if (!element)
+ return 0;
+
+ if (element_has_class (element, "-x-evo-indented"))
+ level++;
+
+ parent = webkit_dom_node_get_parent_element (WEBKIT_DOM_NODE (element));
+ /* Count level of indentation */
+ while (parent && !WEBKIT_DOM_IS_HTML_BODY_ELEMENT (parent)) {
+ if (element_has_class (parent, "-x-evo-indented"))
+ level++;
+
+ parent = webkit_dom_node_get_parent_element (WEBKIT_DOM_NODE (parent));
+ }
+
+ return level;
+}
+
+static void
+process_indented_element (WebKitDOMElement *element)
+{
+ gchar *spaces;
+ WebKitDOMNode *child;
+
+ if (!element)
+ return;
+
+ spaces = g_strnfill (4 * get_indentation_level (element), ' ');
+
+ child = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (element));
+ while (child) {
+ /* If next sibling is indented blockqoute skip it,
+ * it will be processed afterwards */
+ if (WEBKIT_DOM_IS_ELEMENT (child) &&
+ element_has_class (WEBKIT_DOM_ELEMENT (child), "-x-evo-indented"))
+ child = webkit_dom_node_get_next_sibling (child);
+
+ if (WEBKIT_DOM_IS_TEXT (child)) {
+ gchar *text_content;
+ gchar *indented_text;
+
+ text_content = webkit_dom_text_get_whole_text (WEBKIT_DOM_TEXT (child));
+ indented_text = g_strconcat (spaces, text_content, NULL);
+
+ webkit_dom_text_replace_whole_text (
+ WEBKIT_DOM_TEXT (child),
+ indented_text,
+ NULL);
+
+ g_free (text_content);
+ g_free (indented_text);
+ }
+
+ if (!child)
+ break;
+
+ /* Move to next node */
+ if (webkit_dom_node_has_child_nodes (child))
+ child = webkit_dom_node_get_first_child (child);
+ else if (webkit_dom_node_get_next_sibling (child))
+ child = webkit_dom_node_get_next_sibling (child);
+ else {
+ if (webkit_dom_node_is_equal_node (WEBKIT_DOM_NODE (element), child))
+ break;
+
+ child = webkit_dom_node_get_parent_node (child);
+ if (child)
+ child = webkit_dom_node_get_next_sibling (child);
+ }
+ }
+ g_free (spaces);
+
+ webkit_dom_element_remove_attribute (element, "style");
+}
+
+static void
+process_quote_nodes (WebKitDOMElement *blockquote)
+{
+ WebKitDOMNodeList *list = NULL;
+ int jj, length;
+
+ /* Replace quote nodes with symbols */
+ list = webkit_dom_element_query_selector_all (
+ blockquote, "span.-x-evo-quoted", NULL);
+ length = webkit_dom_node_list_get_length (list);
+ for (jj = 0; jj < length; jj++) {
+ WebKitDOMNode *quoted_node;
+ gchar *text_content;
+
+ quoted_node = webkit_dom_node_list_item (list, jj);
+ text_content = webkit_dom_node_get_text_content (quoted_node);
+ webkit_dom_element_set_outer_html (
+ WEBKIT_DOM_ELEMENT (quoted_node), text_content, NULL);
+
+ g_free (text_content);
+ g_object_unref (quoted_node);
+ }
+ g_clear_object (&list);
+}
+
+/* Taken from GtkHTML */
+static gchar *
+get_alpha_value (gint value,
+ gboolean lower)
+{
+ GString *str;
+ gchar *rv;
+ gint add = lower ? 'a' : 'A';
+
+ str = g_string_new (". ");
+
+ do {
+ g_string_prepend_c (str, ((value - 1) % 26) + add);
+ value = (value - 1) / 26;
+ } while (value);
+
+ rv = str->str;
+ g_string_free (str, FALSE);
+
+ return rv;
+}
+
+/* Taken from GtkHTML */
+static gchar *
+get_roman_value (gint value,
+ gboolean lower)
+{
+ GString *str;
+ const gchar *base = "IVXLCDM";
+ gchar *rv;
+ gint b, r, add = lower ? 'a' - 'A' : 0;
+
+ if (value > 3999)
+ return g_strdup ("?. ");
+
+ str = g_string_new (". ");
+
+ for (b = 0; value > 0 && b < 7 - 1; b += 2, value /= 10) {
+ r = value % 10;
+ if (r != 0) {
+ if (r < 4) {
+ for (; r; r--)
+ g_string_prepend_c (str, base[b] + add);
+ } else if (r == 4) {
+ g_string_prepend_c (str, base[b + 1] + add);
+ g_string_prepend_c (str, base[b] + add);
+ } else if (r == 5) {
+ g_string_prepend_c (str, base[b + 1] + add);
+ } else if (r < 9) {
+ for (; r > 5; r--)
+ g_string_prepend_c (str, base[b] + add);
+ g_string_prepend_c (str, base[b + 1] + add);
+ } else if (r == 9) {
+ g_string_prepend_c (str, base[b + 2] + add);
+ g_string_prepend_c (str, base[b] + add);
+ }
+ }
+ }
+
+ rv = str->str;
+ g_string_free (str, FALSE);
+
+ return rv;
+}
+
+static void
+process_list_to_plain_text (EEditorPage *editor_page,
+ WebKitDOMElement *element,
+ gint level,
+ GString *output)
+{
+ EContentEditorBlockFormat format;
+ EContentEditorAlignment alignment;
+ gint counter = 1;
+ gboolean empty = TRUE;
+ gchar *indent_per_level;
+ WebKitDOMNode *item;
+ gint word_wrap_length;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ indent_per_level = g_strnfill (SPACES_PER_LIST_LEVEL, ' ');
+ word_wrap_length = e_editor_page_get_word_wrap_length (editor_page);
+ format = dom_get_list_format_from_node (
+ WEBKIT_DOM_NODE (element));
+
+ /* Process list items to plain text */
+ item = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (element));
+ while (item) {
+ if (WEBKIT_DOM_IS_HTML_BR_ELEMENT (item))
+ g_string_append (output, "\n");
+
+ if (WEBKIT_DOM_IS_HTML_LI_ELEMENT (item)) {
+ gchar *space = NULL, *item_str = NULL;
+ gint ii = 0;
+ WebKitDOMElement *wrapped;
+ GString *item_value = g_string_new ("");
+
+ empty = FALSE;
+
+ alignment = e_editor_dom_get_list_alignment_from_node (
+ WEBKIT_DOM_NODE (item));
+
+ wrapped = webkit_dom_element_query_selector (
+ WEBKIT_DOM_ELEMENT (item), ".-x-evo-wrap-br", NULL);
+ /* Wrapped text */
+ if (wrapped) {
+ WebKitDOMNode *node = webkit_dom_node_get_first_child (item);
+ GString *line = g_string_new ("");
+
+ while (node) {
+ if (WEBKIT_DOM_IS_HTML_BR_ELEMENT (node) &&
+ element_has_class (WEBKIT_DOM_ELEMENT (node), "-x-evo-wrap-br")) {
+ g_string_append (line, "\n");
+ /* put spaces before line characters -> wordwraplength -
indentation */
+ for (ii = 0; ii < level; ii++)
+ g_string_append (line, indent_per_level);
+ if (WEBKIT_DOM_IS_HTML_O_LIST_ELEMENT (element))
+ g_string_append (line, indent_per_level);
+ g_string_append (item_value, line->str);
+ g_string_erase (line, 0, -1);
+ } else {
+ /* append text from node to line */
+ gchar *text_content;
+ text_content = webkit_dom_node_get_text_content (node);
+ g_string_append (line, text_content);
+ g_free (text_content);
+ }
+ node = webkit_dom_node_get_next_sibling (node);
+ }
+
+ if (alignment == E_CONTENT_EDITOR_ALIGNMENT_LEFT)
+ g_string_append (item_value, line->str);
+
+ if (alignment == E_CONTENT_EDITOR_ALIGNMENT_CENTER) {
+ gchar *fill = NULL;
+ gint fill_length;
+
+ fill_length = word_wrap_length - g_utf8_strlen (line->str, -1);
+ fill_length -= ii * SPACES_PER_LIST_LEVEL;
+ if (WEBKIT_DOM_IS_HTML_O_LIST_ELEMENT (element))
+ fill_length += SPACES_PER_LIST_LEVEL;
+ fill_length /= 2;
+
+ if (fill_length < 0)
+ fill_length = 0;
+
+ fill = g_strnfill (fill_length, ' ');
+
+ g_string_append (item_value, fill);
+ g_string_append (item_value, line->str);
+ g_free (fill);
+ }
+
+ if (alignment == E_CONTENT_EDITOR_ALIGNMENT_RIGHT) {
+ gchar *fill = NULL;
+ gint fill_length;
+
+ fill_length = word_wrap_length - g_utf8_strlen (line->str, -1);
+ fill_length -= ii * SPACES_PER_LIST_LEVEL;
+
+ if (fill_length < 0)
+ fill_length = 0;
+
+ fill = g_strnfill (fill_length, ' ');
+
+ g_string_append (item_value, fill);
+ g_string_append (item_value, line->str);
+ g_free (fill);
+ }
+ g_string_free (line, TRUE);
+ /* that same here */
+ } else {
+ gchar *text_content =
+ webkit_dom_node_get_text_content (item);
+
+ g_string_append (item_value, text_content);
+ g_free (text_content);
+ }
+
+ if (format == E_CONTENT_EDITOR_BLOCK_FORMAT_UNORDERED_LIST) {
+ space = g_strnfill (SPACES_PER_LIST_LEVEL - 2, ' ');
+ item_str = g_strdup_printf (
+ "%s* %s", space, item_value->str);
+ g_free (space);
+ }
+
+ if (format == E_CONTENT_EDITOR_BLOCK_FORMAT_ORDERED_LIST) {
+ gint length = 1, tmp = counter, spaces_count;
+
+ while ((tmp = tmp / 10) > 1)
+ length++;
+
+ if (tmp == 1)
+ length++;
+
+ spaces_count = SPACES_ORDERED_LIST_FIRST_LEVEL - 2 - length;
+ if (spaces_count > 0)
+ space = g_strnfill (spaces_count, ' ');
+
+ item_str = g_strdup_printf (
+ "%s%d. %s", space && *space ? space : "", counter, item_value->str);
+ g_free (space);
+ }
+
+ if (format > E_CONTENT_EDITOR_BLOCK_FORMAT_ORDERED_LIST) {
+ gchar *value, spaces_count;
+
+ if (format == E_CONTENT_EDITOR_BLOCK_FORMAT_ORDERED_LIST_ALPHA)
+ value = get_alpha_value (counter, FALSE);
+ else
+ value = get_roman_value (counter, FALSE);
+
+ spaces_count = SPACES_ORDERED_LIST_FIRST_LEVEL - strlen (value);
+ if (spaces_count > 0)
+ space = g_strnfill (spaces_count, ' ');
+ item_str = g_strdup_printf (
+ "%s%s%s", space && *space ? space : "" , value, item_value->str);
+ g_free (space);
+ g_free (value);
+ }
+
+ if (alignment == E_CONTENT_EDITOR_ALIGNMENT_LEFT) {
+ for (ii = 0; ii < level - 1; ii++) {
+ g_string_append (output, indent_per_level);
+ }
+ if (WEBKIT_DOM_IS_HTML_U_LIST_ELEMENT (element))
+ if (dom_node_find_parent_element (item, "OL"))
+ g_string_append (output, indent_per_level);
+ g_string_append (output, item_str);
+ }
+
+ if (alignment == E_CONTENT_EDITOR_ALIGNMENT_RIGHT) {
+ if (!wrapped) {
+ gchar *fill = NULL;
+ gint fill_length;
+
+ fill_length = word_wrap_length - g_utf8_strlen (item_str, -1);
+ fill_length -= ii * SPACES_PER_LIST_LEVEL;
+
+ if (fill_length < 0)
+ fill_length = 0;
+
+ if (g_str_has_suffix (item_str, " "))
+ fill_length++;
+
+ fill = g_strnfill (fill_length, ' ');
+
+ g_string_append (output, fill);
+ g_free (fill);
+ }
+ if (g_str_has_suffix (item_str, " "))
+ g_string_append_len (output, item_str, g_utf8_strlen (item_str, -1) -
1);
+ else
+ g_string_append (output, item_str);
+ }
+
+ if (alignment == E_CONTENT_EDITOR_ALIGNMENT_CENTER) {
+ if (!wrapped) {
+ gchar *fill = NULL;
+ gint fill_length = 0;
+
+ for (ii = 0; ii < level - 1; ii++)
+ g_string_append (output, indent_per_level);
+
+ fill_length = word_wrap_length - g_utf8_strlen (item_str, -1);
+ fill_length -= ii * SPACES_PER_LIST_LEVEL;
+ if (WEBKIT_DOM_IS_HTML_O_LIST_ELEMENT (element))
+ fill_length += SPACES_PER_LIST_LEVEL;
+ fill_length /= 2;
+
+ if (fill_length < 0)
+ fill_length = 0;
+
+ if (g_str_has_suffix (item_str, " "))
+ fill_length++;
+
+ fill = g_strnfill (fill_length, ' ');
+
+ g_string_append (output, fill);
+ g_free (fill);
+ }
+ if (g_str_has_suffix (item_str, " "))
+ g_string_append_len (output, item_str, g_utf8_strlen (item_str, -1) -
1);
+ else
+ g_string_append (output, item_str);
+ }
+
+ counter++;
+ item = webkit_dom_node_get_next_sibling (item);
+ if (item)
+ g_string_append (output, "\n");
+
+ g_free (item_str);
+ g_string_free (item_value, TRUE);
+ } else if (node_is_list (item)) {
+ process_list_to_plain_text (
+ editor_page, WEBKIT_DOM_ELEMENT (item), level + 1, output);
+ item = webkit_dom_node_get_next_sibling (item);
+ } else {
+ item = webkit_dom_node_get_next_sibling (item);
+ }
+ }
+
+ if (webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (element)) && !empty)
+ g_string_append (output, "\n");
+
+ g_free (indent_per_level);
+}
+
+static void
+remove_base_attributes (WebKitDOMElement *element)
+{
+ webkit_dom_element_remove_attribute (element, "class");
+ webkit_dom_element_remove_attribute (element, "id");
+ webkit_dom_element_remove_attribute (element, "name");
+}
+
+static void
+remove_evolution_attributes (WebKitDOMElement *element)
+{
+ webkit_dom_element_remove_attribute (element, "data-evo-paragraph");
+ webkit_dom_element_remove_attribute (element, "data-converted");
+ webkit_dom_element_remove_attribute (element, "data-edit-as-new");
+ webkit_dom_element_remove_attribute (element, "data-evo-draft");
+ webkit_dom_element_remove_attribute (element, "data-inline");
+ webkit_dom_element_remove_attribute (element, "data-uri");
+ webkit_dom_element_remove_attribute (element, "data-message");
+ webkit_dom_element_remove_attribute (element, "data-name");
+ webkit_dom_element_remove_attribute (element, "data-new-message");
+ webkit_dom_element_remove_attribute (element, "data-user-wrapped");
+ webkit_dom_element_remove_attribute (element, "data-evo-plain-text");
+ webkit_dom_element_remove_attribute (element, "data-plain-text-style");
+ webkit_dom_element_remove_attribute (element, "data-style");
+ webkit_dom_element_remove_attribute (element, "spellcheck");
+}
+
+static void
+convert_element_from_html_to_plain_text (EEditorPage *editor_page,
+ WebKitDOMElement *element,
+ gboolean *wrap,
+ gboolean *quote)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *top_signature, *signature, *blockquote, *main_blockquote;
+ WebKitDOMNode *signature_clone, *from;
+ WebKitDOMNodeList *list = NULL;
+ gint blockquotes_count, ii, length;
+ gchar *inner_text, *inner_html;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+ top_signature = webkit_dom_element_query_selector (
+ element, ".-x-evo-top-signature", NULL);
+ signature = webkit_dom_element_query_selector (
+ element, "span.-x-evo-signature", NULL);
+ main_blockquote = webkit_dom_element_query_selector (
+ element, "#-x-evo-main-cite", NULL);
+
+ blockquote = webkit_dom_document_create_element (
+ document, "blockquote", NULL);
+
+ if (main_blockquote) {
+ webkit_dom_element_set_attribute (
+ blockquote, "type", "cite", NULL);
+ from = WEBKIT_DOM_NODE (main_blockquote);
+ } else {
+ if (signature) {
+ WebKitDOMNode *parent = webkit_dom_node_get_parent_node (
+ WEBKIT_DOM_NODE (signature));
+ signature_clone = webkit_dom_node_clone_node_with_error (parent, TRUE, NULL);
+ remove_node (parent);
+ }
+ from = WEBKIT_DOM_NODE (element);
+ }
+
+ blockquotes_count = create_text_markers_for_citations_in_element (WEBKIT_DOM_ELEMENT (from));
+ create_text_markers_for_selection_in_element (WEBKIT_DOM_ELEMENT (from));
+
+ /* Add the missing BR elements on the end of DIV and P elements to
+ * preserve the line breaks. But we need to do that just in case that
+ * there is another element that contains text. */
+ list = webkit_dom_element_query_selector_all (WEBKIT_DOM_ELEMENT (from), "div, p", NULL);
+ length = webkit_dom_node_list_get_length (list);
+ for (ii = 0; ii < length; ii++) {
+ gboolean insert = TRUE;
+ WebKitDOMNode *node, *next_sibling;
+
+ node = webkit_dom_node_list_item (list, ii);
+ next_sibling = webkit_dom_node_get_next_sibling (node);
+
+ if (!next_sibling)
+ insert = FALSE;
+
+ while (insert && next_sibling) {
+ if (!webkit_dom_node_has_child_nodes (next_sibling) &&
+ !webkit_dom_node_get_next_sibling (next_sibling))
+ insert = FALSE;
+ next_sibling = webkit_dom_node_get_next_sibling (next_sibling);
+ }
+
+ if (insert && !WEBKIT_DOM_IS_HTML_BR_ELEMENT (webkit_dom_node_get_last_child (node)))
+ webkit_dom_node_append_child (
+ node,
+ WEBKIT_DOM_NODE (webkit_dom_document_create_element (document, "br", NULL)),
+ NULL);
+
+ g_object_unref (node);
+ }
+ g_clear_object (&list);
+
+ inner_text = webkit_dom_html_element_get_inner_text (
+ WEBKIT_DOM_HTML_ELEMENT (from));
+
+ webkit_dom_html_element_set_inner_text (
+ WEBKIT_DOM_HTML_ELEMENT (blockquote), inner_text, NULL);
+
+ inner_html = webkit_dom_element_get_inner_html (blockquote);
+
+ parse_html_into_blocks (editor_page,
+ main_blockquote ? blockquote : WEBKIT_DOM_ELEMENT (element),
+ NULL,
+ inner_html);
+
+ if (main_blockquote) {
+ webkit_dom_node_replace_child (
+ webkit_dom_node_get_parent_node (
+ WEBKIT_DOM_NODE (main_blockquote)),
+ WEBKIT_DOM_NODE (blockquote),
+ WEBKIT_DOM_NODE (main_blockquote),
+ NULL);
+
+ remove_evolution_attributes (WEBKIT_DOM_ELEMENT (element));
+ } else {
+ WebKitDOMNode *first_child;
+
+ if (signature) {
+ if (!top_signature) {
+ signature_clone = webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (element),
+ signature_clone,
+ NULL);
+ } else {
+ webkit_dom_node_insert_before (
+ WEBKIT_DOM_NODE (element),
+ signature_clone,
+ webkit_dom_node_get_first_child (
+ WEBKIT_DOM_NODE (element)),
+ NULL);
+ }
+ }
+
+ first_child = webkit_dom_node_get_first_child (
+ WEBKIT_DOM_NODE (element));
+ if (first_child) {
+ if (!webkit_dom_node_has_child_nodes (first_child)) {
+ webkit_dom_element_set_inner_html (
+ WEBKIT_DOM_ELEMENT (first_child),
+ "<br>",
+ NULL);
+ }
+ dom_add_selection_markers_into_element_start (
+ document, WEBKIT_DOM_ELEMENT (first_child), NULL, NULL);
+ }
+ }
+
+ if (wrap)
+ *wrap = TRUE;
+ if (quote)
+ *quote = main_blockquote || blockquotes_count > 0;
+
+ webkit_dom_element_set_attribute (
+ WEBKIT_DOM_ELEMENT (element), "data-converted", "", NULL);
+
+ g_free (inner_text);
+ g_free (inner_html);
+}
+
+void
+e_editor_dom_convert_element_from_html_to_plain_text (EEditorPage *editor_page,
+ WebKitDOMElement *element)
+{
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ convert_element_from_html_to_plain_text (editor_page, element, NULL, NULL);
+}
+
+static void
+process_node_to_plain_text_changing_composer_mode (EEditorPage *editor_page,
+ WebKitDOMNode *source)
+{
+ WebKitDOMElement *element;
+ WebKitDOMNamedNodeMap *attributes = NULL;
+ gint length, ii;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ attributes = webkit_dom_element_get_attributes (WEBKIT_DOM_ELEMENT (source));
+ length = webkit_dom_named_node_map_get_length (attributes);
+ for (ii = 0; ii < length; ii++) {
+ gchar *name = NULL;
+ WebKitDOMNode *attribute;
+
+ attribute = webkit_dom_named_node_map_item (attributes, ii);
+
+ name = webkit_dom_node_get_local_name (attribute);
+
+ if (g_strcmp0 (name, "bgcolor") == 0 ||
+ g_strcmp0 (name, "text") == 0 ||
+ g_strcmp0 (name, "vlink") == 0 ||
+ g_strcmp0 (name, "link") == 0) {
+
+ webkit_dom_element_remove_attribute_node (
+ WEBKIT_DOM_ELEMENT (source),
+ WEBKIT_DOM_ATTR (attribute),
+ NULL);
+ length--;
+ }
+ g_free (name);
+ g_object_unref (attribute);
+ }
+ g_clear_object (&attributes);
+
+ /* Signature */
+ element = webkit_dom_element_query_selector (
+ WEBKIT_DOM_ELEMENT (source), "div.-x-evo-signature-wrapper", NULL);
+ if (element) {
+ WebKitDOMNode *first_child;
+
+ first_child = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (element));
+
+ convert_element_from_html_to_plain_text (
+ editor_page, WEBKIT_DOM_ELEMENT (first_child), NULL, NULL);
+ }
+}
+
+/* This function is different than the others there as this needs to go through
+ * the DOM node by node and generate the plain text of their content. For some
+ * it will just take the text content, but for example the lists are not that
+ * easy. */
+static void
+process_node_to_plain_text_for_exporting (EEditorPage *editor_page,
+ WebKitDOMNode *source,
+ GString *buffer)
+{
+ WebKitDOMNodeList *nodes = NULL;
+ gboolean html_mode;
+ gchar *content = NULL;
+ gint ii, nodes_length;
+
+ html_mode = e_editor_page_get_html_mode (editor_page);
+
+ nodes = webkit_dom_node_get_child_nodes (source);
+ nodes_length = webkit_dom_node_list_get_length (nodes);
+
+ for (ii = 0; ii < nodes_length; ii++) {
+ WebKitDOMNode *child;
+ gboolean skip_node = FALSE;
+
+ child = webkit_dom_node_list_item (nodes, ii);
+
+ if (WEBKIT_DOM_IS_TEXT (child)) {
+ gchar *class;
+ const gchar *css_align = NULL;
+ GRegex *regex;
+
+ content = webkit_dom_node_get_text_content (child);
+ if (strstr (content, UNICODE_ZERO_WIDTH_SPACE)) {
+ gchar *tmp;
+
+ regex = g_regex_new (UNICODE_ZERO_WIDTH_SPACE, 0, 0, NULL);
+ tmp = g_regex_replace (
+ regex, content, -1, 0, "", 0, NULL);
+ g_free (content);
+ content = tmp;
+ g_regex_unref (regex);
+ }
+
+ class = webkit_dom_element_get_class_name (WEBKIT_DOM_ELEMENT (source));
+ if (class && (css_align = strstr (class, "-x-evo-align-"))) {
+ gchar *content_with_align;
+ gint word_wrap_length = e_editor_page_get_word_wrap_length (editor_page);
+
+ if (!g_str_has_prefix (css_align + 13, "left")) {
+ gchar *align;
+ gint length;
+
+ if (g_str_has_prefix (css_align + 13, "center"))
+ length = (word_wrap_length - g_utf8_strlen (content, -1)) / 2;
+ else
+ length = word_wrap_length - g_utf8_strlen (content, -1);
+
+ if (length < 0)
+ length = 0;
+
+ if (g_str_has_suffix (content, " ")) {
+ char *tmp;
+
+ length++;
+ align = g_strnfill (length, ' ');
+
+ tmp = g_strndup (content, g_utf8_strlen (content, -1) -1);
+
+ content_with_align = g_strconcat (
+ align, tmp, NULL);
+ g_free (tmp);
+ } else {
+ align = g_strnfill (length, ' ');
+
+ content_with_align = g_strconcat (
+ align, content, NULL);
+ }
+
+ g_free (content);
+ g_free (align);
+ content = content_with_align;
+ }
+ }
+
+ g_free (class);
+
+ g_string_append (buffer, content);
+
+ goto next;
+ }
+
+ if (!WEBKIT_DOM_IS_ELEMENT (child))
+ goto next;
+
+ if (element_has_class (WEBKIT_DOM_ELEMENT (child), "Apple-tab-span")) {
+ content = webkit_dom_node_get_text_content (child);
+ g_string_append (buffer, content);
+ g_free (content);
+ skip_node = TRUE;
+ goto next;
+ }
+
+ if (WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (child))
+ process_quote_nodes (WEBKIT_DOM_ELEMENT (child));
+
+ if (WEBKIT_DOM_IS_HTML_DIV_ELEMENT (child) &&
+ element_has_class (WEBKIT_DOM_ELEMENT (child), "-x-evo-indented"))
+ process_indented_element (WEBKIT_DOM_ELEMENT (child));
+
+ if (node_is_list (child)) {
+ process_list_to_plain_text (editor_page, WEBKIT_DOM_ELEMENT (child), 1, buffer);
+ skip_node = TRUE;
+ goto next;
+ }
+
+ if (element_has_class (WEBKIT_DOM_ELEMENT (child), "-x-evo-resizable-wrapper") &&
+ !element_has_class (WEBKIT_DOM_ELEMENT (child), "-x-evo-smiley-wrapper")) {
+ skip_node = TRUE;
+ goto next;
+ }
+
+ /* Signature */
+ if (WEBKIT_DOM_IS_HTML_DIV_ELEMENT (child) &&
+ element_has_class (WEBKIT_DOM_ELEMENT (child), "-x-evo-signature-wrapper")) {
+ WebKitDOMNode *first_child;
+ gchar *id;
+
+ first_child = webkit_dom_node_get_first_child (child);
+
+ skip_node = TRUE;
+ /* Don't generate any text if the signature is set to None. */
+ id = webkit_dom_element_get_id (WEBKIT_DOM_ELEMENT (first_child));
+ if (g_strcmp0 (id, "none") == 0) {
+ g_free (id);
+
+ remove_node (child);
+ goto next;
+ }
+ g_free (id);
+
+ if (html_mode) {
+ convert_element_from_html_to_plain_text (
+ editor_page, WEBKIT_DOM_ELEMENT (first_child), NULL, NULL);
+ skip_node = FALSE;
+ }
+
+ goto next;
+ }
+
+ /* Replace smileys with their text representation */
+ if (element_has_class (WEBKIT_DOM_ELEMENT (child), "-x-evo-smiley-wrapper")) {
+ WebKitDOMNode *text_version;
+
+ text_version = webkit_dom_node_get_last_child (child);
+ content = webkit_dom_html_element_get_inner_text (
+ WEBKIT_DOM_HTML_ELEMENT (text_version));
+ g_string_append (buffer, content);
+ g_free (content);
+ skip_node = TRUE;
+ goto next;
+ }
+
+ if (WEBKIT_DOM_IS_HTML_BR_ELEMENT (child)) {
+ g_string_append (buffer, "\n");
+ goto next;
+ }
+
+ if (WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (child)) {
+ content = webkit_dom_html_element_get_inner_text (
+ WEBKIT_DOM_HTML_ELEMENT (child));
+ g_string_append (buffer, content);
+ g_free (content);
+ skip_node = TRUE;
+ }
+ next:
+ if (!skip_node && webkit_dom_node_has_child_nodes (child))
+ process_node_to_plain_text_for_exporting (editor_page, child, buffer);
+ g_object_unref (child);
+ }
+ g_clear_object (&nodes);
+
+ if (!g_str_has_suffix (buffer->str, "\n") &&
+ (WEBKIT_DOM_IS_HTML_DIV_ELEMENT (source) ||
+ WEBKIT_DOM_IS_HTML_PARAGRAPH_ELEMENT (source) ||
+ WEBKIT_DOM_IS_HTML_PRE_ELEMENT (source) ||
+ WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (source)))
+ g_string_append (buffer, "\n");
+
+ if (g_str_has_suffix (buffer->str, "\n") &&
+ WEBKIT_DOM_IS_HTML_BODY_ELEMENT (source))
+ g_string_truncate (buffer, buffer->len - 1);
+}
+
+static void
+process_node_to_html_changing_composer_mode (EEditorPage *editor_page,
+ WebKitDOMNode *source)
+{
+}
+
+static void
+process_node_to_html_for_exporting (EEditorPage *editor_page,
+ WebKitDOMNode *source)
+{
+ WebKitDOMNodeList *list = NULL;
+ WebKitDOMHTMLCollection *collection = NULL;
+ WebKitDOMElement *element;
+ WebKitDOMDocument *document;
+ gint ii, length;
+
+ document = webkit_dom_node_get_owner_document (source);
+
+ remove_evolution_attributes (WEBKIT_DOM_ELEMENT (source));
+
+ /* Aligned elements */
+ list = webkit_dom_element_query_selector_all (WEBKIT_DOM_ELEMENT (source),
"[class*=\"-x-evo-align\"]", NULL);
+ length = webkit_dom_node_list_get_length (list);
+
+ for (ii = 0; ii < length; ii++) {
+ gchar *class = NULL;
+ WebKitDOMNode *node;
+ gboolean center = FALSE;
+
+ node = webkit_dom_node_list_item (list, ii);
+ class = webkit_dom_element_get_class_name (WEBKIT_DOM_ELEMENT (node));
+ center = g_strrstr (class, "center") != NULL;
+ if (center || g_strrstr (class, "right")) {
+ if (WEBKIT_DOM_IS_HTML_LI_ELEMENT (node))
+ webkit_dom_element_set_attribute (
+ WEBKIT_DOM_ELEMENT (node),
+ "style",
+ center ?
+ "list-style-position: inside; text-align: center" :
+ "list-style-position: inside; text-align: right",
+ NULL);
+ else
+ webkit_dom_element_set_attribute (
+ WEBKIT_DOM_ELEMENT (node),
+ "style",
+ center ?
+ "text-align: center" :
+ "text-align: right",
+ NULL);
+ }
+ element_remove_class (WEBKIT_DOM_ELEMENT (node), "-x-evo-align-left");
+ element_remove_class (WEBKIT_DOM_ELEMENT (node), "-x-evo-align-center");
+ element_remove_class (WEBKIT_DOM_ELEMENT (node), "-x-evo-align-right");
+ g_free (class);
+ g_object_unref (node);
+ }
+ g_clear_object (&list);
+
+ /* Indented elements */
+ list = webkit_dom_element_query_selector_all (
+ WEBKIT_DOM_ELEMENT (source), ".-x-evo-indented", NULL);
+ length = webkit_dom_node_list_get_length (list);
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMNode *node;
+
+ node = webkit_dom_node_list_item (list, ii);
+ element_remove_class (WEBKIT_DOM_ELEMENT (node), "-x-evo-indented");
+ remove_evolution_attributes (WEBKIT_DOM_ELEMENT (node));
+
+ g_object_unref (node);
+ }
+ g_clear_object (&list);
+
+ /* Tab characters */
+ list = webkit_dom_element_query_selector_all (
+ WEBKIT_DOM_ELEMENT (source), ".Apple-tab-span", NULL);
+ length = webkit_dom_node_list_get_length (list);
+ for (ii = 0; ii < length; ii++) {
+ gchar *text_content;
+ WebKitDOMNode *node;
+
+ node = webkit_dom_node_list_item (list, ii);
+ text_content = webkit_dom_node_get_text_content (node);
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (node),
+ WEBKIT_DOM_NODE (webkit_dom_document_create_text_node (document, text_content)),
+ node,
+ NULL);
+
+ remove_node (node);
+ g_object_unref (node);
+ }
+ g_clear_object (&list);
+
+ list = webkit_dom_element_query_selector_all (
+ WEBKIT_DOM_ELEMENT (source), ".-x-evo-quoted", NULL);
+ length = webkit_dom_node_list_get_length (list);
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMNode *quoted_node;
+ gchar *text_content;
+
+ quoted_node = webkit_dom_node_list_item (list, ii);
+ text_content = webkit_dom_node_get_text_content (quoted_node);
+ webkit_dom_element_set_outer_html (
+ WEBKIT_DOM_ELEMENT (quoted_node), text_content, NULL);
+
+ g_free (text_content);
+ g_object_unref (quoted_node);
+ }
+ g_clear_object (&list);
+
+ /* Images */
+ list = webkit_dom_element_query_selector_all (
+ WEBKIT_DOM_ELEMENT (source), ".-x-evo-resizable-wrapper:not(.-x-evo-smiley-wrapper)", NULL);
+ length = webkit_dom_node_list_get_length (list);
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMNode *node, *image;
+
+ node = webkit_dom_node_list_item (list, ii);
+ image = webkit_dom_node_get_first_child (node);
+
+ if (WEBKIT_DOM_IS_HTML_IMAGE_ELEMENT (image)) {
+ remove_evolution_attributes (
+ WEBKIT_DOM_ELEMENT (image));
+
+ webkit_dom_node_replace_child (
+ webkit_dom_node_get_parent_node (node), image, node, NULL);
+ }
+
+ g_object_unref (node);
+ }
+ g_clear_object (&list);
+
+ /* Signature */
+ element = webkit_dom_element_query_selector (
+ WEBKIT_DOM_ELEMENT (source), "div.-x-evo-signature-wrapper", NULL);
+ if (element) {
+ WebKitDOMNode *first_child;
+ gchar *id;
+
+ /* Don't generate any text if the signature is set to None. */
+ first_child = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (element));
+ id = webkit_dom_element_get_id (WEBKIT_DOM_ELEMENT (first_child));
+ if (g_strcmp0 (id, "none") == 0) {
+ remove_node (WEBKIT_DOM_NODE (element));
+ } else {
+ remove_base_attributes (element);
+ remove_base_attributes (WEBKIT_DOM_ELEMENT (first_child));
+ remove_evolution_attributes (WEBKIT_DOM_ELEMENT (first_child));
+ }
+ g_free (id);
+ }
+
+ /* Smileys */
+ list = webkit_dom_element_query_selector_all (
+ WEBKIT_DOM_ELEMENT (source), ".-x-evo-smiley-wrapper", NULL);
+ length = webkit_dom_node_list_get_length (list);
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMNode *node;
+ WebKitDOMElement *img;
+
+ node = webkit_dom_node_list_item (list, ii);
+ img = WEBKIT_DOM_ELEMENT (webkit_dom_node_get_first_child (node));
+
+ remove_evolution_attributes (img);
+ remove_base_attributes (img);
+
+ webkit_dom_node_replace_child (
+ webkit_dom_node_get_parent_node (node),
+ WEBKIT_DOM_NODE (img),
+ node,
+ NULL);
+
+ g_object_unref (node);
+ }
+ g_clear_object (&list);
+
+ collection = webkit_dom_element_get_elements_by_tag_name_as_html_collection (
+ WEBKIT_DOM_ELEMENT (source), "pre");
+ length = webkit_dom_html_collection_get_length (collection);
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMNode *node;
+
+ node = webkit_dom_html_collection_item (collection, ii);
+ remove_evolution_attributes (WEBKIT_DOM_ELEMENT (node));
+ g_object_unref (node);
+ }
+ g_clear_object (&collection);
+
+ list = webkit_dom_element_query_selector_all (
+ WEBKIT_DOM_ELEMENT (source), "p[data-evo-paragraph]", NULL);
+ length = webkit_dom_node_list_get_length (list);
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMNode *node;
+
+ node = webkit_dom_node_list_item (list, ii);
+ remove_evolution_attributes (WEBKIT_DOM_ELEMENT (node));
+ remove_base_attributes (WEBKIT_DOM_ELEMENT (node));
+ g_object_unref (node);
+ }
+ g_clear_object (&list);
+
+ list = webkit_dom_element_query_selector_all (
+ WEBKIT_DOM_ELEMENT (source), "br.-x-evo-wrap-br", NULL);
+ length = webkit_dom_node_list_get_length (list);
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMNode *node;
+
+ node = webkit_dom_node_list_item (list, ii);
+ webkit_dom_element_remove_attribute (WEBKIT_DOM_ELEMENT (node), "class");
+ g_object_unref (node);
+ }
+ g_clear_object (&list);
+}
+
+static void
+remove_image_attributes_from_element (WebKitDOMElement *element)
+{
+ webkit_dom_element_remove_attribute (element, "background");
+ webkit_dom_element_remove_attribute (element, "data-uri");
+ webkit_dom_element_remove_attribute (element, "data-inline");
+ webkit_dom_element_remove_attribute (element, "data-name");
+}
+
+static void
+remove_background_images_in_element (WebKitDOMElement *element)
+{
+ gint length, ii;
+ WebKitDOMNodeList *images = NULL;
+
+ images = webkit_dom_element_query_selector_all (
+ element, "[background][data-inline]", NULL);
+
+ length = webkit_dom_node_list_get_length (images);
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMElement *image = WEBKIT_DOM_ELEMENT (
+ webkit_dom_node_list_item (images, ii));
+
+ remove_image_attributes_from_element (image);
+ g_object_unref (image);
+ }
+ g_clear_object (&images);
+
+ remove_image_attributes_from_element (element);
+}
+
+static void
+remove_images_in_element (WebKitDOMElement *element)
+{
+ gint length, ii;
+ WebKitDOMNodeList *images = NULL;
+
+ images = webkit_dom_element_query_selector_all (
+ element, "img:not(.-x-evo-smiley-img)", NULL);
+
+ length = webkit_dom_node_list_get_length (images);
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMNode *node = webkit_dom_node_list_item (images, ii);
+ remove_node (node);
+ g_object_unref (node);
+ }
+ g_clear_object (&images);
+}
+
+static void
+remove_images (WebKitDOMDocument *document)
+{
+ remove_images_in_element (
+ WEBKIT_DOM_ELEMENT (webkit_dom_document_get_body (document)));
+}
+
+static void
+toggle_smileys (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMNodeList *smileys = NULL;
+ gboolean html_mode;
+ gint length;
+ gint ii;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+ html_mode = e_editor_page_get_html_mode (editor_page);
+
+ smileys = webkit_dom_document_query_selector_all (
+ document, "img.-x-evo-smiley-img", NULL);
+
+ length = webkit_dom_node_list_get_length (smileys);
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMNode *img = webkit_dom_node_list_item (smileys, ii);
+ WebKitDOMElement *parent = webkit_dom_node_get_parent_element (img);
+
+ if (html_mode)
+ element_add_class (parent, "-x-evo-resizable-wrapper");
+ else
+ element_remove_class (parent, "-x-evo-resizable-wrapper");
+ g_object_unref (img);
+ }
+ g_clear_object (&smileys);
+}
+
+static void
+toggle_paragraphs_style_in_element (EEditorPage *editor_page,
+ WebKitDOMElement *element,
+ gboolean html_mode)
+{
+ gint ii, length;
+ WebKitDOMNodeList *paragraphs = NULL;
+
+ paragraphs = webkit_dom_element_query_selector_all (
+ element, ":not(td) > [data-evo-paragraph]", NULL);
+
+ length = webkit_dom_node_list_get_length (paragraphs);
+
+ for (ii = 0; ii < length; ii++) {
+ gchar *style;
+ const gchar *css_align;
+ WebKitDOMNode *node = webkit_dom_node_list_item (paragraphs, ii);
+
+ if (html_mode) {
+ style = webkit_dom_element_get_attribute (
+ WEBKIT_DOM_ELEMENT (node), "style");
+
+ if (style && (css_align = strstr (style, "text-align: "))) {
+ webkit_dom_element_set_attribute (
+ WEBKIT_DOM_ELEMENT (node),
+ "style",
+ g_str_has_prefix (css_align + 12, "center") ?
+ "text-align: center" :
+ "text-align: right",
+ NULL);
+ } else {
+ /* In HTML mode the paragraphs don't have width limit */
+ webkit_dom_element_remove_attribute (
+ WEBKIT_DOM_ELEMENT (node), "style");
+ }
+ g_free (style);
+ } else {
+ WebKitDOMNode *parent;
+
+ parent = webkit_dom_node_get_parent_node (node);
+ /* If the paragraph is inside indented paragraph don't set
+ * the style as it will be inherited */
+ if (WEBKIT_DOM_IS_HTML_BODY_ELEMENT (parent) && node_is_list (node)) {
+ gint offset;
+
+ offset = WEBKIT_DOM_IS_HTML_U_LIST_ELEMENT (node) ?
+ SPACES_PER_LIST_LEVEL : SPACES_ORDERED_LIST_FIRST_LEVEL;
+ /* In plain text mode the paragraphs have width limit */
+ e_editor_dom_set_paragraph_style (
+ editor_page, WEBKIT_DOM_ELEMENT (node), -1, -offset, NULL);
+ } else if (!element_has_class (WEBKIT_DOM_ELEMENT (parent), "-x-evo-indented")) {
+ const gchar *style_to_add = "";
+ style = webkit_dom_element_get_attribute (
+ WEBKIT_DOM_ELEMENT (node), "style");
+
+ if (style && (css_align = strstr (style, "text-align: "))) {
+ style_to_add = g_str_has_prefix (
+ css_align + 12, "center") ?
+ "text-align: center;" :
+ "text-align: right;";
+ }
+
+ /* In plain text mode the paragraphs have width limit */
+ e_editor_dom_set_paragraph_style (
+ editor_page, WEBKIT_DOM_ELEMENT (node), -1, 0, style_to_add);
+
+ g_free (style);
+ }
+ }
+ g_object_unref (node);
+ }
+ g_clear_object (¶graphs);
+}
+
+static void
+toggle_paragraphs_style (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+
+ toggle_paragraphs_style_in_element (
+ editor_page,
+ WEBKIT_DOM_ELEMENT (webkit_dom_document_get_body (document)),
+ e_editor_page_get_html_mode (editor_page));
+}
+
+gchar *
+e_editor_dom_process_content_for_draft (EEditorPage *editor_page,
+ gboolean only_inner_body)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMHTMLElement *body;
+ WebKitDOMElement *document_element;
+ WebKitDOMNodeList *list = NULL;
+ WebKitDOMNode *document_element_clone;
+ gboolean selection_saved = FALSE;
+ gchar *content;
+ gint ii, length;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+ document = e_editor_page_get_document (editor_page);
+ body = webkit_dom_document_get_body (document);
+
+ webkit_dom_element_set_attribute (
+ WEBKIT_DOM_ELEMENT (body), "data-evo-draft", "", NULL);
+
+ if (webkit_dom_document_get_element_by_id (document, "-x-evo-selection-start-marker"))
+ selection_saved = TRUE;
+
+ if (!selection_saved)
+ e_editor_dom_selection_save (editor_page);
+
+ document_element = webkit_dom_document_get_document_element (document);
+
+ document_element_clone = webkit_dom_node_clone_node_with_error (
+ WEBKIT_DOM_NODE (document_element), TRUE, NULL);
+
+ list = webkit_dom_element_query_selector_all (
+ WEBKIT_DOM_ELEMENT (document_element_clone), "a.-x-evo-visited-link", NULL);
+ length = webkit_dom_node_list_get_length (list);
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMNode *anchor;
+
+ anchor = webkit_dom_node_list_item (list, ii);
+ webkit_dom_element_remove_attribute (WEBKIT_DOM_ELEMENT (anchor), "class");
+ g_object_unref (anchor);
+ }
+ g_clear_object (&list);
+
+ list = webkit_dom_element_query_selector_all (
+ WEBKIT_DOM_ELEMENT (document_element_clone), "#-x-evo-input-start", NULL);
+ length = webkit_dom_node_list_get_length (list);
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMNode *node;
+
+ node = webkit_dom_node_list_item (list, ii);
+ webkit_dom_element_remove_attribute (WEBKIT_DOM_ELEMENT (node), "id");
+ g_object_unref (node);
+ }
+ g_clear_object (&list);
+
+ if (only_inner_body) {
+ WebKitDOMElement *body;
+ WebKitDOMNode *first_child;
+
+ body = webkit_dom_element_query_selector (
+ WEBKIT_DOM_ELEMENT (document_element_clone), "body", NULL);
+
+ first_child = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (body));
+
+ if (!e_editor_page_get_html_mode (editor_page))
+ webkit_dom_element_set_attribute (
+ WEBKIT_DOM_ELEMENT (first_child),
+ "data-evo-signature-plain-text-mode",
+ "",
+ NULL);
+
+ content = webkit_dom_element_get_inner_html (body);
+
+ if (!e_editor_page_get_html_mode (editor_page))
+ webkit_dom_element_remove_attribute (
+ WEBKIT_DOM_ELEMENT (first_child),
+ "data-evo-signature-plain-text-mode");
+ } else
+ content = webkit_dom_element_get_outer_html (
+ WEBKIT_DOM_ELEMENT (document_element_clone));
+
+ webkit_dom_element_remove_attribute (
+ WEBKIT_DOM_ELEMENT (body), "data-evo-draft");
+
+ e_editor_dom_selection_restore (editor_page);
+ e_editor_dom_force_spell_check_in_viewport (editor_page);
+
+ if (selection_saved)
+ e_editor_dom_selection_save (editor_page);
+
+ return content;
+}
+
+static void
+toggle_indented_elements (EEditorPage *editor_page)
+{
+ gboolean html_mode;
+ gint ii, length;
+ WebKitDOMDocument *document;
+ WebKitDOMNodeList *list = NULL;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+ html_mode = e_editor_page_get_html_mode (editor_page);
+ list = webkit_dom_document_query_selector_all (document, ".-x-evo-indented", NULL);
+ length = webkit_dom_node_list_get_length (list);
+
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMNode *node = webkit_dom_node_list_item (list, ii);
+
+ if (html_mode)
+ dom_element_swap_attributes (WEBKIT_DOM_ELEMENT (node), "style",
"data-plain-text-style");
+ else
+ dom_element_swap_attributes (WEBKIT_DOM_ELEMENT (node), "data-plain-text-style",
"style");
+ g_object_unref (node);
+ }
+ g_clear_object (&list);
+}
+
+static void
+process_content_to_html_changing_composer_mode (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMNode *body;
+ WebKitDOMElement *blockquote;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+ body = WEBKIT_DOM_NODE (webkit_dom_document_get_body (document));
+
+ webkit_dom_element_remove_attribute (
+ WEBKIT_DOM_ELEMENT (body), "data-evo-plain-text");
+ blockquote = webkit_dom_document_query_selector (
+ document, "blockquote[type|=cite]", NULL);
+
+ if (blockquote)
+ dom_dequote_plain_text (document);
+
+ toggle_paragraphs_style (editor_page);
+ toggle_smileys (editor_page);
+ remove_images (document);
+ e_editor_dom_remove_wrapping_from_element (WEBKIT_DOM_ELEMENT (body));
+
+ process_node_to_html_changing_composer_mode (editor_page, body);
+}
+
+static void
+wrap_paragraphs_in_quoted_content (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMNodeList *paragraphs = NULL;
+ gint ii, length;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+ paragraphs = webkit_dom_document_query_selector_all (
+ document, "blockquote[type=cite] > [data-evo-paragraph]", NULL);
+
+ length = webkit_dom_node_list_get_length (paragraphs);
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMNode *paragraph;
+
+ paragraph = webkit_dom_node_list_item (paragraphs, ii);
+
+ e_editor_dom_wrap_paragraph (editor_page, WEBKIT_DOM_ELEMENT (paragraph));
+
+ g_object_unref (paragraph);
+ }
+ g_clear_object (¶graphs);
+}
+
+static void
+process_content_to_plain_text_changing_composer_mode (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMNode *body, *head, *node;
+ WebKitDOMElement *blockquote;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+ body = WEBKIT_DOM_NODE (webkit_dom_document_get_body (document));
+ head = WEBKIT_DOM_NODE (webkit_dom_document_get_head (document));
+
+ while ((node = webkit_dom_node_get_last_child (head)))
+ remove_node (node);
+
+ e_editor_dom_selection_save (editor_page);
+
+ webkit_dom_element_remove_attribute (
+ WEBKIT_DOM_ELEMENT (body), "data-user-colors");
+
+ webkit_dom_element_set_attribute (
+ WEBKIT_DOM_ELEMENT (body), "data-evo-plain-text", "", NULL);
+
+ blockquote = webkit_dom_document_query_selector (
+ document, "blockquote[type|=cite]", NULL);
+
+ if (blockquote) {
+ wrap_paragraphs_in_quoted_content (editor_page);
+ quote_plain_text_elements_after_wrapping_in_document (editor_page);
+ }
+
+ toggle_paragraphs_style (editor_page);
+ toggle_smileys (editor_page);
+ toggle_indented_elements (editor_page);
+ remove_images (document);
+ remove_background_images_in_element (WEBKIT_DOM_ELEMENT (body));
+
+ process_node_to_plain_text_changing_composer_mode (editor_page, body);
+
+ e_editor_dom_selection_restore (editor_page);
+ e_editor_dom_force_spell_check_in_viewport (editor_page);
+}
+
+gchar *
+e_editor_dom_process_content_to_plain_text_for_exporting (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMNode *body, *source;
+ WebKitDOMNodeList *list = NULL;
+ WebKitDOMDOMWindow *dom_window = NULL;
+ WebKitDOMDOMSelection *dom_selection = NULL;
+ gboolean wrap = FALSE, quote = FALSE, remove_last_new_line = FALSE;
+ gint length, ii;
+ GString *plain_text;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+ document = e_editor_page_get_document (editor_page);
+ plain_text = g_string_sized_new (1024);
+
+ body = WEBKIT_DOM_NODE (webkit_dom_document_get_body (document));
+ source = webkit_dom_node_clone_node_with_error (WEBKIT_DOM_NODE (body), TRUE, NULL);
+
+ e_editor_dom_selection_save (editor_page);
+
+ /* If composer is in HTML mode we have to move the content to plain version */
+ if (e_editor_page_get_html_mode (editor_page)) {
+ if (e_editor_dom_check_if_conversion_needed (editor_page)) {
+ WebKitDOMElement *wrapper;
+ WebKitDOMNode *child;
+
+ wrapper = webkit_dom_document_create_element (document, "div", NULL);
+ webkit_dom_element_set_id (wrapper, "-x-evo-html-to-plain-text-wrapper");
+ while ((child = webkit_dom_node_get_first_child (source))) {
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (wrapper),
+ child,
+ NULL);
+ }
+
+ list = webkit_dom_element_query_selector_all (
+ wrapper, "#-x-evo-input-start", NULL);
+
+ length = webkit_dom_node_list_get_length (list);
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMNode *paragraph;
+
+ paragraph = webkit_dom_node_list_item (list, ii);
+
+ webkit_dom_element_remove_attribute (
+ WEBKIT_DOM_ELEMENT (paragraph), "id");
+ }
+ g_clear_object (&list);
+
+ remove_images_in_element (wrapper);
+
+ list = webkit_dom_element_query_selector_all (
+ wrapper, "#-x-evo-html-to-plain-text-wrapper > :matches(ul, ol)", NULL);
+
+ length = webkit_dom_node_list_get_length (list);
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMElement *list_pre;
+ WebKitDOMNode *item;
+ GString *list_plain_text;
+
+ item = webkit_dom_node_list_item (list, ii);
+
+ list_plain_text = g_string_new ("");
+
+ process_list_to_plain_text (
+ editor_page, WEBKIT_DOM_ELEMENT (item), 1, list_plain_text);
+
+ list_pre = webkit_dom_document_create_element (document, "pre", NULL);
+ webkit_dom_html_element_set_inner_text (
+ WEBKIT_DOM_HTML_ELEMENT (list_pre),
+ g_string_free (list_plain_text, FALSE),
+ NULL);
+ webkit_dom_node_replace_child (
+ WEBKIT_DOM_NODE (wrapper),
+ WEBKIT_DOM_NODE (list_pre),
+ item,
+ NULL);
+ g_object_unref (item);
+ }
+ g_clear_object (&list);
+
+ convert_element_from_html_to_plain_text (
+ editor_page, wrapper, &wrap, "e);
+
+ source = WEBKIT_DOM_NODE (wrapper);
+
+ remove_last_new_line = TRUE;
+ } else {
+ toggle_paragraphs_style_in_element (
+ editor_page, WEBKIT_DOM_ELEMENT (source), FALSE);
+ remove_images_in_element (
+ WEBKIT_DOM_ELEMENT (source));
+ remove_background_images_in_element (
+ WEBKIT_DOM_ELEMENT (source));
+ }
+ }
+
+ list = webkit_dom_element_query_selector_all (
+ WEBKIT_DOM_ELEMENT (source), "[data-evo-paragraph]", NULL);
+
+ dom_window = webkit_dom_document_get_default_view (document);
+ dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+ webkit_dom_dom_selection_collapse_to_end (dom_selection, NULL);
+ g_clear_object (&dom_window);
+ g_clear_object (&dom_selection);
+
+ length = webkit_dom_node_list_get_length (list);
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMNode *paragraph;
+
+ paragraph = webkit_dom_node_list_item (list, ii);
+
+ if (node_is_list (paragraph)) {
+ WebKitDOMNode *item = webkit_dom_node_get_first_child (paragraph);
+
+ while (item) {
+ WebKitDOMNode *next_item =
+ webkit_dom_node_get_next_sibling (item);
+
+ if (WEBKIT_DOM_IS_HTML_LI_ELEMENT (item))
+ e_editor_dom_wrap_paragraph (editor_page, WEBKIT_DOM_ELEMENT (item));
+
+ item = next_item;
+ }
+ } else if (!webkit_dom_element_query_selector (WEBKIT_DOM_ELEMENT (paragraph),
".-x-evo-wrap-br,.-x-evo-quoted", NULL)) {
+ /* Dont't try to wrap the already wrapped content. */
+ e_editor_dom_wrap_paragraph (editor_page, WEBKIT_DOM_ELEMENT (paragraph));
+ }
+ g_object_unref (paragraph);
+ }
+ g_clear_object (&list);
+
+ list = webkit_dom_element_query_selector_all (
+ WEBKIT_DOM_ELEMENT (source), "#-x-evo-selection-start-marker, #-x-evo-selection-end-marker",
NULL);
+
+ length = webkit_dom_node_list_get_length (list);
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMNode *node = webkit_dom_node_list_item (list, ii);
+ WebKitDOMNode *parent = webkit_dom_node_get_parent_node (node);
+
+ remove_node (node);
+ g_object_unref (node);
+ webkit_dom_node_normalize (parent);
+ }
+ g_clear_object (&list);
+
+ if (quote)
+ quote_plain_text_recursive (document, source, source, 0);
+ else if (e_editor_page_get_html_mode (editor_page)) {
+ WebKitDOMElement *citation;
+
+ citation = webkit_dom_element_query_selector (
+ WEBKIT_DOM_ELEMENT (source), "blockquote[type=cite]", NULL);
+ if (citation)
+ quote_plain_text_recursive (document, source, source, 0);
+ }
+
+ process_node_to_plain_text_for_exporting (editor_page, source, plain_text);
+ /* Truncate the extra new line on the end of generated text as the
+ * check inside the previous function is based on whether the processed
+ * node is BODY or not, but in this case the content is wrapped in DIV. */
+ if (remove_last_new_line)
+ g_string_truncate (plain_text, plain_text->len - 1);
+
+ e_editor_dom_selection_restore (editor_page);
+
+ /* Return text content between <body> and </body> */
+ return g_string_free (plain_text, FALSE);
+}
+
+static void
+restore_image (WebKitDOMDocument *document,
+ const gchar *id,
+ const gchar *element_src)
+{
+ gchar *selector;
+ gint length, ii;
+ WebKitDOMNodeList *list = NULL;
+
+ selector = g_strconcat ("[data-inline][background=\"cid:", id, "\"]", NULL);
+ list = webkit_dom_document_query_selector_all (document, selector, NULL);
+ length = webkit_dom_node_list_get_length (list);
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMElement *element = WEBKIT_DOM_ELEMENT (
+ webkit_dom_node_list_item (list, ii));
+
+ webkit_dom_element_set_attribute (element, "background", element_src, NULL);
+ g_object_unref (element);
+ }
+ g_free (selector);
+ g_clear_object (&list);
+
+ selector = g_strconcat ("[data-inline][src=\"cid:", id, "\"]", NULL);
+ list = webkit_dom_document_query_selector_all (document, selector, NULL);
+ length = webkit_dom_node_list_get_length (list);
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMElement *element = WEBKIT_DOM_ELEMENT (
+ webkit_dom_node_list_item (list, ii));
+
+ webkit_dom_element_set_attribute (element, "src", element_src, NULL);
+ g_object_unref (element);
+ }
+ g_free (selector);
+ g_clear_object (&list);
+}
+
+void
+e_editor_dom_restore_images (EEditorPage *editor_page,
+ GVariant *inline_images_to_restore)
+{
+ WebKitDOMDocument *document;
+ const gchar *element_src, *name, *id;
+ GVariantIter *iter;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+
+ g_variant_get (inline_images_to_restore, "a(sss)", &iter);
+ while (g_variant_iter_loop (iter, "(&s&s&s)", &element_src, &name, &id))
+ restore_image (document, id, element_src);
+
+ g_variant_iter_free (iter);
+}
+
+gchar *
+e_editor_dom_process_content_to_html_for_exporting (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *element;
+ WebKitDOMNode *node, *document_clone;
+ WebKitDOMNodeList *list = NULL;
+ GSettings *settings;
+ gint ii, length;
+ gchar *html_content;
+ gboolean send_editor_colors = FALSE;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+ document = e_editor_page_get_document (editor_page);
+
+ document_clone = webkit_dom_node_clone_node_with_error (
+ WEBKIT_DOM_NODE (webkit_dom_document_get_document_element (document)), TRUE, NULL);
+ element = webkit_dom_element_query_selector (
+ WEBKIT_DOM_ELEMENT (document_clone), "style#-x-evo-quote-style", NULL);
+ if (element)
+ remove_node (WEBKIT_DOM_NODE (element));
+ element = webkit_dom_element_query_selector (
+ WEBKIT_DOM_ELEMENT (document_clone), "style#-x-evo-a-color-style", NULL);
+ if (element)
+ remove_node (WEBKIT_DOM_NODE (element));
+ element = webkit_dom_element_query_selector (
+ WEBKIT_DOM_ELEMENT (document_clone), "style#-x-evo-a-color-style-visited", NULL);
+ if (element)
+ remove_node (WEBKIT_DOM_NODE (element));
+ /* When the Ctrl + Enter is pressed for sending, the links are activated. */
+ element = webkit_dom_element_query_selector (
+ WEBKIT_DOM_ELEMENT (document_clone), "style#-x-evo-style-a", NULL);
+ if (element)
+ remove_node (WEBKIT_DOM_NODE (element));
+ node = WEBKIT_DOM_NODE (webkit_dom_element_query_selector (
+ WEBKIT_DOM_ELEMENT (document_clone), "body", NULL));
+ element = webkit_dom_element_query_selector (
+ WEBKIT_DOM_ELEMENT (node), "#-x-evo-selection-start-marker", NULL);
+ if (element)
+ remove_node (WEBKIT_DOM_NODE (element));
+ element = webkit_dom_element_query_selector (
+ WEBKIT_DOM_ELEMENT (node), "#-x-evo-selection-end-marker", NULL);
+ if (element)
+ remove_node (WEBKIT_DOM_NODE (element));
+
+ settings = e_util_ref_settings ("org.gnome.evolution.mail");
+ send_editor_colors = g_settings_get_boolean (settings, "composer-inherit-theme-colors");
+ g_object_unref (settings);
+
+ if (webkit_dom_element_has_attribute (WEBKIT_DOM_ELEMENT (node), "data-user-colors")) {
+ webkit_dom_element_remove_attribute (WEBKIT_DOM_ELEMENT (node), "data-user-colors");
+ } else if (!send_editor_colors) {
+ webkit_dom_element_remove_attribute (WEBKIT_DOM_ELEMENT (node), "bgcolor");
+ webkit_dom_element_remove_attribute (WEBKIT_DOM_ELEMENT (node), "text");
+ webkit_dom_element_remove_attribute (WEBKIT_DOM_ELEMENT (node), "link");
+ webkit_dom_element_remove_attribute (WEBKIT_DOM_ELEMENT (node), "vlink");
+ }
+
+ list = webkit_dom_element_query_selector_all (
+ WEBKIT_DOM_ELEMENT (node), "span[data-hidden-space]", NULL);
+ length = webkit_dom_node_list_get_length (list);
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMNode *hidden_space_node;
+
+ hidden_space_node = webkit_dom_node_list_item (list, ii);
+ remove_node (hidden_space_node);
+ g_object_unref (hidden_space_node);
+ }
+ g_clear_object (&list);
+
+ list = webkit_dom_element_query_selector_all (
+ WEBKIT_DOM_ELEMENT (node), "[data-style]", NULL);
+ length = webkit_dom_node_list_get_length (list);
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMNode *data_style_node;
+
+ data_style_node = webkit_dom_node_list_item (list, ii);
+
+ element_rename_attribute (WEBKIT_DOM_ELEMENT (data_style_node), "data-style", "style");
+ g_object_unref (data_style_node);
+ }
+ g_clear_object (&list);
+
+ process_node_to_html_for_exporting (editor_page, node);
+
+ html_content = webkit_dom_element_get_outer_html (
+ WEBKIT_DOM_ELEMENT (document_clone));
+
+ g_object_unref (document_clone);
+
+ return html_content;
+}
+
+void
+e_editor_dom_convert_when_changing_composer_mode (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMHTMLElement *body;
+ gboolean quote = FALSE, wrap = FALSE;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+ body = webkit_dom_document_get_body (document);
+
+ convert_element_from_html_to_plain_text (
+ editor_page, WEBKIT_DOM_ELEMENT (body), &wrap, "e);
+
+ if (wrap)
+ e_editor_dom_wrap_paragraphs_in_document (editor_page);
+
+ if (quote) {
+ e_editor_dom_selection_save (editor_page);
+ if (wrap)
+ quote_plain_text_elements_after_wrapping_in_document (editor_page);
+ else
+ body = WEBKIT_DOM_HTML_ELEMENT (dom_quote_plain_text (document));
+ e_editor_dom_selection_restore (editor_page);
+ }
+
+ toggle_paragraphs_style (editor_page);
+ toggle_smileys (editor_page);
+ remove_images (document);
+ remove_background_images_in_element (WEBKIT_DOM_ELEMENT (body));
+
+ clear_attributes (editor_page);
+
+ if (!e_editor_page_get_html_mode (editor_page))
+ webkit_dom_element_set_attribute (
+ WEBKIT_DOM_ELEMENT (body), "data-evo-plain-text", "", NULL);
+ else
+ webkit_dom_element_remove_attribute (
+ WEBKIT_DOM_ELEMENT (body), "data-evo-plain-text");
+
+ e_editor_dom_force_spell_check_in_viewport (editor_page);
+ e_editor_dom_scroll_to_caret (editor_page);
+}
+
+static void
+set_base64_to_element_attribute (GHashTable *inline_images,
+ WebKitDOMElement *element,
+ const gchar *attribute)
+{
+ gchar *attribute_value;
+ const gchar *base64_src;
+
+ attribute_value = webkit_dom_element_get_attribute (element, attribute);
+
+ if (attribute_value && (base64_src = g_hash_table_lookup (inline_images, attribute_value)) != NULL) {
+ const gchar *base64_data = strstr (base64_src, ";") + 1;
+ gchar *name;
+ glong name_length;
+
+ name_length =
+ g_utf8_strlen (base64_src, -1) -
+ g_utf8_strlen (base64_data, -1) - 1;
+ name = g_strndup (base64_src, name_length);
+
+ webkit_dom_element_set_attribute (element, "data-inline", "", NULL);
+ webkit_dom_element_set_attribute (element, "data-name", name, NULL);
+ webkit_dom_element_set_attribute (element, attribute, base64_data, NULL);
+
+ g_free (name);
+ }
+ g_free (attribute_value);
+}
+
+static void
+change_cid_images_src_to_base64 (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *document_element;
+ WebKitDOMNamedNodeMap *attributes = NULL;
+ WebKitDOMNodeList *list = NULL;
+ GHashTable *inline_images;
+ gint ii, length;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+ inline_images = e_editor_page_get_inline_images (editor_page);
+
+ document_element = webkit_dom_document_get_document_element (document);
+
+ list = webkit_dom_document_query_selector_all (document, "img[src^=\"cid:\"]", NULL);
+ length = webkit_dom_node_list_get_length (list);
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMNode *node = webkit_dom_node_list_item (list, ii);
+
+ set_base64_to_element_attribute (inline_images, WEBKIT_DOM_ELEMENT (node), "src");
+ g_object_unref (node);
+ }
+ g_clear_object (&list);
+
+ /* Namespaces */
+ attributes = webkit_dom_element_get_attributes (document_element);
+ length = webkit_dom_named_node_map_get_length (attributes);
+ for (ii = 0; ii < length; ii++) {
+ gchar *name;
+ WebKitDOMNode *node = webkit_dom_named_node_map_item (attributes, ii);
+
+ name = webkit_dom_node_get_local_name (node);
+
+ if (g_str_has_prefix (name, "xmlns:")) {
+ const gchar *ns = name + 6;
+ gchar *attribute_ns = g_strconcat (ns, ":src", NULL);
+ gchar *selector = g_strconcat ("img[", ns, "\\:src^=\"cid:\"]", NULL);
+ gint ns_length, jj;
+
+ list = webkit_dom_document_query_selector_all (
+ document, selector, NULL);
+ ns_length = webkit_dom_node_list_get_length (list);
+ for (jj = 0; jj < ns_length; jj++) {
+ WebKitDOMNode *node = webkit_dom_node_list_item (list, jj);
+
+ set_base64_to_element_attribute (
+ inline_images, WEBKIT_DOM_ELEMENT (node), attribute_ns);
+ g_object_unref (node);
+ }
+
+ g_clear_object (&list);
+ g_free (attribute_ns);
+ g_free (selector);
+ }
+ g_object_unref (node);
+ g_free (name);
+ }
+ g_clear_object (&attributes);
+
+ list = webkit_dom_document_query_selector_all (
+ document, "[background^=\"cid:\"]", NULL);
+ length = webkit_dom_node_list_get_length (list);
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMNode *node = webkit_dom_node_list_item (list, ii);
+
+ set_base64_to_element_attribute (
+ inline_images, WEBKIT_DOM_ELEMENT (node), "background");
+ g_object_unref (node);
+ }
+ g_clear_object (&list);
+}
+
+static void
+adapt_to_editor_dom_changes (WebKitDOMDocument *document)
+{
+ WebKitDOMHTMLCollection *collection = NULL;
+ gint ii, length;
+
+ /* Normal block code div.-x-evo-paragraph replaced by p[data-evo-paragraph] */
+ collection = webkit_dom_document_get_elements_by_class_name_as_html_collection (document,
"-x-evo-paragraph");
+ length = webkit_dom_html_collection_get_length (collection);
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMNode *node, *child;
+ WebKitDOMElement *element;
+ gchar *style;
+
+ node = webkit_dom_html_collection_item (collection, ii);
+ element = webkit_dom_document_create_element (document, "p", NULL);
+ webkit_dom_element_set_attribute (element, "data-evo-paragraph", "", NULL);
+
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (node),
+ WEBKIT_DOM_NODE (element),
+ node,
+ NULL);
+
+ while ((child = webkit_dom_node_get_first_child (node)))
+ webkit_dom_node_append_child (WEBKIT_DOM_NODE (element), child, NULL);
+
+ style = webkit_dom_element_get_attribute (WEBKIT_DOM_ELEMENT (node), "style");
+ if (style)
+ webkit_dom_element_set_attribute (element, "style", style, NULL);
+
+ remove_node (node);
+ g_object_unref (node);
+ }
+ g_clear_object (&collection);
+}
+
+void
+e_editor_dom_process_content_after_load (EEditorPage *editor_page)
+{
+ gboolean html_mode;
+ WebKitDOMDocument *document;
+ WebKitDOMHTMLElement *body;
+ WebKitDOMDOMWindow *dom_window = NULL;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+
+ /* Don't use CSS when possible to preserve compatibility with older
+ * versions of Evolution or other MUAs */
+ e_editor_dom_exec_command (editor_page, E_CONTENT_EDITOR_COMMAND_STYLE_WITH_CSS, "false");
+ e_editor_dom_exec_command (editor_page, E_CONTENT_EDITOR_COMMAND_DEFAULT_PARAGRAPH_SEPARATOR, "p");
+
+ body = webkit_dom_document_get_body (document);
+
+ webkit_dom_element_remove_attribute (WEBKIT_DOM_ELEMENT (body), "style");
+ html_mode = e_editor_page_get_html_mode (editor_page);
+ if (!html_mode)
+ webkit_dom_element_set_attribute (
+ WEBKIT_DOM_ELEMENT (body), "data-evo-plain-text", "", NULL);
+
+ if (e_editor_page_get_convert_in_situ (editor_page)) {
+ e_editor_dom_convert_content (editor_page, NULL);
+ /* Make the quote marks non-selectable. */
+ e_editor_dom_disable_quote_marks_select (editor_page);
+ dom_set_links_active (document, FALSE);
+ e_editor_page_set_convert_in_situ (editor_page, FALSE);
+
+ e_editor_dom_register_input_event_listener_on_body (editor_page);
+ register_html_events_handlers (editor_page, body);
+
+ return;
+ }
+
+ adapt_to_editor_dom_changes (document);
+
+ /* Make the quote marks non-selectable. */
+ e_editor_dom_disable_quote_marks_select (editor_page);
+ dom_set_links_active (document, FALSE);
+ put_body_in_citation (document);
+ move_elements_to_body (editor_page);
+ repair_gmail_blockquotes (document);
+ remove_thunderbird_signature (document);
+
+ if (webkit_dom_element_has_attribute (WEBKIT_DOM_ELEMENT (body), "data-evo-draft")) {
+ /* Restore the selection how it was when the draft was saved */
+ e_editor_dom_move_caret_into_element (editor_page, WEBKIT_DOM_ELEMENT (body), FALSE);
+ e_editor_dom_selection_restore (editor_page);
+ e_editor_dom_remove_embedded_style_sheet (editor_page);
+ }
+
+ /* The composer body could be empty in some case (loading an empty string
+ * or empty HTML. In that case create the initial paragraph. */
+ if (!webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (body))) {
+ WebKitDOMElement *paragraph;
+
+ paragraph = e_editor_dom_prepare_paragraph (editor_page, TRUE);
+ webkit_dom_element_set_id (paragraph, "-x-evo-input-start");
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (body), WEBKIT_DOM_NODE (paragraph), NULL);
+ e_editor_dom_selection_restore (editor_page);
+ }
+
+ /* Register on input event that is called when the content (body) is modified */
+ e_editor_dom_register_input_event_listener_on_body (editor_page);
+ register_html_events_handlers (editor_page, body);
+
+ e_editor_dom_fix_file_uri_images (editor_page);
+ change_cid_images_src_to_base64 (editor_page);
+
+ if (e_editor_page_get_inline_spelling_enabled (editor_page))
+ e_editor_dom_force_spell_check (editor_page);
+ else
+ e_editor_dom_turn_spell_check_off (editor_page);
+
+ e_editor_dom_set_monospace_font_family_on_body (
+ WEBKIT_DOM_ELEMENT (body), e_editor_page_get_html_mode (editor_page));
+
+ dom_window = webkit_dom_document_get_default_view (document);
+
+ webkit_dom_event_target_add_event_listener (
+ WEBKIT_DOM_EVENT_TARGET (dom_window),
+ "scroll",
+ G_CALLBACK (body_scroll_event_cb),
+ FALSE,
+ editor_page);
+
+ /* Intentionally leak the WebKitDOMDOMWindow object here as otherwise the
+ * callback won't be set up. */
+}
+
+GVariant *
+e_editor_dom_get_inline_images_data (EEditorPage *editor_page,
+ const gchar *uid_domain)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMNodeList *list = NULL;
+ GVariant *result = NULL;
+ GVariantBuilder *builder = NULL;
+ GHashTable *added = NULL;
+ gint length, ii;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+ document = e_editor_page_get_document (editor_page);
+ list = webkit_dom_document_query_selector_all (document, "img[data-inline]", NULL);
+
+ length = webkit_dom_node_list_get_length (list);
+ if (length == 0) {
+ g_clear_object (&list);
+ goto background;
+ }
+
+ builder = g_variant_builder_new (G_VARIANT_TYPE ("a(sss)"));
+
+ added = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+ for (ii = 0; ii < length; ii++) {
+ const gchar *id;
+ gchar *cid = NULL;
+ WebKitDOMNode *node = webkit_dom_node_list_item (list, ii);
+ gchar *src = webkit_dom_element_get_attribute (
+ WEBKIT_DOM_ELEMENT (node), "src");
+
+ if (!src)
+ continue;
+
+ if ((id = g_hash_table_lookup (added, src)) != NULL) {
+ cid = g_strdup_printf ("cid:%s", id);
+ g_free (src);
+ } else {
+ gchar *data_name = webkit_dom_element_get_attribute (
+ WEBKIT_DOM_ELEMENT (node), "data-name");
+
+ if (data_name) {
+ gchar *new_id;
+
+ new_id = camel_header_msgid_generate (uid_domain);
+ g_variant_builder_add (
+ builder, "(sss)", src, data_name, new_id);
+ cid = g_strdup_printf ("cid:%s", new_id);
+
+ g_hash_table_insert (added, src, new_id);
+ }
+ g_free (data_name);
+ }
+ webkit_dom_element_set_attribute (
+ WEBKIT_DOM_ELEMENT (node), "src", cid, NULL);
+ g_object_unref (node);
+ g_free (cid);
+ }
+ g_clear_object (&list);
+
+ background:
+ list = webkit_dom_document_query_selector_all (
+ document, "[data-inline][background]", NULL);
+ length = webkit_dom_node_list_get_length (list);
+ if (length == 0)
+ goto out;
+ if (!builder)
+ builder = g_variant_builder_new (G_VARIANT_TYPE ("a(sss)"));
+ if (!added)
+ added = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+
+ for (ii = 0; ii < length; ii++) {
+ const gchar *id;
+ gchar *cid = NULL;
+ WebKitDOMNode *node = webkit_dom_node_list_item (list, ii);
+ gchar *src = webkit_dom_element_get_attribute (
+ WEBKIT_DOM_ELEMENT (node), "background");
+
+ if (!src)
+ continue;
+
+ if ((id = g_hash_table_lookup (added, src)) != NULL) {
+ cid = g_strdup_printf ("cid:%s", id);
+ webkit_dom_element_set_attribute (
+ WEBKIT_DOM_ELEMENT (node), "background", cid, NULL);
+ g_free (src);
+ } else {
+ gchar *data_name = webkit_dom_element_get_attribute (
+ WEBKIT_DOM_ELEMENT (node), "data-name");
+
+ if (data_name) {
+ gchar *new_id;
+
+ new_id = camel_header_msgid_generate (uid_domain);
+ g_variant_builder_add (
+ builder, "(sss)", src, data_name, new_id);
+ cid = g_strdup_printf ("cid:%s", new_id);
+
+ g_hash_table_insert (added, src, new_id);
+
+ webkit_dom_element_set_attribute (
+ WEBKIT_DOM_ELEMENT (node), "background", cid, NULL);
+ }
+ g_free (data_name);
+ }
+ g_free (cid);
+ g_object_unref (node);
+ }
+ out:
+ g_clear_object (&list);
+ if (added)
+ g_hash_table_destroy (added);
+
+ if (builder) {
+ result = g_variant_new ("a(sss)", builder);
+ g_variant_builder_unref (builder);
+ }
+
+ return result;
+}
+
+static gboolean
+pasting_quoted_content (const gchar *content)
+{
+ /* Check if the content we are pasting is a quoted content from composer.
+ * If it is, we can't use WebKit to paste it as it would leave the formatting
+ * on the content. */
+ return g_str_has_prefix (
+ content,
+ "<meta http-equiv=\"content-type\" content=\"text/html; "
+ "charset=utf-8\"><blockquote type=\"cite\"") &&
+ strstr (content, "\"-x-evo-");
+}
+
+/*
+ * e_editor_dom_insert_html:
+ * @selection: an #EEditorSelection
+ * @html_text: an HTML code to insert
+ *
+ * Insert @html_text into document at current cursor position. When a text range
+ * is selected, it will be replaced by @html_text.
+ */
+void
+e_editor_dom_insert_html (EEditorPage *editor_page,
+ const gchar *html_text)
+{
+ WebKitDOMDocument *document;
+ EEditorHistoryEvent *ev = NULL;
+ EEditorUndoRedoManager *manager;
+ gboolean html_mode;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+ g_return_if_fail (html_text != NULL);
+
+ document = e_editor_page_get_document (editor_page);
+
+ manager = e_editor_page_get_undo_redo_manager (editor_page);
+ if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+ gboolean collapsed;
+
+ ev = g_new0 (EEditorHistoryEvent, 1);
+ ev->type = HISTORY_INSERT_HTML;
+
+ collapsed = e_editor_dom_selection_is_collapsed (editor_page);
+ e_editor_dom_selection_get_coordinates (editor_page,
+ &ev->before.start.x,
+ &ev->before.start.y,
+ &ev->before.end.x,
+ &ev->before.end.y);
+
+ if (!collapsed) {
+ ev->before.end.x = ev->before.start.x;
+ ev->before.end.y = ev->before.start.y;
+ }
+
+ ev->data.string.from = NULL;
+ ev->data.string.to = g_strdup (html_text);
+ }
+
+ html_mode = e_editor_page_get_html_mode (editor_page);
+ if (html_mode ||
+ (e_editor_page_is_pasting_content_from_itself (editor_page) &&
+ !pasting_quoted_content (html_text))) {
+ if (!e_editor_dom_selection_is_collapsed (editor_page)) {
+ EEditorHistoryEvent *event;
+ WebKitDOMDocumentFragment *fragment;
+ WebKitDOMRange *range = NULL;
+
+ event = g_new0 (EEditorHistoryEvent, 1);
+ event->type = HISTORY_DELETE;
+
+ range = e_editor_dom_get_current_range (editor_page);
+ fragment = webkit_dom_range_clone_contents (range, NULL);
+ g_clear_object (&range);
+ event->data.fragment = fragment;
+
+ e_editor_dom_selection_get_coordinates (editor_page,
+ &event->before.start.x,
+ &event->before.start.y,
+ &event->before.end.x,
+ &event->before.end.y);
+
+ event->after.start.x = event->before.start.x;
+ event->after.start.y = event->before.start.y;
+ event->after.end.x = event->before.start.x;
+ event->after.end.y = event->before.start.y;
+
+ e_editor_undo_redo_manager_insert_history_event (manager, event);
+
+ event = g_new0 (EEditorHistoryEvent, 1);
+ event->type = HISTORY_AND;
+
+ e_editor_undo_redo_manager_insert_history_event (manager, event);
+ }
+
+ e_editor_dom_exec_command (editor_page, E_CONTENT_EDITOR_COMMAND_INSERT_HTML, html_text);
+ e_editor_dom_fix_file_uri_images (editor_page);
+ if (strstr (html_text, "id=\"-x-evo-selection-start-marker\""))
+ e_editor_dom_selection_restore (editor_page);
+
+ if (!html_mode) {
+ WebKitDOMNodeList *list = NULL;
+ gint ii, length;
+
+ list = webkit_dom_document_query_selector_all (
+ document, "span[style^=font-family]", NULL);
+ length = webkit_dom_node_list_get_length (list);
+ if (length > 0)
+ e_editor_dom_selection_save (editor_page);
+
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMNode *span, *child;
+
+ span = webkit_dom_node_list_item (list, ii);
+ while ((child = webkit_dom_node_get_first_child (span)))
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (span),
+ child,
+ span,
+ NULL);
+
+ remove_node (span);
+ g_object_unref (span);
+ }
+ g_clear_object (&list);
+
+ if (length > 0)
+ e_editor_dom_selection_restore (editor_page);
+ }
+
+ e_editor_dom_check_magic_links (editor_page, FALSE);
+ e_editor_dom_force_spell_check (editor_page);
+ e_editor_dom_scroll_to_caret (editor_page);
+ } else
+ e_editor_dom_convert_and_insert_html_into_selection (editor_page, html_text, TRUE);
+
+ if (ev) {
+ e_editor_dom_selection_get_coordinates (editor_page,
+ &ev->after.start.x,
+ &ev->after.start.y,
+ &ev->after.end.x,
+ &ev->after.end.y);
+
+ e_editor_undo_redo_manager_insert_history_event (manager, ev);
+ }
+}
+
+static void
+save_history_for_delete_or_backspace (EEditorPage *editor_page,
+ gboolean delete_key,
+ gboolean control_key)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMDocumentFragment *fragment = NULL;
+ WebKitDOMDOMWindow *dom_window = NULL;
+ WebKitDOMDOMSelection *dom_selection = NULL;
+ WebKitDOMRange *range = NULL;
+ EEditorHistoryEvent *ev = NULL;
+ EEditorUndoRedoManager *manager;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+ dom_window = webkit_dom_document_get_default_view (document);
+ dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+ g_clear_object (&dom_window);
+
+ if (!webkit_dom_dom_selection_get_range_count (dom_selection)) {
+ g_clear_object (&dom_selection);
+ return;
+ }
+
+ range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+
+ /* Check if we can delete something */
+ if (webkit_dom_range_get_collapsed (range, NULL)) {
+ WebKitDOMRange *tmp_range = NULL;
+
+ webkit_dom_dom_selection_modify (
+ dom_selection, "move", delete_key ? "right" : "left", "character");
+
+ tmp_range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+ if (webkit_dom_range_compare_boundary_points (tmp_range, WEBKIT_DOM_RANGE_END_TO_END, range,
NULL) == 0) {
+ g_clear_object (&dom_selection);
+ g_clear_object (&range);
+ g_clear_object (&tmp_range);
+
+ return;
+ }
+
+ webkit_dom_dom_selection_modify (
+ dom_selection, "move", delete_key ? "left" : "right", "character");
+
+ g_clear_object (&tmp_range);
+ }
+
+ if (save_history_before_event_in_table (editor_page, range)) {
+ g_clear_object (&range);
+ g_clear_object (&dom_selection);
+ return;
+ }
+
+ ev = g_new0 (EEditorHistoryEvent, 1);
+ ev->type = HISTORY_DELETE;
+
+ e_editor_dom_selection_get_coordinates (editor_page, &ev->before.start.x, &ev->before.start.y,
&ev->before.end.x, &ev->before.end.y);
+ g_clear_object (&range);
+ range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+
+ if (webkit_dom_range_get_collapsed (range, NULL)) {
+ gboolean removing_from_anchor = FALSE;
+ WebKitDOMRange *range_clone = NULL;
+ WebKitDOMNode *node, *next_block = NULL;
+
+ e_editor_page_block_selection_changed (editor_page);
+
+ range_clone = webkit_dom_range_clone_range (range, NULL);
+ if (control_key) {
+ WebKitDOMRange *tmp_range = NULL;
+
+ /* Control + Delete/Backspace deletes previous/next word. */
+ webkit_dom_dom_selection_modify (
+ dom_selection, "move", delete_key ? "right" : "left", "word");
+ tmp_range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+ if (delete_key)
+ webkit_dom_range_set_end (
+ range_clone,
+ webkit_dom_range_get_end_container (tmp_range, NULL),
+ webkit_dom_range_get_end_offset (tmp_range, NULL),
+ NULL);
+ else
+ webkit_dom_range_set_start (
+ range_clone,
+ webkit_dom_range_get_start_container (tmp_range, NULL),
+ webkit_dom_range_get_start_offset (tmp_range, NULL),
+ NULL);
+ g_clear_object (&tmp_range);
+ } else {
+ typedef WebKitDOMNode * (*GetSibling)(WebKitDOMNode *node);
+ WebKitDOMNode *container, *sibling;
+ WebKitDOMElement *selection_marker;
+
+ GetSibling get_sibling = delete_key ?
+ webkit_dom_node_get_next_sibling :
+ webkit_dom_node_get_previous_sibling;
+
+ container = webkit_dom_range_get_end_container (range_clone, NULL);
+ sibling = get_sibling (container);
+
+ selection_marker = webkit_dom_document_get_element_by_id (
+ document,
+ delete_key ?
+ "-x-evo-selection-end-marker" :
+ "-x-evo-selection-start-marker");
+
+ if (selection_marker) {
+ WebKitDOMNode *tmp_sibling;
+
+ tmp_sibling = get_sibling (WEBKIT_DOM_NODE (selection_marker));
+ if (!tmp_sibling || (WEBKIT_DOM_IS_HTML_BR_ELEMENT (tmp_sibling) &&
+ !element_has_class (WEBKIT_DOM_ELEMENT (tmp_sibling), "-x-evo-wrap-br")))
+ sibling = WEBKIT_DOM_NODE (selection_marker);
+ }
+
+ if (e_editor_dom_is_selection_position_node (sibling)) {
+ if ((node = get_sibling (sibling)))
+ node = get_sibling (node);
+ if (node) {
+ if (WEBKIT_DOM_IS_ELEMENT (node) &&
+ webkit_dom_element_has_attribute (WEBKIT_DOM_ELEMENT (node),
"data-hidden-space")) {
+ fragment = webkit_dom_document_create_document_fragment
(document);
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (fragment),
+ WEBKIT_DOM_NODE (
+ webkit_dom_document_create_text_node
(document, " ")),
+ NULL);
+ } else if (delete_key) {
+ webkit_dom_range_set_start (
+ range_clone, node, 0, NULL);
+ webkit_dom_range_set_end (
+ range_clone, node, 1, NULL);
+ }
+ } else {
+ WebKitDOMRange *tmp_range = NULL, *actual_range = NULL;
+
+ actual_range = webkit_dom_dom_selection_get_range_at (dom_selection,
0, NULL);
+
+ webkit_dom_dom_selection_modify (
+ dom_selection, "move", delete_key ? "right" : "left",
"character");
+
+ tmp_range = webkit_dom_dom_selection_get_range_at (dom_selection, 0,
NULL);
+ if (webkit_dom_range_compare_boundary_points (tmp_range,
WEBKIT_DOM_RANGE_END_TO_END, actual_range, NULL) != 0) {
+ WebKitDOMNode *actual_block;
+ WebKitDOMNode *tmp_block;
+
+ actual_block = e_editor_dom_get_parent_block_node_from_child
(container);
+
+ tmp_block = delete_key ?
+ webkit_dom_range_get_end_container (tmp_range, NULL) :
+ webkit_dom_range_get_start_container (tmp_range,
NULL);
+ tmp_block = e_editor_dom_get_parent_block_node_from_child
(tmp_block);
+
+ webkit_dom_dom_selection_modify (
+ dom_selection, "move", delete_key ? "left" : "right",
"character");
+
+ if (tmp_block) {
+ fragment =
webkit_dom_document_create_document_fragment (document);
+ if (delete_key) {
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (fragment),
+ webkit_dom_node_clone_node_with_error
(actual_block, TRUE, NULL),
+ NULL);
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (fragment),
+ webkit_dom_node_clone_node_with_error
(tmp_block, TRUE, NULL),
+ NULL);
+ if (delete_key)
+ next_block = tmp_block;
+ } else {
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (fragment),
+ webkit_dom_node_clone_node_with_error
(tmp_block, TRUE, NULL),
+ NULL);
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (fragment),
+ webkit_dom_node_clone_node_with_error
(actual_block, TRUE, NULL),
+ NULL);
+ }
+ g_object_set_data (
+ G_OBJECT (fragment),
+ "history-concatenating-blocks",
+ GINT_TO_POINTER (1));
+ }
+ }
+ g_clear_object (&tmp_range);
+ g_clear_object (&actual_range);
+ }
+ } else {
+ glong offset;
+
+ /* FIXME This code is wrong for unicode smileys. */
+ offset = webkit_dom_range_get_start_offset (range_clone, NULL);
+
+ if (delete_key)
+ webkit_dom_range_set_end (
+ range_clone, container, offset + 1, NULL);
+ else
+ webkit_dom_range_set_start (
+ range_clone, container, offset - 1, NULL);
+
+ removing_from_anchor = WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (
+ webkit_dom_node_get_parent_node (container));
+ }
+ }
+
+
+ if (!fragment)
+ fragment = webkit_dom_range_clone_contents (range_clone, NULL);
+ if (removing_from_anchor)
+ g_object_set_data (
+ G_OBJECT (fragment),
+ "history-removing-from-anchor",
+ GINT_TO_POINTER (1));
+ node = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (fragment));
+ if (!node) {
+ g_free (ev);
+ e_editor_page_unblock_selection_changed (editor_page);
+ g_clear_object (&range);
+ g_clear_object (&range_clone);
+ g_clear_object (&dom_selection);
+ g_warning ("History event was not saved for %s key", delete_key ? "Delete" :
"Backspace");
+ return;
+ }
+
+ if (control_key) {
+ if (delete_key) {
+ ev->after.start.x = ev->before.start.x;
+ ev->after.start.y = ev->before.start.y;
+ ev->after.end.x = ev->before.end.x;
+ ev->after.end.y = ev->before.end.y;
+
+ webkit_dom_range_collapse (range_clone, TRUE, NULL);
+ webkit_dom_dom_selection_remove_all_ranges (dom_selection);
+ webkit_dom_dom_selection_add_range (dom_selection, range_clone);
+ } else {
+ gboolean selection_saved = FALSE;
+ WebKitDOMRange *tmp_range = NULL;
+
+ if (webkit_dom_document_get_element_by_id (document,
"-x-evo-selection-start-marker"))
+ selection_saved = TRUE;
+
+ if (selection_saved)
+ e_editor_dom_selection_restore (editor_page);
+
+ tmp_range = webkit_dom_range_clone_range (range_clone, NULL);
+ /* Prepare the selection to the right position after
+ * delete and save it. */
+ webkit_dom_range_collapse (range_clone, TRUE, NULL);
+ webkit_dom_dom_selection_remove_all_ranges (dom_selection);
+ webkit_dom_dom_selection_add_range (dom_selection, range_clone);
+ e_editor_dom_selection_get_coordinates (editor_page, &ev->after.start.x,
&ev->after.start.y, &ev->after.end.x, &ev->after.end.y);
+ /* Restore the selection where it was before the
+ * history event was saved. */
+ webkit_dom_range_collapse (tmp_range, FALSE, NULL);
+ webkit_dom_dom_selection_remove_all_ranges (dom_selection);
+ webkit_dom_dom_selection_add_range (dom_selection, tmp_range);
+ g_clear_object (&tmp_range);
+
+ if (selection_saved)
+ e_editor_dom_selection_save (editor_page);
+ }
+ } else {
+ gboolean selection_saved = FALSE;
+
+ if (webkit_dom_document_get_element_by_id (document, "-x-evo-selection-start-marker"))
+ selection_saved = TRUE;
+
+ if (selection_saved)
+ e_editor_dom_selection_restore (editor_page);
+
+ if (delete_key) {
+ e_editor_dom_selection_get_coordinates (editor_page, &ev->after.start.x,
&ev->after.start.y, &ev->after.end.x, &ev->after.end.y);
+ } else {
+ webkit_dom_dom_selection_modify (dom_selection, "move", "left", "character");
+ e_editor_dom_selection_get_coordinates (editor_page, &ev->after.start.x,
&ev->after.start.y, &ev->after.end.x, &ev->after.end.y);
+ webkit_dom_dom_selection_modify (dom_selection, "move", "right", "character");
+
+ ev->after.end.x = ev->after.start.x;
+ ev->after.end.y = ev->after.start.y;
+ }
+
+ if (selection_saved)
+ e_editor_dom_selection_save (editor_page);
+ }
+
+ g_clear_object (&range_clone);
+
+ if (delete_key) {
+ if (!WEBKIT_DOM_IS_ELEMENT (node)) {
+ webkit_dom_node_insert_before (
+ WEBKIT_DOM_NODE (fragment),
+ WEBKIT_DOM_NODE (
+ dom_create_selection_marker (document, FALSE)),
+ webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (fragment)),
+ NULL);
+ webkit_dom_node_insert_before (
+ WEBKIT_DOM_NODE (fragment),
+ WEBKIT_DOM_NODE (
+ dom_create_selection_marker (document, TRUE)),
+ webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (fragment)),
+ NULL);
+ }
+ } else {
+ if (!WEBKIT_DOM_IS_ELEMENT (node)) {
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (fragment),
+ WEBKIT_DOM_NODE (
+ dom_create_selection_marker (document, TRUE)),
+ NULL);
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (fragment),
+ WEBKIT_DOM_NODE (
+ dom_create_selection_marker (document, FALSE)),
+ NULL);
+ }
+ }
+
+ /* If concatenating two blocks with pressing Delete on the end
+ * of the previous one and the next node contain content that
+ * is wrapped on multiple lines, the last line will by separated
+ * by WebKit to the separate block. To avoid it let's remove
+ * all quoting and wrapping from the next paragraph. */
+ if (next_block) {
+ e_editor_dom_remove_wrapping_from_element (WEBKIT_DOM_ELEMENT (next_block));
+ e_editor_dom_remove_quoting_from_element (WEBKIT_DOM_ELEMENT (next_block));
+ }
+
+ e_editor_page_unblock_selection_changed (editor_page);
+ } else {
+ WebKitDOMElement *tmp_element;
+ WebKitDOMNode *sibling;
+
+ ev->after.start.x = ev->before.start.x;
+ ev->after.start.y = ev->before.start.y;
+ ev->after.end.x = ev->before.start.x;
+ ev->after.end.y = ev->before.start.y;
+
+ fragment = webkit_dom_range_clone_contents (range, NULL);
+
+ tmp_element = webkit_dom_document_fragment_query_selector (
+ fragment, "#-x-evo-selection-start-marker", NULL);
+ if (tmp_element)
+ remove_node (WEBKIT_DOM_NODE (tmp_element));
+
+ tmp_element = webkit_dom_document_fragment_query_selector (
+ fragment, "#-x-evo-selection-end-marker", NULL);
+ if (tmp_element)
+ remove_node (WEBKIT_DOM_NODE (tmp_element));
+
+ /* If any empty blockquote is presented, remove it. */
+ tmp_element = webkit_dom_document_query_selector (
+ document, "blockquote[type=cite]:empty", NULL);
+ if (tmp_element)
+ remove_node (WEBKIT_DOM_NODE (tmp_element));
+
+ /* Selection starts in the beginning of blockquote. */
+ tmp_element = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-start-marker");
+ sibling = webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (tmp_element));
+ if (sibling && WEBKIT_DOM_IS_ELEMENT (sibling) &&
+ element_has_class (WEBKIT_DOM_ELEMENT (sibling), "-x-evo-quoted")) {
+ WebKitDOMNode *child;
+
+ tmp_element = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-end-marker");
+
+ /* If there is no text after the selection end it means that
+ * the block will be replaced with block that is body's descendant
+ * and not the blockquote's one. Also if the selection started
+ * in the beginning of blockquote we have to insert the quote
+ * characters into the deleted content to correctly restore
+ * them during undo/redo operations. */
+ if (!(tmp_element && webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE
(tmp_element)))) {
+ child = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (fragment));
+ while (child && WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (child))
+ child = webkit_dom_node_get_first_child (child);
+
+ child = webkit_dom_node_get_first_child (child);
+ if (child && (WEBKIT_DOM_IS_TEXT (child) ||
+ (WEBKIT_DOM_IS_ELEMENT (child) &&
+ !element_has_class (WEBKIT_DOM_ELEMENT (child), "-x-evo-quoted")))) {
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (child),
+ webkit_dom_node_clone_node_with_error (sibling, TRUE, NULL),
+ child,
+ NULL);
+ }
+ }
+ }
+
+ /* When we were cloning the range above and the range contained
+ * quoted content there will still be blockquote missing in the
+ * final range. Let's modify the fragment and add it there. */
+ tmp_element = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-end-marker");
+ if (tmp_element) {
+ WebKitDOMNode *node;
+
+ node = WEBKIT_DOM_NODE (tmp_element);
+ while (!WEBKIT_DOM_IS_HTML_BODY_ELEMENT (webkit_dom_node_get_parent_node (node)))
+ node = webkit_dom_node_get_parent_node (node);
+
+ if (node && WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (node)) {
+ WebKitDOMNode *last_child;
+
+ last_child = webkit_dom_node_get_last_child (WEBKIT_DOM_NODE (fragment));
+
+ if (last_child && !WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (last_child)) {
+ WebKitDOMDocumentFragment *tmp_fragment;
+ WebKitDOMNode *clone;
+
+ tmp_fragment = webkit_dom_document_create_document_fragment
(document);
+ clone = webkit_dom_node_clone_node_with_error (node, FALSE, NULL);
+ clone = webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (tmp_fragment), clone, NULL);
+ webkit_dom_node_append_child (clone, WEBKIT_DOM_NODE (fragment),
NULL);
+ fragment = tmp_fragment;
+ }
+ }
+ }
+
+ /* FIXME Ugly hack */
+ /* If the deleted selection contained the signature (or at least its
+ * part) replace it with the unchanged signature to correctly perform
+ * undo operation. */
+ tmp_element = webkit_dom_document_fragment_query_selector (fragment,
".-x-evo-signature-wrapper", NULL);
+ if (tmp_element) {
+ WebKitDOMElement *signature;
+
+ signature = webkit_dom_document_query_selector (document,
".-x-evo-signature-wrapper", NULL);
+ if (signature) {
+ webkit_dom_node_replace_child (
+ webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (tmp_element)),
+ webkit_dom_node_clone_node_with_error (WEBKIT_DOM_NODE (signature),
TRUE, NULL),
+ WEBKIT_DOM_NODE (tmp_element),
+ NULL);
+ }
+ }
+ }
+
+ g_clear_object (&range);
+ g_clear_object (&dom_selection);
+
+ g_object_set_data (G_OBJECT (fragment), "history-delete-key", GINT_TO_POINTER (delete_key));
+ g_object_set_data (G_OBJECT (fragment), "history-control-key", GINT_TO_POINTER (control_key));
+
+ ev->data.fragment = fragment;
+
+ manager = e_editor_page_get_undo_redo_manager (editor_page);
+ e_editor_undo_redo_manager_insert_history_event (manager, ev);
+}
+
+gboolean
+e_editor_dom_fix_structure_after_delete_before_quoted_content (EEditorPage *editor_page,
+ glong key_code,
+ gboolean control_key,
+ gboolean delete_key)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *selection_start_marker, *selection_end_marker;
+ WebKitDOMNode *block, *node;
+ gboolean collapsed = FALSE;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+ document = e_editor_page_get_document (editor_page);
+ collapsed = e_editor_dom_selection_is_collapsed (editor_page);
+
+ e_editor_dom_selection_save (editor_page);
+
+ selection_start_marker = webkit_dom_document_query_selector (
+ document, "span#-x-evo-selection-start-marker", NULL);
+ selection_end_marker = webkit_dom_document_query_selector (
+ document, "span#-x-evo-selection-end-marker", NULL);
+
+ if (!selection_start_marker || !selection_end_marker)
+ return FALSE;
+
+ if (collapsed) {
+ WebKitDOMNode *next_block;
+
+ block = e_editor_dom_get_parent_block_node_from_child (
+ WEBKIT_DOM_NODE (selection_start_marker));
+
+ next_block = webkit_dom_node_get_next_sibling (block);
+
+ /* Next block is quoted content */
+ if (!WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (next_block))
+ goto restore;
+
+ /* Delete was pressed in block without any content */
+ if (webkit_dom_node_get_previous_sibling (WEBKIT_DOM_NODE (selection_start_marker)))
+ goto restore;
+
+ /* If there is just BR element go ahead */
+ node = webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (selection_end_marker));
+ if (node && !WEBKIT_DOM_IS_HTML_BR_ELEMENT (node))
+ goto restore;
+ else {
+ if (key_code != ~0)
+ save_history_for_delete_or_backspace (
+ editor_page, key_code == HTML_KEY_CODE_DELETE, control_key);
+
+ /* Remove the empty block and move caret to the right place. */
+ remove_node (block);
+
+ if (delete_key) {
+ /* To the beginning of the next block. */
+ e_editor_dom_move_caret_into_element (editor_page, WEBKIT_DOM_ELEMENT
(next_block), TRUE);
+ } else {
+ WebKitDOMNode *prev_block;
+
+ /* On the end of previous block. */
+ prev_block = webkit_dom_node_get_previous_sibling (next_block);
+ while (prev_block && WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (prev_block))
+ prev_block = webkit_dom_node_get_last_child (prev_block);
+
+ if (prev_block)
+ e_editor_dom_move_caret_into_element (editor_page, WEBKIT_DOM_ELEMENT
(prev_block), FALSE);
+ }
+
+ return TRUE;
+ }
+ } else {
+ WebKitDOMNode *end_block, *parent;
+
+ /* Let the quote marks be selectable to nearly correctly remove the
+ * selection. Corrections after are done in body_keyup_event_cb. */
+ enable_quote_marks_select (document);
+
+ parent = webkit_dom_node_get_parent_node (
+ WEBKIT_DOM_NODE (selection_start_marker));
+ if (WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (parent) ||
+ element_has_tag (WEBKIT_DOM_ELEMENT (parent), "b") ||
+ element_has_tag (WEBKIT_DOM_ELEMENT (parent), "i") ||
+ element_has_tag (WEBKIT_DOM_ELEMENT (parent), "u"))
+ node = webkit_dom_node_get_previous_sibling (parent);
+ else
+ node = webkit_dom_node_get_previous_sibling (
+ WEBKIT_DOM_NODE (selection_start_marker));
+
+ if (!node || !WEBKIT_DOM_IS_ELEMENT (node))
+ goto restore;
+
+ if (!element_has_class (WEBKIT_DOM_ELEMENT (node), "-x-evo-quoted"))
+ goto restore;
+
+ block = e_editor_dom_get_parent_block_node_from_child (
+ WEBKIT_DOM_NODE (selection_start_marker));
+ end_block = e_editor_dom_get_parent_block_node_from_child (
+ WEBKIT_DOM_NODE (selection_end_marker));
+
+ /* Situation where the start of the selection is in the beginning
+ + * of the block in quoted content and the end in the beginning of
+ + * content that is after the citation or the selection end is in
+ + * the end of the quoted content (showed by ^). We have to
+ + * mark the start block to correctly restore the structure
+ + * afterwards.
+ *
+ * > |xxx
+ * > xxx^
+ * |xxx
+ */
+ if (e_editor_dom_get_citation_level (end_block, FALSE) > 0) {
+ WebKitDOMNode *parent;
+
+ if (webkit_dom_node_get_next_sibling (end_block))
+ goto restore;
+
+ parent = webkit_dom_node_get_parent_node (end_block);
+ while (parent && WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (parent)) {
+ WebKitDOMNode *next_parent = webkit_dom_node_get_parent_node (parent);
+
+ if (webkit_dom_node_get_next_sibling (parent) &&
+ !WEBKIT_DOM_IS_HTML_BODY_ELEMENT (next_parent))
+ goto restore;
+
+ parent = next_parent;
+ }
+ }
+ }
+
+ restore:
+ if (key_code != ~0)
+ save_history_for_delete_or_backspace (
+ editor_page, key_code == HTML_KEY_CODE_DELETE, control_key);
+
+ e_editor_dom_selection_restore (editor_page);
+
+ return FALSE;
+}
+
+static gboolean
+split_citation (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *element;
+ EEditorHistoryEvent *ev = NULL;
+ EEditorUndoRedoManager *manager;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+ document = e_editor_page_get_document (editor_page);
+ manager = e_editor_page_get_undo_redo_manager (editor_page);
+
+ if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+ WebKitDOMElement *selection_end;
+ WebKitDOMNode *sibling;
+
+ ev = g_new0 (EEditorHistoryEvent, 1);
+ ev->type = HISTORY_CITATION_SPLIT;
+
+ e_editor_dom_selection_save (editor_page);
+
+ e_editor_dom_selection_get_coordinates (editor_page, &ev->before.start.x,
&ev->before.start.y, &ev->before.end.x, &ev->before.end.y);
+
+ if (!e_editor_dom_selection_is_collapsed (editor_page)) {
+ WebKitDOMRange *range = NULL;
+
+ range = e_editor_dom_get_current_range (editor_page);
+ insert_delete_event (editor_page, range);
+
+ g_clear_object (&range);
+
+ ev->before.end.x = ev->before.start.x;
+ ev->before.end.y = ev->before.start.y;
+ }
+
+ selection_end = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-end-marker");
+
+ sibling = webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (selection_end));
+ if (!sibling || (WEBKIT_DOM_IS_HTML_BR_ELEMENT (sibling) &&
+ !element_has_class (WEBKIT_DOM_ELEMENT (sibling), "-x-evo-wrap-br"))) {
+ WebKitDOMDocumentFragment *fragment;
+
+ fragment = webkit_dom_document_create_document_fragment (document);
+ ev->data.fragment = fragment;
+ } else
+ ev->data.fragment = NULL;
+
+ e_editor_dom_selection_restore (editor_page);
+ }
+
+ element = e_editor_dom_insert_new_line_into_citation (editor_page, "");
+
+ if (ev) {
+ e_editor_dom_selection_get_coordinates (editor_page, &ev->after.start.x, &ev->after.start.y,
&ev->after.end.x, &ev->after.end.y);
+
+ e_editor_undo_redo_manager_insert_history_event (manager, ev);
+ }
+
+ return element != NULL;
+}
+
+static gboolean
+delete_last_character_from_previous_line_in_quoted_block (EEditorPage *editor_page,
+ glong key_code,
+ guint state)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMDocumentFragment *fragment = NULL;
+ WebKitDOMElement *element;
+ WebKitDOMNode *node, *beginning, *prev_sibling;
+ EEditorHistoryEvent *ev = NULL;
+ gboolean hidden_space = FALSE;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+ /* We have to be in quoted content. */
+ if (!e_editor_dom_selection_is_citation (editor_page))
+ return FALSE;
+
+ /* Selection is just caret. */
+ if (!e_editor_dom_selection_is_collapsed (editor_page))
+ return FALSE;
+
+ document = e_editor_page_get_document (editor_page);
+
+ e_editor_dom_selection_save (editor_page);
+
+ element = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-start-marker");
+
+ /* Before the caret are just quote characters */
+ beginning = webkit_dom_node_get_previous_sibling (WEBKIT_DOM_NODE (element));
+ if (!(beginning && WEBKIT_DOM_IS_ELEMENT (beginning))) {
+ WebKitDOMNode *parent;
+
+ parent = webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element));
+ if (WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (parent))
+ beginning = webkit_dom_node_get_previous_sibling (parent);
+ else
+ goto out;
+ }
+
+ /* Before the text is the beginning of line. */
+ if (!(element_has_class (WEBKIT_DOM_ELEMENT (beginning), "-x-evo-quoted")))
+ goto out;
+
+ /* If we are just on the beginning of the line and not on the beginning of
+ * the block we need to remove the last character ourselves as well, otherwise
+ * WebKit will put the caret to wrong position. */
+ if (!(prev_sibling = webkit_dom_node_get_previous_sibling (beginning)))
+ goto out;
+
+ if (key_code != ~0) {
+ ev = g_new0 (EEditorHistoryEvent, 1);
+ ev->type = HISTORY_DELETE;
+
+ e_editor_dom_selection_get_coordinates (editor_page,
+ &ev->before.start.x,
+ &ev->before.start.y,
+ &ev->before.end.x,
+ &ev->before.end.y);
+
+ fragment = webkit_dom_document_create_document_fragment (document);
+ }
+
+ if (WEBKIT_DOM_IS_HTML_BR_ELEMENT (prev_sibling)) {
+ if (key_code != ~0)
+ webkit_dom_node_append_child (WEBKIT_DOM_NODE (fragment), prev_sibling, NULL);
+ else
+ remove_node (prev_sibling);
+ }
+
+ prev_sibling = webkit_dom_node_get_previous_sibling (beginning);
+ if (WEBKIT_DOM_IS_ELEMENT (prev_sibling) &&
+ webkit_dom_element_has_attribute (WEBKIT_DOM_ELEMENT (prev_sibling), "data-hidden-space")) {
+ hidden_space = TRUE;
+ if (key_code != ~0)
+ webkit_dom_node_insert_before (
+ WEBKIT_DOM_NODE (fragment),
+ prev_sibling,
+ webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (fragment)),
+ NULL);
+ else
+ remove_node (prev_sibling);
+ }
+
+ node = webkit_dom_node_get_previous_sibling (beginning);
+
+ if (key_code != ~0)
+ webkit_dom_node_append_child (WEBKIT_DOM_NODE (fragment), beginning, NULL);
+ else
+ remove_node (beginning);
+
+ if (!hidden_space) {
+ if (key_code != ~0) {
+ gchar *data;
+
+ data = webkit_dom_character_data_substring_data (
+ WEBKIT_DOM_CHARACTER_DATA (node),
+ webkit_dom_character_data_get_length (
+ WEBKIT_DOM_CHARACTER_DATA (node)) -1,
+ 1,
+ NULL);
+
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (fragment),
+ WEBKIT_DOM_NODE (
+ webkit_dom_document_create_text_node (document, data)),
+ NULL);
+
+ g_free (data);
+ }
+
+ webkit_dom_character_data_delete_data (
+ WEBKIT_DOM_CHARACTER_DATA (node),
+ webkit_dom_character_data_get_length (
+ WEBKIT_DOM_CHARACTER_DATA (node)) -1,
+ 1,
+ NULL);
+ }
+
+ if (key_code != ~0) {
+ EEditorUndoRedoManager *manager;
+
+ e_editor_dom_selection_get_coordinates (editor_page,
+ &ev->after.start.x,
+ &ev->after.start.y,
+ &ev->after.end.x,
+ &ev->after.end.y);
+
+ ev->data.fragment = fragment;
+
+ manager = e_editor_page_get_undo_redo_manager (editor_page);
+ e_editor_undo_redo_manager_insert_history_event (manager, ev);
+ }
+
+ e_editor_dom_selection_restore (editor_page);
+
+ return TRUE;
+ out:
+ e_editor_dom_selection_restore (editor_page);
+
+ return FALSE;
+}
+
+gboolean
+e_editor_dom_delete_last_character_on_line_in_quoted_block (EEditorPage *editor_page,
+ glong key_code,
+ gboolean control_key)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *element;
+ WebKitDOMNode *node, *beginning, *next_sibling;
+ gboolean success = FALSE;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+ document = e_editor_page_get_document (editor_page);
+
+ /* We have to be in quoted content. */
+ if (!e_editor_dom_selection_is_citation (editor_page))
+ return FALSE;
+
+ /* Selection is just caret. */
+ if (!e_editor_dom_selection_is_collapsed (editor_page))
+ return FALSE;
+
+ e_editor_dom_selection_save (editor_page);
+
+ element = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-start-marker");
+
+ /* selection end marker */
+ node = webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (element));
+
+ /* We have to be on the end of line. */
+ next_sibling = webkit_dom_node_get_next_sibling (node);
+ if (next_sibling &&
+ (!WEBKIT_DOM_IS_HTML_BR_ELEMENT (next_sibling) ||
+ webkit_dom_node_get_next_sibling (next_sibling)))
+ goto out;
+
+ /* Before the caret is just text. */
+ node = webkit_dom_node_get_previous_sibling (WEBKIT_DOM_NODE (element));
+ if (!(node && WEBKIT_DOM_IS_TEXT (node)))
+ goto out;
+
+ /* There is just one character. */
+ if (webkit_dom_character_data_get_length (WEBKIT_DOM_CHARACTER_DATA (node)) != 1)
+ goto out;
+
+ beginning = webkit_dom_node_get_previous_sibling (WEBKIT_DOM_NODE (node));
+ if (!(beginning && WEBKIT_DOM_IS_ELEMENT (beginning)))
+ goto out;
+
+ /* Before the text is the beginning of line. */
+ if (!(element_has_class (WEBKIT_DOM_ELEMENT (beginning), "-x-evo-quoted")))
+ goto out;
+
+ if (!webkit_dom_node_get_previous_sibling (beginning))
+ goto out;
+
+ if (key_code != ~0)
+ save_history_for_delete_or_backspace (
+ editor_page, key_code == HTML_KEY_CODE_DELETE, control_key);
+
+ element = webkit_dom_node_get_parent_element (beginning);
+ remove_node (WEBKIT_DOM_NODE (element));
+
+ success = TRUE;
+ out:
+ e_editor_dom_selection_restore (editor_page);
+
+ if (success)
+ e_editor_dom_insert_new_line_into_citation (editor_page, NULL);
+
+ return success;
+}
+
+static gboolean
+selection_is_in_empty_list_item (WebKitDOMNode *selection_start_marker)
+{
+ gchar *text;
+ WebKitDOMNode *sibling;
+
+ /* Selection needs to be collapsed. */
+ sibling = webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (selection_start_marker));
+ if (!e_editor_dom_is_selection_position_node (sibling))
+ return FALSE;
+
+ /* After the selection end there could be just the BR element. */
+ sibling = webkit_dom_node_get_next_sibling (sibling);
+ if (sibling && !WEBKIT_DOM_IS_HTML_BR_ELEMENT (sibling))
+ return FALSE;
+
+ if (sibling && webkit_dom_node_get_next_sibling (sibling))
+ return FALSE;
+
+ sibling = webkit_dom_node_get_previous_sibling (WEBKIT_DOM_NODE (selection_start_marker));
+
+ if (!sibling)
+ return TRUE;
+
+ /* Only text node with the zero width space character is allowed. */
+ if (!WEBKIT_DOM_IS_TEXT (sibling))
+ return FALSE;
+
+ if (webkit_dom_node_get_previous_sibling (sibling))
+ return FALSE;
+
+ if (webkit_dom_character_data_get_length (WEBKIT_DOM_CHARACTER_DATA (sibling)) != 1)
+ return FALSE;
+
+ text = webkit_dom_character_data_get_data (WEBKIT_DOM_CHARACTER_DATA (sibling));
+ if (!(text && g_strcmp0 (text, UNICODE_ZERO_WIDTH_SPACE) == 0)) {
+ g_free (text);
+ return FALSE;
+ }
+
+ g_free (text);
+
+ return TRUE;
+}
+
+static gboolean
+return_pressed_in_image_wrapper (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMDocumentFragment *fragment;
+ WebKitDOMElement *selection_start_marker;
+ WebKitDOMNode *parent, *block, *clone;
+ EEditorHistoryEvent *ev = NULL;
+ EEditorUndoRedoManager *manager;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+ document = e_editor_page_get_document (editor_page);
+
+ if (!e_editor_dom_selection_is_collapsed (editor_page))
+ return FALSE;
+
+ e_editor_dom_selection_save (editor_page);
+
+ selection_start_marker = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-start-marker");
+
+ parent = webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (selection_start_marker));
+ if (!element_has_class (WEBKIT_DOM_ELEMENT (parent), "-x-evo-resizable-wrapper")) {
+ e_editor_dom_selection_restore (editor_page);
+ return FALSE;
+ }
+
+ manager = e_editor_page_get_undo_redo_manager (editor_page);
+
+ if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+ ev = g_new0 (EEditorHistoryEvent, 1);
+ ev->type = HISTORY_INPUT;
+
+ e_editor_dom_selection_get_coordinates (editor_page,
+ &ev->before.start.x,
+ &ev->before.start.y,
+ &ev->before.end.x,
+ &ev->before.end.y);
+
+ fragment = webkit_dom_document_create_document_fragment (document);
+
+ g_object_set_data (
+ G_OBJECT (fragment), "history-return-key", GINT_TO_POINTER (1));
+ }
+
+ block = e_editor_dom_get_parent_block_node_from_child (
+ WEBKIT_DOM_NODE (selection_start_marker));
+
+ clone = webkit_dom_node_clone_node_with_error (block, FALSE, NULL);
+ webkit_dom_node_append_child (
+ clone, WEBKIT_DOM_NODE (webkit_dom_document_create_element (document, "br", NULL)), NULL);
+
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (block),
+ clone,
+ block,
+ NULL);
+
+ if (ev) {
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (fragment),
+ webkit_dom_node_clone_node_with_error (clone, TRUE, NULL),
+ NULL);
+
+ e_editor_dom_selection_get_coordinates (editor_page,
+ &ev->after.start.x,
+ &ev->after.start.y,
+ &ev->after.end.x,
+ &ev->after.end.y);
+
+ ev->data.fragment = fragment;
+
+ e_editor_undo_redo_manager_insert_history_event (manager, ev);
+ }
+
+ e_editor_page_emit_content_changed (editor_page);
+
+ e_editor_dom_selection_restore (editor_page);
+
+ return TRUE;
+}
+
+static gboolean
+return_pressed_after_h_rule (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMDocumentFragment *fragment;
+ WebKitDOMElement *selection_marker;
+ WebKitDOMNode *node, *block, *clone, *hr, *insert_before = NULL;
+ EEditorHistoryEvent *ev = NULL;
+ EEditorUndoRedoManager *manager;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+ document = e_editor_page_get_document (editor_page);
+
+ if (!e_editor_dom_selection_is_collapsed (editor_page))
+ return FALSE;
+
+ e_editor_dom_selection_save (editor_page);
+
+ manager = e_editor_page_get_undo_redo_manager (editor_page);
+
+ if (e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+ selection_marker = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-end-marker");
+
+ hr = webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (selection_marker));
+ hr = webkit_dom_node_get_next_sibling (hr);
+ node = webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (selection_marker));
+ if (node && !WEBKIT_DOM_IS_HTML_BR_ELEMENT (node) &&
+ !WEBKIT_DOM_IS_HTML_HR_ELEMENT (hr)) {
+ e_editor_dom_selection_restore (editor_page);
+ return FALSE;
+ }
+
+ insert_before = webkit_dom_node_get_next_sibling (hr);
+ } else {
+ selection_marker = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-start-marker");
+
+ node = webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (selection_marker));
+ hr = webkit_dom_node_get_previous_sibling (WEBKIT_DOM_NODE (selection_marker));
+ if (!WEBKIT_DOM_IS_HTML_BODY_ELEMENT (node) ||
+ !WEBKIT_DOM_IS_HTML_HR_ELEMENT (hr)) {
+ e_editor_dom_selection_restore (editor_page);
+ return FALSE;
+ }
+
+ insert_before = WEBKIT_DOM_NODE (selection_marker);
+
+ ev = g_new0 (EEditorHistoryEvent, 1);
+ ev->type = HISTORY_INPUT;
+
+ e_editor_dom_selection_get_coordinates (editor_page,
+ &ev->before.start.x,
+ &ev->before.start.y,
+ &ev->before.end.x,
+ &ev->before.end.y);
+
+ fragment = webkit_dom_document_create_document_fragment (document);
+
+ g_object_set_data (
+ G_OBJECT (fragment), "history-return-key", GINT_TO_POINTER (1));
+ }
+
+ block = webkit_dom_node_get_previous_sibling (hr);
+
+ clone = webkit_dom_node_clone_node_with_error (block, FALSE, NULL);
+
+ webkit_dom_node_append_child (
+ clone, WEBKIT_DOM_NODE (webkit_dom_document_create_element (document, "br", NULL)), NULL);
+
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (hr), clone, insert_before, NULL);
+
+ dom_remove_selection_markers (document);
+
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (clone),
+ WEBKIT_DOM_NODE (
+ dom_create_selection_marker (document, TRUE)),
+ NULL);
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (clone),
+ WEBKIT_DOM_NODE (
+ dom_create_selection_marker (document, FALSE)),
+ NULL);
+
+ if (ev) {
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (fragment),
+ webkit_dom_node_clone_node_with_error (clone, TRUE, NULL),
+ NULL);
+
+ e_editor_dom_selection_get_coordinates (editor_page,
+ &ev->after.start.x,
+ &ev->after.start.y,
+ &ev->after.end.x,
+ &ev->after.end.y);
+
+ ev->data.fragment = fragment;
+
+ e_editor_undo_redo_manager_insert_history_event (manager, ev);
+ }
+
+ e_editor_page_emit_content_changed (editor_page);
+
+ e_editor_dom_selection_restore (editor_page);
+
+ return TRUE;
+}
+
+gboolean
+e_editor_dom_return_pressed_in_empty_list_item (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *selection_start_marker;
+ WebKitDOMNode *parent;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+ document = e_editor_page_get_document (editor_page);
+
+ if (!e_editor_dom_selection_is_collapsed (editor_page))
+ return FALSE;
+
+ e_editor_dom_selection_save (editor_page);
+
+ selection_start_marker = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-start-marker");
+
+ parent = webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (selection_start_marker));
+ if (!WEBKIT_DOM_IS_HTML_LI_ELEMENT (parent)) {
+ e_editor_dom_selection_restore (editor_page);
+ return FALSE;
+ }
+
+ if (selection_is_in_empty_list_item (WEBKIT_DOM_NODE (selection_start_marker))) {
+ EEditorHistoryEvent *ev = NULL;
+ EEditorUndoRedoManager *manager;
+ WebKitDOMDocumentFragment *fragment;
+ WebKitDOMElement *paragraph;
+ WebKitDOMNode *list;
+
+ manager = e_editor_page_get_undo_redo_manager (editor_page);
+
+ if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+ ev = g_new0 (EEditorHistoryEvent, 1);
+ ev->type = HISTORY_INPUT;
+
+ e_editor_dom_selection_get_coordinates (editor_page,
+ &ev->before.start.x,
+ &ev->before.start.y,
+ &ev->before.end.x,
+ &ev->before.end.y);
+
+ fragment = webkit_dom_document_create_document_fragment (document);
+
+ g_object_set_data (
+ G_OBJECT (fragment), "history-return-key", GINT_TO_POINTER (1));
+ }
+
+ list = split_list_into_two (parent, -1);
+
+ if (ev) {
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (fragment),
+ parent,
+ NULL);
+ } else {
+ remove_node (parent);
+ }
+
+ paragraph = e_editor_dom_prepare_paragraph (editor_page, TRUE);
+
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (list),
+ WEBKIT_DOM_NODE (paragraph),
+ list,
+ NULL);
+
+ remove_node_if_empty (list);
+
+ if (ev) {
+ e_editor_dom_selection_get_coordinates (editor_page,
+ &ev->after.start.x,
+ &ev->after.start.y,
+ &ev->after.end.x,
+ &ev->after.end.y);
+
+ ev->data.fragment = fragment;
+
+ e_editor_undo_redo_manager_insert_history_event (manager, ev);
+ }
+
+ e_editor_dom_selection_restore (editor_page);
+
+ e_editor_page_emit_content_changed (editor_page);
+
+ return TRUE;
+ }
+
+ e_editor_dom_selection_restore (editor_page);
+
+ return FALSE;
+}
+
+static void
+process_smiley_on_delete_or_backspace (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *element;
+ WebKitDOMNode *parent;
+ gboolean in_smiley = FALSE;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+ e_editor_dom_selection_save (editor_page);
+ element = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-start-marker");
+
+ parent = webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element));
+ if (WEBKIT_DOM_IS_ELEMENT (parent) &&
+ element_has_class (WEBKIT_DOM_ELEMENT (parent), "-x-evo-smiley-text"))
+ in_smiley = TRUE;
+ else {
+ if (e_editor_dom_selection_is_collapsed (editor_page)) {
+ WebKitDOMNode *prev_sibling;
+
+ prev_sibling = webkit_dom_node_get_previous_sibling (WEBKIT_DOM_NODE (element));
+ if (prev_sibling && WEBKIT_DOM_IS_TEXT (prev_sibling)) {
+ gchar *text = webkit_dom_character_data_get_data (
+ WEBKIT_DOM_CHARACTER_DATA (prev_sibling));
+
+ if (g_strcmp0 (text, UNICODE_ZERO_WIDTH_SPACE) == 0) {
+ WebKitDOMNode *prev_prev_sibling;
+
+ prev_prev_sibling = webkit_dom_node_get_previous_sibling
(prev_sibling);
+ if (WEBKIT_DOM_IS_ELEMENT (prev_prev_sibling) &&
+ element_has_class (WEBKIT_DOM_ELEMENT (prev_prev_sibling),
"-x-evo-smiley-wrapper")) {
+ remove_node (prev_sibling);
+ in_smiley = TRUE;
+ parent = webkit_dom_node_get_last_child (prev_prev_sibling);
+ }
+ }
+
+ g_free (text);
+ }
+ } else {
+ element = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-end-marker");
+
+ parent = webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element));
+ if (WEBKIT_DOM_IS_ELEMENT (parent) &&
+ element_has_class (WEBKIT_DOM_ELEMENT (parent), "-x-evo-smiley-text"))
+ in_smiley = TRUE;
+ }
+ }
+
+ if (in_smiley) {
+ WebKitDOMNode *wrapper;
+
+ wrapper = webkit_dom_node_get_parent_node (parent);
+ if (!e_editor_page_get_html_mode (editor_page)) {
+ WebKitDOMNode *child;
+
+ while ((child = webkit_dom_node_get_first_child (parent)))
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (wrapper),
+ child,
+ wrapper,
+ NULL);
+ }
+ /* In the HTML mode the whole smiley will be removed. */
+ remove_node (wrapper);
+ /* FIXME history will be probably broken here */
+ }
+
+ e_editor_dom_selection_restore (editor_page);
+}
+
+gboolean
+e_editor_dom_key_press_event_process_return_key (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMNode *table = NULL;
+ gboolean first_cell = FALSE;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+ document = e_editor_page_get_document (editor_page);
+ /* Return pressed in the beginning of the first cell will insert
+ * new block before the table (and move the caret there) if none
+ * is already there, otherwise it will act as normal return. */
+ if (selection_is_in_table (document, &first_cell, &table) && first_cell) {
+ WebKitDOMNode *node;
+
+ node = webkit_dom_node_get_previous_sibling (table);
+ if (!node) {
+ node = webkit_dom_node_get_next_sibling (table);
+ node = webkit_dom_node_clone_node_with_error (node, FALSE, NULL);
+ webkit_dom_node_append_child (
+ node,
+ WEBKIT_DOM_NODE (webkit_dom_document_create_element (
+ document, "br", NULL)),
+ NULL);
+ dom_add_selection_markers_into_element_start (
+ document, WEBKIT_DOM_ELEMENT (node), NULL, NULL);
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (table),
+ node,
+ table,
+ NULL);
+ e_editor_dom_selection_restore (editor_page);
+ e_editor_page_emit_content_changed (editor_page);
+ return TRUE;
+ }
+ }
+
+ /* When user presses ENTER in a citation block, WebKit does
+ * not break the citation automatically, so we need to use
+ * the special command to do it. */
+ if (e_editor_dom_selection_is_citation (editor_page)) {
+ e_editor_dom_remove_input_event_listener_from_body (editor_page);
+ if (split_citation (editor_page)) {
+ e_editor_page_set_return_key_pressed (editor_page, TRUE);
+ e_editor_dom_check_magic_links (editor_page, FALSE);
+ e_editor_page_set_return_key_pressed (editor_page, FALSE);
+ e_editor_page_emit_content_changed (editor_page);
+
+ return TRUE;
+ }
+ return FALSE;
+ }
+
+ /* If the ENTER key is pressed inside an empty list item then the list
+ * is broken into two and empty paragraph is inserted between lists. */
+ if (e_editor_dom_return_pressed_in_empty_list_item (editor_page))
+ return TRUE;
+
+ if (return_pressed_in_image_wrapper (editor_page))
+ return TRUE;
+
+ if (return_pressed_after_h_rule (editor_page))
+ return TRUE;
+
+ return FALSE;
+}
+
+static gboolean
+remove_empty_bulleted_list_item (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *selection_start;
+ WebKitDOMNode *parent;
+ EEditorUndoRedoManager *manager;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+ document = e_editor_page_get_document (editor_page);
+ manager = e_editor_page_get_undo_redo_manager (editor_page);
+ e_editor_dom_selection_save (editor_page);
+
+ selection_start = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-start-marker");
+
+ parent = webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (selection_start));
+ while (parent && !node_is_list_or_item (parent))
+ parent = webkit_dom_node_get_parent_node (parent);
+
+ if (!parent)
+ goto out;
+
+ if (selection_is_in_empty_list_item (WEBKIT_DOM_NODE (selection_start))) {
+ EEditorHistoryEvent *ev = NULL;
+ WebKitDOMDocumentFragment *fragment;
+ WebKitDOMNode *prev_item;
+
+ prev_item = webkit_dom_node_get_previous_sibling (parent);
+
+ if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+ /* Insert new history event for Return to have the right coordinates.
+ * The fragment will be added later. */
+ ev = g_new0 (EEditorHistoryEvent, 1);
+ ev->type = HISTORY_DELETE;
+
+ e_editor_dom_selection_get_coordinates (editor_page,
+ &ev->before.start.x,
+ &ev->before.start.y,
+ &ev->before.end.x,
+ &ev->before.end.y);
+
+ fragment = webkit_dom_document_create_document_fragment (document);
+ }
+
+ if (ev) {
+ if (prev_item)
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (fragment),
+ webkit_dom_node_clone_node_with_error (prev_item, TRUE, NULL),
+ NULL);
+
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (fragment),
+ parent,
+ NULL);
+ } else
+ remove_node (parent);
+
+ if (prev_item)
+ dom_add_selection_markers_into_element_end (
+ document, WEBKIT_DOM_ELEMENT (prev_item), NULL, NULL);
+
+ if (ev) {
+ e_editor_dom_selection_get_coordinates (editor_page,
+ &ev->after.start.x,
+ &ev->after.start.y,
+ &ev->after.end.x,
+ &ev->after.end.y);
+
+ ev->data.fragment = fragment;
+
+ e_editor_undo_redo_manager_insert_history_event (manager, ev);
+ }
+
+ e_editor_page_emit_content_changed (editor_page);
+ e_editor_dom_selection_restore (editor_page);
+
+ return TRUE;
+ }
+ out:
+ e_editor_dom_selection_restore (editor_page);
+
+ return FALSE;
+}
+
+gboolean
+e_editor_dom_key_press_event_process_backspace_key (EEditorPage *editor_page)
+{
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+ /* BackSpace pressed in the beginning of quoted content changes
+ * format to normal and inserts text into body */
+ if (e_editor_dom_selection_is_collapsed (editor_page)) {
+ e_editor_dom_selection_save (editor_page);
+ if (e_editor_dom_move_quoted_block_level_up (editor_page) || delete_hidden_space
(editor_page)) {
+ e_editor_dom_selection_restore (editor_page);
+ e_editor_dom_force_spell_check_for_current_paragraph (editor_page);
+ e_editor_page_emit_content_changed (editor_page);
+ return TRUE;
+ }
+ e_editor_dom_selection_restore (editor_page);
+ }
+
+ /* BackSpace in indented block decrease indent level by one */
+ if (e_editor_dom_selection_is_indented (editor_page) &&
+ e_editor_dom_selection_is_collapsed (editor_page)) {
+ WebKitDOMDocument *document;
+ WebKitDOMElement *selection_start;
+ WebKitDOMNode *prev_sibling;
+
+ document = e_editor_page_get_document (editor_page);
+
+ e_editor_dom_selection_save (editor_page);
+ selection_start = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-start-marker");
+
+ /* Empty text node before caret */
+ prev_sibling = webkit_dom_node_get_previous_sibling (
+ WEBKIT_DOM_NODE (selection_start));
+ if (prev_sibling && WEBKIT_DOM_IS_TEXT (prev_sibling))
+ if (webkit_dom_character_data_get_length (WEBKIT_DOM_CHARACTER_DATA (prev_sibling))
== 0)
+ prev_sibling = webkit_dom_node_get_previous_sibling (prev_sibling);
+
+ e_editor_dom_selection_restore (editor_page);
+ if (!prev_sibling) {
+ e_editor_dom_selection_unindent (editor_page);
+ e_editor_page_emit_content_changed (editor_page);
+ return TRUE;
+ }
+ }
+
+ /* BackSpace pressed in an empty item in the bulleted list removes it. */
+ if (!e_editor_page_get_html_mode (editor_page) && e_editor_dom_selection_is_collapsed (editor_page) &&
+ remove_empty_bulleted_list_item (editor_page))
+ return TRUE;
+
+
+ if (prevent_from_deleting_last_element_in_body (e_editor_page_get_document (editor_page)))
+ return TRUE;
+
+ return FALSE;
+}
+
+gboolean
+e_editor_dom_key_press_event_process_delete_or_backspace_key (EEditorPage *editor_page,
+ glong key_code,
+ gboolean control_key,
+ gboolean delete)
+{
+ WebKitDOMDocument *document;
+ gboolean html_mode;
+ gboolean local_delete;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+ document = e_editor_page_get_document (editor_page);
+ html_mode = e_editor_page_get_html_mode (editor_page);
+ local_delete = (key_code == HTML_KEY_CODE_DELETE) || delete;
+
+ if (e_editor_page_get_magic_smileys_enabled (editor_page)) {
+ /* If deleting something in a smiley it won't be a smiley
+ * anymore (at least from Evolution' POV), so remove all
+ * the elements that are hidden in the wrapper and leave
+ * just the text. Also this ensures that when a smiley is
+ * recognized and we press the BackSpace key we won't delete
+ * the UNICODE_HIDDEN_SPACE, but we will correctly delete
+ * the last character of smiley. */
+ process_smiley_on_delete_or_backspace (editor_page);
+ }
+
+ if (!local_delete && !html_mode &&
+ e_editor_dom_delete_last_character_on_line_in_quoted_block (editor_page, key_code, control_key))
+ goto out;
+
+ if (!local_delete && !html_mode &&
+ delete_last_character_from_previous_line_in_quoted_block (editor_page, key_code, control_key))
+ goto out;
+
+ if (e_editor_dom_fix_structure_after_delete_before_quoted_content (editor_page, key_code,
control_key, FALSE))
+ goto out;
+
+ if (local_delete) {
+ WebKitDOMElement *selection_start_marker;
+ WebKitDOMNode *sibling, *block, *next_block;
+
+ /* This needs to be performed just in plain text mode
+ * and when the selection is collapsed. */
+ if (html_mode || !e_editor_dom_selection_is_collapsed (editor_page))
+ return FALSE;
+
+ e_editor_dom_selection_save (editor_page);
+
+ selection_start_marker = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-start-marker");
+ sibling = webkit_dom_node_get_previous_sibling (
+ WEBKIT_DOM_NODE (selection_start_marker));
+ /* Check if the key was pressed in the beginning of block. */
+ if (!(sibling && WEBKIT_DOM_IS_ELEMENT (sibling) &&
+ element_has_class (WEBKIT_DOM_ELEMENT (sibling), "-x-evo-quoted"))) {
+ e_editor_dom_selection_restore (editor_page);
+ return FALSE;
+ }
+
+ sibling = webkit_dom_node_get_next_sibling (
+ WEBKIT_DOM_NODE (selection_start_marker));
+ sibling = webkit_dom_node_get_next_sibling (sibling);
+
+ /* And also the current block was empty. */
+ if (!(!sibling || (sibling && WEBKIT_DOM_IS_HTML_BR_ELEMENT (sibling) &&
+ !element_has_class (WEBKIT_DOM_ELEMENT (sibling), "-x-evo-wrap-br")))) {
+ e_editor_dom_selection_restore (editor_page);
+ return FALSE;
+ }
+
+ block = e_editor_dom_get_parent_block_node_from_child (
+ WEBKIT_DOM_NODE (selection_start_marker));
+ next_block = webkit_dom_node_get_next_sibling (block);
+
+ remove_node (block);
+
+ e_editor_dom_move_caret_into_element (editor_page, WEBKIT_DOM_ELEMENT (next_block), TRUE);
+
+ goto out;
+ } else {
+ /* Concatenating a non-quoted block with Backspace key to the
+ * previous block that is inside a quoted content. */
+ WebKitDOMElement *selection_start_marker;
+ WebKitDOMNode *node, *block, *prev_block, *last_child, *child;
+
+ if (html_mode || !e_editor_dom_selection_is_collapsed (editor_page) ||
+ e_editor_dom_selection_is_citation (editor_page))
+ return FALSE;
+
+ e_editor_dom_selection_save (editor_page);
+
+ selection_start_marker = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-start-marker");
+
+ node = webkit_dom_node_get_previous_sibling (WEBKIT_DOM_NODE (selection_start_marker));
+ if (node) {
+ e_editor_dom_selection_restore (editor_page);
+ return FALSE;
+ }
+
+ remove_empty_blocks (document);
+
+ block = e_editor_dom_get_parent_block_node_from_child (
+ WEBKIT_DOM_NODE (selection_start_marker));
+
+ prev_block = webkit_dom_node_get_previous_sibling (block);
+ if (!prev_block || !WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (prev_block)) {
+ e_editor_dom_selection_restore (editor_page);
+ return FALSE;
+ }
+
+ last_child = webkit_dom_node_get_last_child (prev_block);
+ while (last_child && WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (last_child))
+ last_child = webkit_dom_node_get_last_child (last_child);
+
+ if (!last_child) {
+ e_editor_dom_selection_restore (editor_page);
+ return FALSE;
+ }
+
+ e_editor_dom_remove_wrapping_from_element (WEBKIT_DOM_ELEMENT (last_child));
+ e_editor_dom_remove_quoting_from_element (WEBKIT_DOM_ELEMENT (last_child));
+
+ node = webkit_dom_node_get_last_child (last_child);
+ if (WEBKIT_DOM_IS_HTML_BR_ELEMENT (node))
+ remove_node (node);
+
+ while ((child = webkit_dom_node_get_first_child (block)))
+ webkit_dom_node_append_child (last_child, child, NULL);
+
+ remove_node (block);
+
+ if (WEBKIT_DOM_IS_ELEMENT (last_child))
+ e_editor_dom_wrap_and_quote_element (editor_page, WEBKIT_DOM_ELEMENT (last_child));
+
+ e_editor_dom_selection_restore (editor_page);
+
+ goto out;
+ }
+
+ return FALSE;
+ out:
+ e_editor_dom_force_spell_check_for_current_paragraph (editor_page);
+ e_editor_page_emit_content_changed (editor_page);
+
+ return TRUE;
+}
+
+static gboolean
+contains_forbidden_elements (WebKitDOMDocument *document)
+{
+ WebKitDOMElement *body, *element;
+
+ body = WEBKIT_DOM_ELEMENT (webkit_dom_document_get_body (document));
+
+ /* Try to find disallowed elements in the plain text mode */
+ element = webkit_dom_element_query_selector (
+ body,
+ ":not("
+ /* Basic elements used as blocks allowed in the plain text mode */
+ "p[data-evo-paragraph], pre, ul, ol, li, blockquote[type=cite], "
+ /* Other elements */
+ "br, a, "
+ /* Indented elements */
+ ".-x-evo-indented, "
+ /* Signature */
+ ".-x-evo-signature-wrapper, .-x-evo-signature, "
+ /* Smileys */
+ ".-x-evo-smiley-wrapper, .-x-evo-smiley-img, .-x-evo-smiley-text, "
+ /* Selection markers */
+ "#-x-evo-selection-start-marker, #-x-evo-selection-end-marker"
+ ")",
+ NULL);
+
+ if (element)
+ return TRUE;
+
+ /* Try to find disallowed elements relationship in the plain text */
+ element = webkit_dom_element_query_selector (
+ body,
+ ":not("
+ /* Body descendants */
+ "body > :matches(blockquote[type=cite], .-x-evo-signature-wrapper), "
+ /* Main blocks and indented blocks */
+ ":matches(body, .-x-evo-indented) > :matches(pre, p, ul, ol, .-x-evo-indented), "
+ /* Blockquote descendants */
+ "blockquote[type=cite] > :matches(pre, p, blockquote[type=cite]), "
+ /* Block descendants */
+ ":matches(pre, p, li) > :matches(br, span, a), "
+ /* Lists */
+ ":matches(ul, ol) > :matches(ul, ol, li), "
+ /* Smileys */
+ ".-x-evo-smiley-wrapper > :matches(.-x-evo-smiley-img, .-x-evo-smiley-text), "
+ /* Signature */
+ ".-x-evo-signature-wrapper > .-x-evo-signature"
+ ")",
+ NULL);
+
+ return element ? TRUE : FALSE;
+}
+
+gboolean
+e_editor_dom_check_if_conversion_needed (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ gboolean html_mode, convert = FALSE;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+ document = e_editor_page_get_document (editor_page);
+ html_mode = e_editor_page_get_html_mode (editor_page);
+
+ if (html_mode)
+ convert = contains_forbidden_elements (document);
+
+ return convert;
+}
+
+void
+e_editor_dom_process_content_after_mode_change (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ EEditorUndoRedoManager *manager;
+ gboolean html_mode;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+ html_mode = e_editor_page_get_html_mode (editor_page);
+
+ if (html_mode)
+ process_content_to_html_changing_composer_mode (editor_page);
+ else
+ process_content_to_plain_text_changing_composer_mode (editor_page);
+
+ e_editor_dom_set_monospace_font_family_on_body (
+ WEBKIT_DOM_ELEMENT (webkit_dom_document_get_body (document)), html_mode);
+
+ manager = e_editor_page_get_undo_redo_manager (editor_page);
+ e_editor_undo_redo_manager_clean_history (manager);
+}
+
+guint
+e_editor_dom_get_caret_offset (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMDOMWindow *dom_window = NULL;
+ WebKitDOMDOMSelection *dom_selection = NULL;
+ WebKitDOMNode *anchor;
+ WebKitDOMRange *range = NULL;
+ guint ret_val;
+ gchar *text;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), 0);
+
+ document = e_editor_page_get_document (editor_page);
+ dom_window = webkit_dom_document_get_default_view (document);
+ dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+ g_clear_object (&dom_window);
+
+ if (webkit_dom_dom_selection_get_range_count (dom_selection) < 1) {
+ g_clear_object (&dom_selection);
+ return 0;
+ }
+
+ webkit_dom_dom_selection_collapse_to_start (dom_selection, NULL);
+ /* Select the text from the current caret position to the beginning of the line. */
+ webkit_dom_dom_selection_modify (dom_selection, "extend", "left", "lineBoundary");
+
+ range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+ anchor = webkit_dom_dom_selection_get_anchor_node (dom_selection);
+ text = webkit_dom_range_to_string (range, NULL);
+ ret_val = strlen (text);
+ g_free (text);
+
+ webkit_dom_dom_selection_collapse_to_end (dom_selection, NULL);
+
+ /* In the plain text mode we need to increase the return value by 2 per
+ * citation level because of "> ". */
+ if (!e_editor_page_get_html_mode (editor_page)) {
+ WebKitDOMNode *parent = anchor;
+
+ while (parent && !WEBKIT_DOM_IS_HTML_BODY_ELEMENT (parent)) {
+ if (WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (parent))
+ ret_val += 2;
+
+ parent = webkit_dom_node_get_parent_node (parent);
+ }
+ }
+
+ g_clear_object (&range);
+ g_clear_object (&dom_selection);
+
+ return ret_val;
+}
+
+guint
+e_editor_dom_get_caret_position (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMHTMLElement *body;
+ WebKitDOMDOMWindow *dom_window = NULL;
+ WebKitDOMDOMSelection *dom_selection = NULL;
+ WebKitDOMRange *range = NULL, *range_clone = NULL;
+ guint ret_val;
+ gchar *text;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), 0);
+
+ document = e_editor_page_get_document (editor_page);
+ dom_window = webkit_dom_document_get_default_view (document);
+ dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+ g_clear_object (&dom_window);
+
+ if (webkit_dom_dom_selection_get_range_count (dom_selection) < 1) {
+ g_clear_object (&dom_selection);
+ return 0;
+ }
+
+ range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+ range_clone = webkit_dom_range_clone_range (range, NULL);
+
+ body = webkit_dom_document_get_body (document);
+ /* Select the text from the beginning of the body to the current caret. */
+ webkit_dom_range_set_start_before (
+ range_clone, webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (body)), NULL);
+
+ /* This is returning a text without new lines! */
+ text = webkit_dom_range_to_string (range_clone, NULL);
+ ret_val = strlen (text);
+ g_free (text);
+
+ g_clear_object (&range_clone);
+ g_clear_object (&range);
+ g_clear_object (&dom_selection);
+
+ return ret_val;
+}
+
+void
+e_editor_dom_save_history_for_drop (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMDocumentFragment *fragment;
+ WebKitDOMDOMSelection *dom_selection = NULL;
+ WebKitDOMDOMWindow *dom_window = NULL;
+ WebKitDOMNodeList *list = NULL;
+ WebKitDOMRange *range = NULL;
+ EEditorUndoRedoManager *manager;
+ EEditorHistoryEvent *event;
+ gint ii, length;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+ manager = e_editor_page_get_undo_redo_manager (editor_page);
+
+ /* When the image is DnD inside the view WebKit removes the wrapper that
+ * is used for resizing the image, so we have to recreate it again. */
+ list = webkit_dom_document_query_selector_all (document, ":not(span) > img[data-inline]", NULL);
+ length = webkit_dom_node_list_get_length (list);
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMElement *element;
+ WebKitDOMNode *node = webkit_dom_node_list_item (list, ii);
+
+ element = webkit_dom_document_create_element (document, "span", NULL);
+ webkit_dom_element_set_class_name (element, "-x-evo-resizable-wrapper");
+
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (node),
+ WEBKIT_DOM_NODE (element),
+ node,
+ NULL);
+
+ webkit_dom_node_append_child (WEBKIT_DOM_NODE (element), node, NULL);
+ g_object_unref (node);
+ }
+ g_clear_object (&list);
+
+ /* When the image is moved the new selection is created after after it, so
+ * lets collapse the selection to have the caret right after the image. */
+ dom_window = webkit_dom_document_get_default_view (document);
+ dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+ g_clear_object (&dom_window);
+
+ range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+
+ /* Remove the last inserted history event as this one was inserted in
+ * body_input_event_cb and is wrong as its type is HISTORY_INPUT. */
+ /* FIXME we could probably disable the HTML input event callback while
+ * doing DnD within the view */
+ /* FIXME WK2 - what if e_editor_undo_redo_manager_get_current_history_event() returns NULL? */
+ if (((EEditorHistoryEvent *) (e_editor_undo_redo_manager_get_current_history_event (manager)))->type
== HISTORY_INPUT)
+ e_editor_undo_redo_manager_remove_current_history_event (manager);
+
+ event = g_new0 (EEditorHistoryEvent, 1);
+ event->type = HISTORY_INSERT_HTML;
+
+ /* Get the dropped content. It's easy as it is selected by WebKit. */
+ fragment = webkit_dom_range_clone_contents (range, NULL);
+ event->data.string.from = NULL;
+ /* Get the HTML content of the dropped content. */
+ event->data.string.to = dom_get_node_inner_html (WEBKIT_DOM_NODE (fragment));
+
+ e_editor_dom_selection_get_coordinates (editor_page,
+ &event->before.start.x,
+ &event->before.start.y,
+ &event->before.end.x,
+ &event->before.end.y);
+
+ event->before.end.x = event->before.start.x;
+ event->before.end.y = event->before.start.y;
+
+ if (length > 0)
+ webkit_dom_dom_selection_collapse_to_start (dom_selection, NULL);
+ else
+ webkit_dom_dom_selection_collapse_to_end (dom_selection, NULL);
+
+ e_editor_dom_selection_get_coordinates (editor_page,
+ &event->after.start.x,
+ &event->after.start.y,
+ &event->after.end.x,
+ &event->after.end.y);
+
+ e_editor_undo_redo_manager_insert_history_event (manager, event);
+
+ if (!e_editor_page_get_html_mode (editor_page)) {
+ list = webkit_dom_document_query_selector_all (
+ document, "span[style^=font-family]", NULL);
+ length = webkit_dom_node_list_get_length (list);
+ if (length > 0)
+ e_editor_dom_selection_save (editor_page);
+
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMNode *span, *child;
+
+ span = webkit_dom_node_list_item (list, ii);
+ while ((child = webkit_dom_node_get_first_child (span)))
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (span),
+ child,
+ span,
+ NULL);
+
+ remove_node (span);
+ g_object_unref (span);
+ }
+ g_clear_object (&list);
+
+ if (length > 0)
+ e_editor_dom_selection_restore (editor_page);
+ }
+
+ e_editor_dom_force_spell_check_in_viewport (editor_page);
+
+ g_clear_object (&range);
+ g_clear_object (&dom_selection);
+}
+
+void
+e_editor_dom_drag_and_drop_end (EEditorPage *editor_page)
+{
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ e_editor_dom_save_history_for_drop (editor_page);
+}
+
+static void
+dom_set_link_color_in_document (EEditorPage *editor_page,
+ const gchar *color,
+ gboolean visited)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMHTMLHeadElement *head;
+ WebKitDOMElement *style_element;
+ WebKitDOMHTMLElement *body;
+ gchar *color_str = NULL;
+ const gchar *style_id;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+ g_return_if_fail (color != NULL);
+
+ style_id = visited ? "-x-evo-a-color-style-visited" : "-x-evo-a-color-style";
+
+ document = e_editor_page_get_document (editor_page);
+ head = webkit_dom_document_get_head (document);
+ body = webkit_dom_document_get_body (document);
+
+ style_element = webkit_dom_document_get_element_by_id (document, style_id);
+ if (!style_element) {
+ style_element = webkit_dom_document_create_element (document, "style", NULL);
+ webkit_dom_element_set_id (style_element, style_id);
+ webkit_dom_element_set_attribute (style_element, "type", "text/css", NULL);
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (head), WEBKIT_DOM_NODE (style_element), NULL);
+ }
+
+ color_str = g_strdup_printf (
+ visited ? "a.-x-evo-visited-link { color: %s; }" : "a { color: %s; }", color);
+ webkit_dom_element_set_inner_html (style_element, color_str, NULL);
+ g_free (color_str);
+
+ if (visited)
+ webkit_dom_html_body_element_set_v_link (
+ WEBKIT_DOM_HTML_BODY_ELEMENT (body), color);
+ else
+ webkit_dom_html_body_element_set_link (
+ WEBKIT_DOM_HTML_BODY_ELEMENT (body), color);
+}
+
+void
+e_editor_dom_set_link_color (EEditorPage *editor_page,
+ const gchar *color)
+{
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ dom_set_link_color_in_document (editor_page, color, FALSE);
+}
+
+void
+e_editor_dom_set_visited_link_color (EEditorPage *editor_page,
+ const gchar *color)
+{
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ dom_set_link_color_in_document (editor_page, color, TRUE);
+}
+
+void
+e_editor_dom_fix_file_uri_images (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMNodeList *list = NULL;
+ gint ii, length;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+
+ list = webkit_dom_document_query_selector_all (
+ document, "img[src^=\"file://\"]", NULL);
+ length = webkit_dom_node_list_get_length (list);
+
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMNode *node;
+ gchar *uri;
+
+ node = webkit_dom_node_list_item (list, ii);
+ uri = webkit_dom_element_get_attribute (WEBKIT_DOM_ELEMENT (node), "src");
+ g_free (uri);
+ }
+
+ g_clear_object (&list);
+}
+
+/* ******************** Selection ******************** */
+
+void
+e_editor_dom_replace_base64_image_src (EEditorPage *editor_page,
+ const gchar *selector,
+ const gchar *base64_content,
+ const gchar *filename,
+ const gchar *uri)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *element;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+ element = webkit_dom_document_query_selector (document, selector, NULL);
+
+ if (WEBKIT_DOM_IS_HTML_IMAGE_ELEMENT (element))
+ webkit_dom_html_image_element_set_src (
+ WEBKIT_DOM_HTML_IMAGE_ELEMENT (element),
+ base64_content);
+ else
+ webkit_dom_element_set_attribute (
+ element, "background", base64_content, NULL);
+
+ webkit_dom_element_set_attribute (element, "data-uri", uri, NULL);
+ webkit_dom_element_set_attribute (element, "data-inline", "", NULL);
+ webkit_dom_element_set_attribute (
+ element, "data-name", filename ? filename : "", NULL);
+}
+
+WebKitDOMRange *
+e_editor_dom_get_current_range (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMDOMWindow *dom_window = NULL;
+ WebKitDOMDOMSelection *dom_selection = NULL;
+ WebKitDOMRange *range = NULL;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+ document = e_editor_page_get_document (editor_page);
+ dom_window = webkit_dom_document_get_default_view (document);
+ if (!dom_window)
+ return NULL;
+
+ dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+ if (!WEBKIT_DOM_IS_DOM_SELECTION (dom_selection)) {
+ g_clear_object (&dom_window);
+ return NULL;
+ }
+
+ if (webkit_dom_dom_selection_get_range_count (dom_selection) < 1)
+ goto exit;
+
+ range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+ exit:
+ g_clear_object (&dom_selection);
+ g_clear_object (&dom_window);
+
+ return range;
+}
+
+void
+e_editor_dom_move_caret_into_element (EEditorPage *editor_page,
+ WebKitDOMElement *element,
+ gboolean to_start)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMDOMWindow *dom_window = NULL;
+ WebKitDOMDOMSelection *dom_selection = NULL;
+ WebKitDOMRange *range = NULL;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ if (!element)
+ return;
+
+ document = e_editor_page_get_document (editor_page);
+ dom_window = webkit_dom_document_get_default_view (document);
+ dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+ range = webkit_dom_document_create_range (document);
+
+ webkit_dom_range_select_node_contents (
+ range, WEBKIT_DOM_NODE (element), NULL);
+ webkit_dom_range_collapse (range, to_start, NULL);
+ webkit_dom_dom_selection_remove_all_ranges (dom_selection);
+ webkit_dom_dom_selection_add_range (dom_selection, range);
+
+ g_clear_object (&range);
+ g_clear_object (&dom_selection);
+ g_clear_object (&dom_window);
+}
+
+void
+e_editor_dom_insert_base64_image (EEditorPage *editor_page,
+ const gchar *base64_content,
+ const gchar *filename,
+ const gchar *uri)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *element, *selection_start_marker, *resizable_wrapper;
+ WebKitDOMText *text;
+ EEditorHistoryEvent *ev = NULL;
+ EEditorUndoRedoManager *manager;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+ manager = e_editor_page_get_undo_redo_manager (editor_page);
+
+ if (!e_editor_dom_selection_is_collapsed (editor_page)) {
+ EEditorHistoryEvent *ev;
+ WebKitDOMDocumentFragment *fragment;
+ WebKitDOMRange *range = NULL;
+
+ ev = g_new0 (EEditorHistoryEvent, 1);
+ ev->type = HISTORY_DELETE;
+
+ range = e_editor_dom_get_current_range (editor_page);
+ fragment = webkit_dom_range_clone_contents (range, NULL);
+ g_clear_object (&range);
+ ev->data.fragment = fragment;
+
+ e_editor_dom_selection_get_coordinates (editor_page,
+ &ev->before.start.x,
+ &ev->before.start.y,
+ &ev->before.end.x,
+ &ev->before.end.y);
+
+ ev->after.start.x = ev->before.start.x;
+ ev->after.start.y = ev->before.start.y;
+ ev->after.end.x = ev->before.start.x;
+ ev->after.end.y = ev->before.start.y;
+
+ e_editor_undo_redo_manager_insert_history_event (manager, ev);
+
+ ev = g_new0 (EEditorHistoryEvent, 1);
+ ev->type = HISTORY_AND;
+
+ e_editor_undo_redo_manager_insert_history_event (manager, ev);
+ e_editor_dom_exec_command (editor_page, E_CONTENT_EDITOR_COMMAND_DELETE, NULL);
+ }
+
+ e_editor_dom_selection_save (editor_page);
+ selection_start_marker = webkit_dom_document_query_selector (
+ document, "span#-x-evo-selection-start-marker", NULL);
+
+ if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+ ev = g_new0 (EEditorHistoryEvent, 1);
+ ev->type = HISTORY_IMAGE;
+
+ e_editor_dom_selection_get_coordinates (editor_page,
+ &ev->before.start.x,
+ &ev->before.start.y,
+ &ev->before.end.x,
+ &ev->before.end.y);
+ }
+
+ resizable_wrapper =
+ webkit_dom_document_create_element (document, "span", NULL);
+ webkit_dom_element_set_attribute (
+ resizable_wrapper, "class", "-x-evo-resizable-wrapper", NULL);
+
+ element = webkit_dom_document_create_element (document, "img", NULL);
+ webkit_dom_html_image_element_set_src (
+ WEBKIT_DOM_HTML_IMAGE_ELEMENT (element),
+ base64_content);
+ webkit_dom_element_set_attribute (
+ WEBKIT_DOM_ELEMENT (element), "data-uri", uri, NULL);
+ webkit_dom_element_set_attribute (
+ WEBKIT_DOM_ELEMENT (element), "data-inline", "", NULL);
+ webkit_dom_element_set_attribute (
+ WEBKIT_DOM_ELEMENT (element), "data-name",
+ filename ? filename : "", NULL);
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (resizable_wrapper),
+ WEBKIT_DOM_NODE (element),
+ NULL);
+
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (
+ WEBKIT_DOM_NODE (selection_start_marker)),
+ WEBKIT_DOM_NODE (resizable_wrapper),
+ WEBKIT_DOM_NODE (selection_start_marker),
+ NULL);
+
+ /* We have to again use UNICODE_ZERO_WIDTH_SPACE character to restore
+ * caret on right position */
+ text = webkit_dom_document_create_text_node (
+ document, UNICODE_ZERO_WIDTH_SPACE);
+
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (
+ WEBKIT_DOM_NODE (selection_start_marker)),
+ WEBKIT_DOM_NODE (text),
+ WEBKIT_DOM_NODE (selection_start_marker),
+ NULL);
+
+ if (ev) {
+ WebKitDOMDocumentFragment *fragment;
+ WebKitDOMNode *node;
+
+ fragment = webkit_dom_document_create_document_fragment (document);
+ node = webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (fragment),
+ webkit_dom_node_clone_node_with_error (WEBKIT_DOM_NODE (resizable_wrapper), TRUE,
NULL),
+ NULL);
+
+ webkit_dom_html_element_insert_adjacent_html (
+ WEBKIT_DOM_HTML_ELEMENT (node), "afterend", "​", NULL);
+ ev->data.fragment = fragment;
+
+ e_editor_dom_selection_get_coordinates (editor_page,
+ &ev->after.start.x,
+ &ev->after.start.y,
+ &ev->after.end.x,
+ &ev->after.end.y);
+
+ e_editor_undo_redo_manager_insert_history_event (manager, ev);
+ }
+
+ e_editor_dom_selection_restore (editor_page);
+ e_editor_dom_force_spell_check_for_current_paragraph (editor_page);
+ e_editor_dom_scroll_to_caret (editor_page);
+}
+
+/* ************************ image_load_and_insert_async() ************************ */
+
+typedef struct _ImageLoadContext {
+ EEditorPage *editor_page;
+ GInputStream *input_stream;
+ GOutputStream *output_stream;
+ GFile *file;
+ GFileInfo *file_info;
+ goffset total_num_bytes;
+ gssize bytes_read;
+ const gchar *content_type;
+ const gchar *filename;
+ const gchar *selector;
+ gchar buffer[4096];
+} ImageLoadContext;
+
+/* Forward Declaration */
+static void
+image_load_stream_read_cb (GInputStream *input_stream,
+ GAsyncResult *result,
+ ImageLoadContext *load_context);
+
+static ImageLoadContext *
+image_load_context_new (EEditorPage *editor_page)
+{
+ ImageLoadContext *load_context;
+
+ load_context = g_slice_new0 (ImageLoadContext);
+ load_context->editor_page = editor_page;
+
+ return load_context;
+}
+
+static void
+image_load_context_free (ImageLoadContext *load_context)
+{
+ if (load_context->input_stream != NULL)
+ g_object_unref (load_context->input_stream);
+
+ if (load_context->output_stream != NULL)
+ g_object_unref (load_context->output_stream);
+
+ if (load_context->file_info != NULL)
+ g_object_unref (load_context->file_info);
+
+ if (load_context->file != NULL)
+ g_object_unref (load_context->file);
+
+ g_slice_free (ImageLoadContext, load_context);
+}
+
+static void
+image_load_finish (ImageLoadContext *load_context)
+{
+ EEditorPage *editor_page;
+ GMemoryOutputStream *output_stream;
+ const gchar *selector;
+ gchar *base64_encoded, *mime_type, *output, *uri;
+ gsize size;
+ gpointer data;
+
+ output_stream = G_MEMORY_OUTPUT_STREAM (load_context->output_stream);
+ editor_page = load_context->editor_page;
+ mime_type = g_content_type_get_mime_type (load_context->content_type);
+
+ data = g_memory_output_stream_get_data (output_stream);
+ size = g_memory_output_stream_get_data_size (output_stream);
+ uri = g_file_get_uri (load_context->file);
+
+ base64_encoded = g_base64_encode ((const guchar *) data, size);
+ output = g_strconcat ("data:", mime_type, ";base64,", base64_encoded, NULL);
+ selector = load_context->selector;
+ if (selector && *selector)
+ e_editor_dom_replace_base64_image_src (editor_page, selector, output, load_context->filename,
uri);
+ else
+ e_editor_dom_insert_base64_image (editor_page, output, load_context->filename, uri);
+
+ g_free (base64_encoded);
+ g_free (output);
+ g_free (mime_type);
+ g_free (uri);
+
+ image_load_context_free (load_context);
+}
+
+static void
+image_load_write_cb (GOutputStream *output_stream,
+ GAsyncResult *result,
+ ImageLoadContext *load_context)
+{
+ GInputStream *input_stream;
+ gssize bytes_written;
+ GError *error = NULL;
+
+ bytes_written = g_output_stream_write_finish (
+ output_stream, result, &error);
+
+ if (error) {
+ image_load_context_free (load_context);
+ return;
+ }
+
+ input_stream = load_context->input_stream;
+
+ if (bytes_written < load_context->bytes_read) {
+ g_memmove (
+ load_context->buffer,
+ load_context->buffer + bytes_written,
+ load_context->bytes_read - bytes_written);
+ load_context->bytes_read -= bytes_written;
+
+ g_output_stream_write_async (
+ output_stream,
+ load_context->buffer,
+ load_context->bytes_read,
+ G_PRIORITY_DEFAULT, NULL,
+ (GAsyncReadyCallback) image_load_write_cb,
+ load_context);
+ } else
+ g_input_stream_read_async (
+ input_stream,
+ load_context->buffer,
+ sizeof (load_context->buffer),
+ G_PRIORITY_DEFAULT, NULL,
+ (GAsyncReadyCallback) image_load_stream_read_cb,
+ load_context);
+}
+
+static void
+image_load_stream_read_cb (GInputStream *input_stream,
+ GAsyncResult *result,
+ ImageLoadContext *load_context)
+{
+ GOutputStream *output_stream;
+ gssize bytes_read;
+ GError *error = NULL;
+
+ bytes_read = g_input_stream_read_finish (
+ input_stream, result, &error);
+
+ if (error) {
+ image_load_context_free (load_context);
+ return;
+ }
+
+ if (bytes_read == 0) {
+ image_load_finish (load_context);
+ return;
+ }
+
+ output_stream = load_context->output_stream;
+ load_context->bytes_read = bytes_read;
+
+ g_output_stream_write_async (
+ output_stream,
+ load_context->buffer,
+ load_context->bytes_read,
+ G_PRIORITY_DEFAULT, NULL,
+ (GAsyncReadyCallback) image_load_write_cb,
+ load_context);
+}
+
+static void
+image_load_file_read_cb (GFile *file,
+ GAsyncResult *result,
+ ImageLoadContext *load_context)
+{
+ GFileInputStream *input_stream;
+ GOutputStream *output_stream;
+ GError *error = NULL;
+
+ /* Input stream might be NULL, so don't use cast macro. */
+ input_stream = g_file_read_finish (file, result, &error);
+ load_context->input_stream = (GInputStream *) input_stream;
+
+ if (error) {
+ image_load_context_free (load_context);
+ return;
+ }
+
+ /* Load the contents into a GMemoryOutputStream. */
+ output_stream = g_memory_output_stream_new (
+ NULL, 0, g_realloc, g_free);
+
+ load_context->output_stream = output_stream;
+
+ g_input_stream_read_async (
+ load_context->input_stream,
+ load_context->buffer,
+ sizeof (load_context->buffer),
+ G_PRIORITY_DEFAULT, NULL,
+ (GAsyncReadyCallback) image_load_stream_read_cb,
+ load_context);
+}
+
+static void
+image_load_query_info_cb (GFile *file,
+ GAsyncResult *result,
+ ImageLoadContext *load_context)
+{
+ GFileInfo *file_info;
+ GError *error = NULL;
+
+ file_info = g_file_query_info_finish (file, result, &error);
+ if (error) {
+ image_load_context_free (load_context);
+ return;
+ }
+
+ load_context->content_type = g_file_info_get_content_type (file_info);
+ load_context->total_num_bytes = g_file_info_get_size (file_info);
+ load_context->filename = g_file_info_get_name (file_info);
+
+ g_file_read_async (
+ file, G_PRIORITY_DEFAULT,
+ NULL, (GAsyncReadyCallback)
+ image_load_file_read_cb, load_context);
+}
+
+static void
+image_load_and_insert_async (EEditorPage *editor_page,
+ const gchar *selector,
+ const gchar *uri)
+{
+ ImageLoadContext *load_context;
+ GFile *file;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+ g_return_if_fail (uri && *uri);
+
+ file = g_file_new_for_uri (uri);
+ g_return_if_fail (file != NULL);
+
+ load_context = image_load_context_new (editor_page);
+ load_context->file = file;
+ if (selector && *selector)
+ load_context->selector = g_strdup (selector);
+
+ g_file_query_info_async (
+ file, "standard::*",
+ G_FILE_QUERY_INFO_NONE,G_PRIORITY_DEFAULT,
+ NULL, (GAsyncReadyCallback)
+ image_load_query_info_cb, load_context);
+}
+
+void
+e_editor_dom_insert_image (EEditorPage *editor_page,
+ const gchar *uri)
+{
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ if (!e_editor_page_get_html_mode (editor_page))
+ return;
+
+ if (strstr (uri, ";base64,")) {
+ if (g_str_has_prefix (uri, "data:"))
+ e_editor_dom_insert_base64_image (editor_page, uri, "", "");
+ if (strstr (uri, ";data")) {
+ const gchar *base64_data = strstr (uri, ";") + 1;
+ gchar *filename;
+ glong filename_length;
+
+ filename_length =
+ g_utf8_strlen (uri, -1) -
+ g_utf8_strlen (base64_data, -1) - 1;
+ filename = g_strndup (uri, filename_length);
+
+ e_editor_dom_insert_base64_image (editor_page, base64_data, filename, "");
+ g_free (filename);
+ }
+ } else
+ image_load_and_insert_async (editor_page, NULL, uri);
+}
+
+void
+e_editor_dom_replace_image_src (EEditorPage *editor_page,
+ const gchar *selector,
+ const gchar *uri)
+{
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ if (strstr (uri, ";base64,")) {
+ if (g_str_has_prefix (uri, "data:"))
+ e_editor_dom_replace_base64_image_src (
+ editor_page, selector, uri, "", "");
+ if (strstr (uri, ";data")) {
+ const gchar *base64_data = strstr (uri, ";") + 1;
+ gchar *filename;
+ glong filename_length;
+
+ filename_length =
+ g_utf8_strlen (uri, -1) -
+ g_utf8_strlen (base64_data, -1) - 1;
+ filename = g_strndup (uri, filename_length);
+
+ e_editor_dom_replace_base64_image_src (
+ editor_page, selector, base64_data, filename, "");
+ g_free (filename);
+ }
+ } else
+ image_load_and_insert_async (editor_page, selector, uri);
+}
+
+/*
+ * e_html_editor_selection_unlink:
+ * @selection: an #EEditorSelection
+ *
+ * Removes any links (<A> elements) from current selection or at current
+ * cursor position.
+ */
+void
+e_editor_dom_selection_unlink (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMDOMWindow *dom_window = NULL;
+ WebKitDOMDOMSelection *dom_selection = NULL;
+ WebKitDOMRange *range = NULL;
+ WebKitDOMElement *link;
+ EEditorUndoRedoManager *manager;
+ gchar *text;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+ dom_window = webkit_dom_document_get_default_view (document);
+ dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+
+ range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+ link = dom_node_find_parent_element (
+ webkit_dom_range_get_start_container (range, NULL), "A");
+
+ g_clear_object (&dom_selection);
+ g_clear_object (&dom_window);
+
+ if (!link) {
+ WebKitDOMNode *node;
+
+ /* get element that was clicked on */
+ node = webkit_dom_range_get_common_ancestor_container (range, NULL);
+ if (node && !WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (node)) {
+ link = dom_node_find_parent_element (node, "A");
+ if (link && !WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (link)) {
+ g_clear_object (&range);
+ return;
+ } else
+ link = WEBKIT_DOM_ELEMENT (node);
+ }
+ }
+
+ g_clear_object (&range);
+
+ if (!link)
+ return;
+
+ manager = e_editor_page_get_undo_redo_manager (editor_page);
+ if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+ EEditorHistoryEvent *ev;
+ WebKitDOMDocumentFragment *fragment;
+
+ ev = g_new0 (EEditorHistoryEvent, 1);
+ ev->type = HISTORY_REMOVE_LINK;
+
+ e_editor_dom_selection_get_coordinates (editor_page,
+ &ev->before.start.x,
+ &ev->before.start.y,
+ &ev->before.end.x,
+ &ev->before.end.y);
+
+ fragment = webkit_dom_document_create_document_fragment (document);
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (fragment),
+ webkit_dom_node_clone_node_with_error (WEBKIT_DOM_NODE (link), TRUE, NULL),
+ NULL);
+ ev->data.fragment = fragment;
+
+ e_editor_undo_redo_manager_insert_history_event (manager, ev);
+ }
+
+ text = webkit_dom_html_element_get_inner_text (
+ WEBKIT_DOM_HTML_ELEMENT (link));
+ webkit_dom_element_set_outer_html (link, text, NULL);
+ g_free (text);
+}
+
+/*
+ * e_html_editor_selection_create_link:
+ * @document: a @WebKitDOMDocument
+ * @uri: destination of the new link
+ *
+ * Converts current selection into a link pointing to @url.
+ */
+void
+e_editor_dom_create_link (EEditorPage *editor_page,
+ const gchar *uri)
+{
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+ g_return_if_fail (uri != NULL && *uri != '\0');
+
+ e_editor_dom_exec_command (editor_page, E_CONTENT_EDITOR_COMMAND_CREATE_LINK, uri);
+}
+
+static gint
+get_list_level (WebKitDOMNode *node)
+{
+ gint level = 0;
+
+ while (node && !WEBKIT_DOM_IS_HTML_BODY_ELEMENT (node)) {
+ if (node_is_list (node))
+ level++;
+ node = webkit_dom_node_get_parent_node (node);
+ }
+
+ return level;
+}
+
+static void
+set_ordered_list_type_to_element (WebKitDOMElement *list,
+ EContentEditorBlockFormat format)
+{
+ if (format == E_CONTENT_EDITOR_BLOCK_FORMAT_ORDERED_LIST)
+ webkit_dom_element_remove_attribute (list, "type");
+ else if (format == E_CONTENT_EDITOR_BLOCK_FORMAT_ORDERED_LIST_ALPHA)
+ webkit_dom_element_set_attribute (list, "type", "A", NULL);
+ else if (format == E_CONTENT_EDITOR_BLOCK_FORMAT_ORDERED_LIST_ROMAN)
+ webkit_dom_element_set_attribute (list, "type", "I", NULL);
+}
+
+static const gchar *
+get_css_alignment_value_class (EContentEditorAlignment alignment)
+{
+ if (alignment == E_CONTENT_EDITOR_ALIGNMENT_LEFT)
+ return ""; /* Left is by default on ltr */
+
+ if (alignment == E_CONTENT_EDITOR_ALIGNMENT_CENTER)
+ return "-x-evo-align-center";
+
+ if (alignment == E_CONTENT_EDITOR_ALIGNMENT_RIGHT)
+ return "-x-evo-align-right";
+
+ return "";
+}
+
+/*
+ * e_html_editor_selection_get_alignment:
+ * @selection: #an EEditorSelection
+ *
+ * Returns alignment of current paragraph
+ *
+ * Returns: #EContentEditorAlignment
+ */
+static EContentEditorAlignment
+dom_get_alignment (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMCSSStyleDeclaration *style = NULL;
+ WebKitDOMDOMWindow *dom_window = NULL;
+ WebKitDOMElement *element;
+ WebKitDOMNode *node;
+ WebKitDOMRange *range = NULL;
+ EContentEditorAlignment alignment;
+ gchar *value;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), E_CONTENT_EDITOR_ALIGNMENT_LEFT);
+
+ document = e_editor_page_get_document (editor_page);
+ range = e_editor_dom_get_current_range (editor_page);
+ if (!range)
+ return E_CONTENT_EDITOR_ALIGNMENT_LEFT;
+
+ node = webkit_dom_range_get_start_container (range, NULL);
+ g_clear_object (&range);
+ if (!node)
+ return E_CONTENT_EDITOR_ALIGNMENT_LEFT;
+
+ if (WEBKIT_DOM_IS_ELEMENT (node))
+ element = WEBKIT_DOM_ELEMENT (node);
+ else
+ element = WEBKIT_DOM_ELEMENT (e_editor_dom_get_parent_block_node_from_child (node));
+
+ if (WEBKIT_DOM_IS_HTML_LI_ELEMENT (element)) {
+ if (element_has_class (element, "-x-evo-align-right"))
+ alignment = E_CONTENT_EDITOR_ALIGNMENT_RIGHT;
+ else if (element_has_class (element, "-x-evo-align-center"))
+ alignment = E_CONTENT_EDITOR_ALIGNMENT_CENTER;
+ else
+ alignment = E_CONTENT_EDITOR_ALIGNMENT_LEFT;
+
+ return alignment;
+ }
+
+ dom_window = webkit_dom_document_get_default_view (document);
+ style = webkit_dom_dom_window_get_computed_style (dom_window, element, NULL);
+ value = webkit_dom_css_style_declaration_get_property_value (style, "text-align");
+
+ if (!value || !*value ||
+ (g_ascii_strncasecmp (value, "left", 4) == 0)) {
+ alignment = E_CONTENT_EDITOR_ALIGNMENT_LEFT;
+ } else if (g_ascii_strncasecmp (value, "center", 6) == 0) {
+ alignment = E_CONTENT_EDITOR_ALIGNMENT_CENTER;
+ } else if (g_ascii_strncasecmp (value, "right", 5) == 0) {
+ alignment = E_CONTENT_EDITOR_ALIGNMENT_RIGHT;
+ } else {
+ alignment = E_CONTENT_EDITOR_ALIGNMENT_LEFT;
+ }
+
+ g_clear_object (&dom_window);
+ g_clear_object (&style);
+ g_free (value);
+
+ return alignment;
+}
+
+static gint
+set_word_wrap_length (EEditorPage *editor_page,
+ gint user_word_wrap_length)
+{
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), 0);
+
+ /* user_word_wrap_length < 0, set block width to word_wrap_length
+ * user_word_wrap_length == 0, no width limit set,
+ * user_word_wrap_length > 0, set width limit to given value */
+ return (user_word_wrap_length < 0) ?
+ e_editor_page_get_word_wrap_length (editor_page) : user_word_wrap_length;
+}
+
+void
+e_editor_dom_set_paragraph_style (EEditorPage *editor_page,
+ WebKitDOMElement *element,
+ gint width,
+ gint offset,
+ const gchar *style_to_add)
+{
+ WebKitDOMNode *parent;
+ gchar *style = NULL;
+ gint word_wrap_length;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ word_wrap_length = set_word_wrap_length (editor_page, width);
+ webkit_dom_element_set_attribute (element, "data-evo-paragraph", "", NULL);
+
+ /* Don't set the alignment for nodes as they are handled separately. */
+ if (!node_is_list (WEBKIT_DOM_NODE (element))) {
+ EContentEditorAlignment alignment;
+
+ alignment = dom_get_alignment (editor_page);
+ element_add_class (element, get_css_alignment_value_class (alignment));
+ }
+
+ parent = webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element));
+ /* Don't set the width limit to sub-blocks as the width limit is inhered
+ * from its parents. */
+ if (!e_editor_page_get_html_mode (editor_page) &&
+ (!parent || WEBKIT_DOM_IS_HTML_BODY_ELEMENT (parent))) {
+ style = g_strdup_printf (
+ "width: %dch;%s%s",
+ (word_wrap_length + offset),
+ style_to_add && *style_to_add ? " " : "",
+ style_to_add && *style_to_add ? style_to_add : "");
+ } else {
+ if (style_to_add && *style_to_add)
+ style = g_strdup_printf ("%s", style_to_add);
+ }
+ if (style) {
+ webkit_dom_element_set_attribute (element, "style", style, NULL);
+ g_free (style);
+ }
+}
+
+static WebKitDOMElement *
+create_list_element (EEditorPage *editor_page,
+ EContentEditorBlockFormat format,
+ gint level,
+ gboolean html_mode)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *list;
+ gboolean inserting_unordered_list;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+ document = e_editor_page_get_document (editor_page);
+ inserting_unordered_list = format == E_CONTENT_EDITOR_BLOCK_FORMAT_UNORDERED_LIST;
+
+ list = webkit_dom_document_create_element (
+ document, inserting_unordered_list ? "UL" : "OL", NULL);
+
+ if (!inserting_unordered_list)
+ set_ordered_list_type_to_element (list, format);
+
+ if (level >= 0 && !html_mode) {
+ gint offset;
+
+ offset = (level + 1) * SPACES_PER_LIST_LEVEL;
+
+ offset += !inserting_unordered_list ?
+ SPACES_ORDERED_LIST_FIRST_LEVEL - SPACES_PER_LIST_LEVEL: 0;
+
+ e_editor_dom_set_paragraph_style (editor_page, list, -1, -offset, NULL);
+
+ if (inserting_unordered_list)
+ webkit_dom_element_set_attribute (list, "data-evo-plain-text", "", NULL);
+ }
+
+ return list;
+}
+
+static gboolean
+indent_list (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *selection_start_marker, *selection_end_marker;
+ WebKitDOMNode *item, *next_item;
+ gboolean after_selection_end = FALSE;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+ document = e_editor_page_get_document (editor_page);
+ selection_start_marker = webkit_dom_document_query_selector (
+ document, "span#-x-evo-selection-start-marker", NULL);
+
+ selection_end_marker = webkit_dom_document_query_selector (
+ document, "span#-x-evo-selection-end-marker", NULL);
+
+ item = e_editor_dom_get_parent_block_node_from_child (
+ WEBKIT_DOM_NODE (selection_start_marker));
+
+ if (WEBKIT_DOM_IS_HTML_LI_ELEMENT (item)) {
+ gboolean html_mode = e_editor_page_get_html_mode (editor_page);
+ WebKitDOMElement *list;
+ WebKitDOMNode *source_list = webkit_dom_node_get_parent_node (item);
+ EContentEditorBlockFormat format;
+
+ format = dom_get_list_format_from_node (source_list);
+
+ list = create_list_element (
+ editor_page, format, get_list_level (item), html_mode);
+
+ element_add_class (list, "-x-evo-indented");
+
+ webkit_dom_node_insert_before (
+ source_list, WEBKIT_DOM_NODE (list), item, NULL);
+
+ while (item && !after_selection_end) {
+ after_selection_end = webkit_dom_node_contains (
+ item, WEBKIT_DOM_NODE (selection_end_marker));
+
+ next_item = webkit_dom_node_get_next_sibling (item);
+
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (list), item, NULL);
+
+ item = next_item;
+ }
+
+ merge_lists_if_possible (WEBKIT_DOM_NODE (list));
+ }
+
+ return after_selection_end;
+}
+
+static void
+dom_set_indented_style (EEditorPage *editor_page,
+ WebKitDOMElement *element,
+ gint width)
+{
+ gchar *style;
+ gint word_wrap_length;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ word_wrap_length = set_word_wrap_length (editor_page, width);
+ webkit_dom_element_set_class_name (element, "-x-evo-indented");
+
+ if (e_editor_page_get_html_mode (editor_page) || word_wrap_length == 0) {
+ style = g_strdup_printf ("margin-left: %dch;", SPACES_PER_INDENTATION);
+
+ if (word_wrap_length != 0) {
+ gchar *plain_text_style;
+
+ plain_text_style = g_strdup_printf (
+ "margin-left: %dch; word-wrap: normal; width: %dch;",
+ SPACES_PER_INDENTATION, word_wrap_length);
+
+ webkit_dom_element_set_attribute (
+ element, "data-plain-text-style", plain_text_style, NULL);
+ g_free (plain_text_style);
+ }
+ } else {
+ style = g_strdup_printf (
+ "margin-left: %dch; word-wrap: normal; width: %dch;",
+ SPACES_PER_INDENTATION, word_wrap_length);
+ }
+
+ webkit_dom_element_set_attribute (element, "style", style, NULL);
+ g_free (style);
+}
+
+static WebKitDOMElement *
+dom_get_indented_element (EEditorPage *editor_page,
+ gint width)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *element;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+ document = e_editor_page_get_document (editor_page);
+ element = webkit_dom_document_create_element (document, "DIV", NULL);
+ dom_set_indented_style (editor_page, element, width);
+
+ return element;
+}
+
+static WebKitDOMNode *
+indent_block (EEditorPage *editor_page,
+ WebKitDOMNode *block,
+ gint width)
+{
+ WebKitDOMElement *element;
+ WebKitDOMNode *sibling, *tmp;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+ sibling = webkit_dom_node_get_previous_sibling (block);
+ if (WEBKIT_DOM_IS_ELEMENT (sibling) &&
+ element_has_class (WEBKIT_DOM_ELEMENT (sibling), "-x-evo-indented")) {
+ element = WEBKIT_DOM_ELEMENT (sibling);
+ } else {
+ element = dom_get_indented_element (editor_page, width);
+
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (block),
+ WEBKIT_DOM_NODE (element),
+ block,
+ NULL);
+ }
+
+ /* Remove style and let the paragraph inherit it from parent */
+ if (webkit_dom_element_has_attribute (WEBKIT_DOM_ELEMENT (block), "data-evo-paragraph"))
+ webkit_dom_element_remove_attribute (
+ WEBKIT_DOM_ELEMENT (block), "style");
+
+ tmp = webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (element),
+ block,
+ NULL);
+
+ sibling = webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (element));
+
+ while (WEBKIT_DOM_IS_ELEMENT (sibling) &&
+ element_has_class (WEBKIT_DOM_ELEMENT (sibling), "-x-evo-indented")) {
+ WebKitDOMNode *next_sibling;
+ WebKitDOMNode *child;
+
+ next_sibling = webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (sibling));
+
+ while ((child = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (sibling)))) {
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (element),
+ child,
+ NULL);
+ }
+ remove_node (sibling);
+ sibling = next_sibling;
+ }
+
+ return tmp;
+}
+
+static WebKitDOMNode *
+get_list_item_node_from_child (WebKitDOMNode *child)
+{
+ WebKitDOMNode *parent = webkit_dom_node_get_parent_node (child);
+
+ while (parent && !WEBKIT_DOM_IS_HTML_LI_ELEMENT (parent))
+ parent = webkit_dom_node_get_parent_node (parent);
+
+ return parent;
+}
+
+static WebKitDOMNode *
+get_list_node_from_child (WebKitDOMNode *child)
+{
+ WebKitDOMNode *parent = get_list_item_node_from_child (child);
+
+ return webkit_dom_node_get_parent_node (parent);
+}
+
+static gboolean
+do_format_change_list_to_block (EEditorPage *editor_page,
+ EContentEditorBlockFormat format,
+ WebKitDOMNode *item,
+ const gchar *value)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *element, *selection_end;
+ WebKitDOMNode *node, *source_list;
+ gboolean after_end = FALSE;
+ gint level;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+ document = e_editor_page_get_document (editor_page);
+ selection_end = webkit_dom_document_query_selector (
+ document, "span#-x-evo-selection-end-marker", NULL);
+
+ source_list = webkit_dom_node_get_parent_node (item);
+ while (source_list) {
+ WebKitDOMNode *parent;
+
+ parent = webkit_dom_node_get_parent_node (source_list);
+ if (node_is_list (parent))
+ source_list = parent;
+ else
+ break;
+ }
+
+ if (webkit_dom_node_contains (source_list, WEBKIT_DOM_NODE (selection_end)))
+ source_list = split_list_into_two (item, -1);
+ else {
+ source_list = webkit_dom_node_get_next_sibling (source_list);
+ }
+
+ /* Process all nodes that are in selection one by one */
+ while (item && WEBKIT_DOM_IS_HTML_LI_ELEMENT (item)) {
+ WebKitDOMNode *next_item;
+
+ next_item = webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (item));
+ if (!next_item) {
+ WebKitDOMNode *parent;
+ WebKitDOMNode *tmp = item;
+
+ while (tmp) {
+ parent = webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (tmp));
+ if (!node_is_list (parent))
+ break;
+
+ next_item = webkit_dom_node_get_next_sibling (parent);
+ if (node_is_list (next_item)) {
+ next_item = webkit_dom_node_get_first_child (next_item);
+ break;
+ } else if (next_item && !WEBKIT_DOM_IS_HTML_LI_ELEMENT (next_item)) {
+ next_item = webkit_dom_node_get_next_sibling (next_item);
+ break;
+ } else if (WEBKIT_DOM_IS_HTML_LI_ELEMENT (next_item)) {
+ break;
+ }
+ tmp = parent;
+ }
+ } else if (node_is_list (next_item)) {
+ next_item = webkit_dom_node_get_first_child (next_item);
+ } else if (!WEBKIT_DOM_IS_HTML_LI_ELEMENT (next_item)) {
+ next_item = webkit_dom_node_get_next_sibling (item);
+ continue;
+ }
+
+ if (!after_end) {
+ after_end = webkit_dom_node_contains (item, WEBKIT_DOM_NODE (selection_end));
+
+ level = get_indentation_level (WEBKIT_DOM_ELEMENT (item));
+
+ if (format == E_CONTENT_EDITOR_BLOCK_FORMAT_PARAGRAPH) {
+ element = e_editor_dom_get_paragraph_element (editor_page, -1, 0);
+ } else
+ element = webkit_dom_document_create_element (
+ document, value, NULL);
+
+ while ((node = webkit_dom_node_get_first_child (item)))
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (element), node, NULL);
+
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (source_list),
+ WEBKIT_DOM_NODE (element),
+ source_list,
+ NULL);
+
+ if (level > 0) {
+ gint final_width = 0;
+
+ node = WEBKIT_DOM_NODE (element);
+
+ if (webkit_dom_element_has_attribute (element, "data-evo-paragraph"))
+ final_width = e_editor_page_get_word_wrap_length (editor_page) -
+ SPACES_PER_INDENTATION * level;
+
+ while (level--)
+ node = indent_block (editor_page, node, final_width);
+ }
+
+ e_editor_dom_remove_node_and_parents_if_empty (item);
+ } else
+ break;
+
+ item = next_item;
+ }
+
+ remove_node_if_empty (source_list);
+
+ return after_end;
+}
+
+static void
+format_change_list_to_block (EEditorPage *editor_page,
+ EContentEditorBlockFormat format,
+ const gchar *value)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *selection_start;
+ WebKitDOMNode *item;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+ selection_start = webkit_dom_document_query_selector (
+ document, "span#-x-evo-selection-start-marker", NULL);
+
+ item = get_list_item_node_from_child (WEBKIT_DOM_NODE (selection_start));
+
+ do_format_change_list_to_block (editor_page, format, item, value);
+}
+
+static WebKitDOMNode *
+get_parent_indented_block (WebKitDOMNode *node)
+{
+ WebKitDOMNode *parent, *block = NULL;
+
+ parent = webkit_dom_node_get_parent_node (node);
+ if (element_has_class (WEBKIT_DOM_ELEMENT (parent), "-x-evo-indented"))
+ block = parent;
+
+ while (parent && !WEBKIT_DOM_IS_HTML_BODY_ELEMENT (parent)) {
+ if (element_has_class (WEBKIT_DOM_ELEMENT (parent), "-x-evo-indented"))
+ block = parent;
+ parent = webkit_dom_node_get_parent_node (parent);
+ }
+
+ return block;
+}
+
+static WebKitDOMElement*
+get_element_for_inspection (WebKitDOMRange *range)
+{
+ WebKitDOMNode *node;
+
+ node = webkit_dom_range_get_end_container (range, NULL);
+ /* No selection or whole body selected */
+ if (WEBKIT_DOM_IS_HTML_BODY_ELEMENT (node))
+ return NULL;
+
+ return WEBKIT_DOM_ELEMENT (get_parent_indented_block (node));
+}
+
+static EContentEditorAlignment
+dom_get_alignment_from_node (WebKitDOMNode *node)
+{
+ EContentEditorAlignment alignment;
+ gchar *value;
+ WebKitDOMCSSStyleDeclaration *style = NULL;
+
+ style = webkit_dom_element_get_style (WEBKIT_DOM_ELEMENT (node));
+ value = webkit_dom_css_style_declaration_get_property_value (style, "text-align");
+
+ if (!value || !*value ||
+ (g_ascii_strncasecmp (value, "left", 4) == 0)) {
+ alignment = E_CONTENT_EDITOR_ALIGNMENT_LEFT;
+ } else if (g_ascii_strncasecmp (value, "center", 6) == 0) {
+ alignment = E_CONTENT_EDITOR_ALIGNMENT_CENTER;
+ } else if (g_ascii_strncasecmp (value, "right", 5) == 0) {
+ alignment = E_CONTENT_EDITOR_ALIGNMENT_RIGHT;
+ } else {
+ alignment = E_CONTENT_EDITOR_ALIGNMENT_LEFT;
+ }
+
+ g_clear_object (&style);
+ g_free (value);
+
+ return alignment;
+}
+
+/*
+ * e_html_editor_selection_indent:
+ * @selection: an #EEditorSelection
+ *
+ * Indents current paragraph by one level.
+ */
+void
+e_editor_dom_selection_indent (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *selection_start_marker, *selection_end_marker;
+ WebKitDOMNode *block;
+ EEditorHistoryEvent *ev = NULL;
+ EEditorUndoRedoManager *manager;
+ gboolean after_selection_start = FALSE, after_selection_end = FALSE;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+ e_editor_dom_selection_save (editor_page);
+
+ manager = e_editor_page_get_undo_redo_manager (editor_page);
+
+ selection_start_marker = webkit_dom_document_query_selector (
+ document, "span#-x-evo-selection-start-marker", NULL);
+
+ selection_end_marker = webkit_dom_document_query_selector (
+ document, "span#-x-evo-selection-end-marker", NULL);
+
+ /* If the selection was not saved, move it into the first child of body */
+ if (!selection_start_marker || !selection_end_marker) {
+ WebKitDOMHTMLElement *body;
+ WebKitDOMNode *child;
+
+ body = webkit_dom_document_get_body (document);
+ child = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (body));
+
+ dom_add_selection_markers_into_element_start (
+ document,
+ WEBKIT_DOM_ELEMENT (child),
+ &selection_start_marker,
+ &selection_end_marker);
+ }
+
+ if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+ ev = g_new0 (EEditorHistoryEvent, 1);
+ ev->type = HISTORY_INDENT;
+
+ e_editor_dom_selection_get_coordinates (editor_page,
+ &ev->before.start.x,
+ &ev->before.start.y,
+ &ev->before.end.x,
+ &ev->before.end.y);
+
+ ev->data.style.from = 1;
+ ev->data.style.to = 1;
+ }
+
+ block = get_parent_indented_block (
+ WEBKIT_DOM_NODE (selection_start_marker));
+ if (!block)
+ block = e_editor_dom_get_parent_block_node_from_child (
+ WEBKIT_DOM_NODE (selection_start_marker));
+
+ while (block && !after_selection_end) {
+ gint ii, length, level, word_wrap_length, final_width = 0;
+ WebKitDOMNode *next_block;
+ WebKitDOMNodeList *list = NULL;
+
+ word_wrap_length = e_editor_page_get_word_wrap_length (editor_page);
+
+ next_block = webkit_dom_node_get_next_sibling (block);
+
+ list = webkit_dom_element_query_selector_all (
+ WEBKIT_DOM_ELEMENT (block),
+ ".-x-evo-indented > *:not(.-x-evo-indented):not(li)",
+ NULL);
+
+ after_selection_end = webkit_dom_node_contains (
+ block, WEBKIT_DOM_NODE (selection_end_marker));
+
+ length = webkit_dom_node_list_get_length (list);
+ if (length == 0 && node_is_list_or_item (block)) {
+ after_selection_end = indent_list (editor_page);
+ goto next;
+ }
+
+ if (length == 0) {
+ if (!after_selection_start) {
+ after_selection_start = webkit_dom_node_contains (
+ block, WEBKIT_DOM_NODE (selection_start_marker));
+ if (!after_selection_start)
+ goto next;
+ }
+
+ if (webkit_dom_element_has_attribute (WEBKIT_DOM_ELEMENT (block),
"data-evo-paragraph")) {
+ level = get_indentation_level (WEBKIT_DOM_ELEMENT (block));
+
+ final_width = word_wrap_length - SPACES_PER_INDENTATION * (level + 1);
+ if (final_width < MINIMAL_PARAGRAPH_WIDTH &&
+ !e_editor_page_get_html_mode (editor_page))
+ goto next;
+ }
+
+ indent_block (editor_page, block, final_width);
+
+ if (after_selection_end)
+ goto next;
+ }
+
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMNode *block_to_process;
+
+ block_to_process = webkit_dom_node_list_item (list, ii);
+
+ after_selection_end = webkit_dom_node_contains (
+ block_to_process, WEBKIT_DOM_NODE (selection_end_marker));
+
+ if (!after_selection_start) {
+ after_selection_start = webkit_dom_node_contains (
+ block_to_process,
+ WEBKIT_DOM_NODE (selection_start_marker));
+ if (!after_selection_start) {
+ g_object_unref (block_to_process);
+ continue;
+ }
+ }
+
+ if (webkit_dom_element_has_attribute (WEBKIT_DOM_ELEMENT (block_to_process),
"data-evo-paragraph")) {
+ level = get_indentation_level (
+ WEBKIT_DOM_ELEMENT (block_to_process));
+
+ final_width = word_wrap_length - SPACES_PER_INDENTATION * (level + 1);
+ if (final_width < MINIMAL_PARAGRAPH_WIDTH &&
+ !e_editor_page_get_html_mode (editor_page)) {
+ g_object_unref (block_to_process);
+ continue;
+ }
+ }
+
+ indent_block (editor_page, block_to_process, final_width);
+
+ g_object_unref (block_to_process);
+ if (after_selection_end)
+ break;
+ }
+
+ next:
+ g_clear_object (&list);
+
+ if (!after_selection_end)
+ block = next_block;
+ }
+
+ if (ev) {
+ e_editor_dom_selection_get_coordinates (editor_page,
+ &ev->after.start.x,
+ &ev->after.start.y,
+ &ev->after.end.x,
+ &ev->after.end.y);
+ e_editor_undo_redo_manager_insert_history_event (manager, ev);
+ }
+
+ e_editor_dom_selection_restore (editor_page);
+ e_editor_dom_force_spell_check_for_current_paragraph (editor_page);
+}
+
+static void
+unindent_list (WebKitDOMDocument *document)
+{
+ gboolean after = FALSE;
+ WebKitDOMElement *new_list;
+ WebKitDOMElement *selection_start_marker, *selection_end_marker;
+ WebKitDOMNode *source_list, *source_list_clone, *current_list, *item;
+ WebKitDOMNode *prev_item;
+
+ selection_start_marker = webkit_dom_document_query_selector (
+ document, "span#-x-evo-selection-start-marker", NULL);
+ selection_end_marker = webkit_dom_document_query_selector (
+ document, "span#-x-evo-selection-end-marker", NULL);
+
+ if (!selection_start_marker || !selection_end_marker)
+ return;
+
+ /* Copy elements from previous block to list */
+ item = e_editor_dom_get_parent_block_node_from_child (
+ WEBKIT_DOM_NODE (selection_start_marker));
+ source_list = webkit_dom_node_get_parent_node (item);
+ new_list = WEBKIT_DOM_ELEMENT (
+ webkit_dom_node_clone_node_with_error (source_list, FALSE, NULL));
+ current_list = source_list;
+ source_list_clone = webkit_dom_node_clone_node_with_error (source_list, FALSE, NULL);
+
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (source_list),
+ WEBKIT_DOM_NODE (source_list_clone),
+ webkit_dom_node_get_next_sibling (source_list),
+ NULL);
+
+ if (element_has_class (WEBKIT_DOM_ELEMENT (source_list), "-x-evo-indented"))
+ element_add_class (WEBKIT_DOM_ELEMENT (new_list), "-x-evo-indented");
+
+ prev_item = source_list;
+
+ while (item) {
+ WebKitDOMNode *next_item = webkit_dom_node_get_next_sibling (item);
+
+ if (WEBKIT_DOM_IS_HTML_LI_ELEMENT (item)) {
+ if (after)
+ prev_item = webkit_dom_node_append_child (
+ source_list_clone, WEBKIT_DOM_NODE (item), NULL);
+ else
+ prev_item = webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (prev_item),
+ item,
+ webkit_dom_node_get_next_sibling (prev_item),
+ NULL);
+ }
+
+ if (webkit_dom_node_contains (item, WEBKIT_DOM_NODE (selection_end_marker)))
+ after = TRUE;
+
+ if (!next_item) {
+ if (after)
+ break;
+
+ current_list = webkit_dom_node_get_next_sibling (current_list);
+ next_item = webkit_dom_node_get_first_child (current_list);
+ }
+ item = next_item;
+ }
+
+ remove_node_if_empty (source_list_clone);
+ remove_node_if_empty (source_list);
+}
+
+static void
+unindent_block (EEditorPage *editor_page,
+ WebKitDOMNode *block)
+{
+ WebKitDOMElement *element;
+ WebKitDOMElement *prev_blockquote = NULL, *next_blockquote = NULL;
+ WebKitDOMNode *block_to_process, *node_clone = NULL, *child;
+ EContentEditorAlignment alignment;
+ gboolean before_node = TRUE;
+ gint word_wrap_length, level, width;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ block_to_process = block;
+
+ alignment = dom_get_alignment_from_node (block_to_process);
+ element = webkit_dom_node_get_parent_element (block_to_process);
+
+ if (!WEBKIT_DOM_IS_HTML_DIV_ELEMENT (element) &&
+ !element_has_class (element, "-x-evo-indented"))
+ return;
+
+ element_add_class (WEBKIT_DOM_ELEMENT (block_to_process), "-x-evo-to-unindent");
+
+ level = get_indentation_level (element);
+ word_wrap_length = e_editor_page_get_word_wrap_length (editor_page);
+ width = word_wrap_length - SPACES_PER_INDENTATION * level;
+
+ /* Look if we have previous siblings, if so, we have to
+ * create new blockquote that will include them */
+ if (webkit_dom_node_get_previous_sibling (block_to_process))
+ prev_blockquote = dom_get_indented_element (editor_page, width);
+
+ /* Look if we have next siblings, if so, we have to
+ * create new blockquote that will include them */
+ if (webkit_dom_node_get_next_sibling (block_to_process))
+ next_blockquote = dom_get_indented_element (editor_page, width);
+
+ /* Copy nodes that are before / after the element that we want to unindent */
+ while ((child = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (element)))) {
+ if (webkit_dom_node_is_equal_node (child, block_to_process)) {
+ before_node = FALSE;
+ node_clone = webkit_dom_node_clone_node_with_error (child, TRUE, NULL);
+ remove_node (child);
+ continue;
+ }
+
+ webkit_dom_node_append_child (
+ before_node ?
+ WEBKIT_DOM_NODE (prev_blockquote) :
+ WEBKIT_DOM_NODE (next_blockquote),
+ child,
+ NULL);
+ }
+
+ if (node_clone) {
+ element_remove_class (WEBKIT_DOM_ELEMENT (node_clone), "-x-evo-to-unindent");
+
+ /* Insert blockqoute with nodes that were before the element that we want to unindent */
+ if (prev_blockquote) {
+ if (webkit_dom_node_has_child_nodes (WEBKIT_DOM_NODE (prev_blockquote))) {
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element)),
+ WEBKIT_DOM_NODE (prev_blockquote),
+ WEBKIT_DOM_NODE (element),
+ NULL);
+ }
+ }
+
+ if (level == 1 && webkit_dom_element_has_attribute (WEBKIT_DOM_ELEMENT (node_clone),
"data-evo-paragraph")) {
+ e_editor_dom_set_paragraph_style (
+ editor_page, WEBKIT_DOM_ELEMENT (node_clone), word_wrap_length, 0, NULL);
+ element_add_class (
+ WEBKIT_DOM_ELEMENT (node_clone),
+ get_css_alignment_value_class (alignment));
+ }
+
+ /* Insert the unindented element */
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element)),
+ node_clone,
+ WEBKIT_DOM_NODE (element),
+ NULL);
+ } else {
+ g_warn_if_reached ();
+ }
+
+ /* Insert blockqoute with nodes that were after the element that we want to unindent */
+ if (next_blockquote) {
+ if (webkit_dom_node_has_child_nodes (WEBKIT_DOM_NODE (next_blockquote))) {
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element)),
+ WEBKIT_DOM_NODE (next_blockquote),
+ WEBKIT_DOM_NODE (element),
+ NULL);
+ }
+ }
+
+ /* Remove old blockquote */
+ remove_node (WEBKIT_DOM_NODE (element));
+}
+
+/*
+ * dom_unindent:
+ * @selection: an #EEditorSelection
+ *
+ * Unindents current paragraph by one level.
+ */
+void
+e_editor_dom_selection_unindent (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *selection_start_marker, *selection_end_marker;
+ WebKitDOMNode *block;
+ EEditorHistoryEvent *ev = NULL;
+ EEditorUndoRedoManager *manager;
+ gboolean after_selection_start = FALSE, after_selection_end = FALSE;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+ e_editor_dom_selection_save (editor_page);
+
+ selection_start_marker = webkit_dom_document_query_selector (
+ document, "span#-x-evo-selection-start-marker", NULL);
+ selection_end_marker = webkit_dom_document_query_selector (
+ document, "span#-x-evo-selection-end-marker", NULL);
+
+ /* If the selection was not saved, move it into the first child of body */
+ if (!selection_start_marker || !selection_end_marker) {
+ WebKitDOMHTMLElement *body;
+ WebKitDOMNode *child;
+
+ body = webkit_dom_document_get_body (document);
+ child = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (body));
+
+ dom_add_selection_markers_into_element_start (
+ document,
+ WEBKIT_DOM_ELEMENT (child),
+ &selection_start_marker,
+ &selection_end_marker);
+ }
+
+ manager = e_editor_page_get_undo_redo_manager (editor_page);
+ if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+ ev = g_new0 (EEditorHistoryEvent, 1);
+ ev->type = HISTORY_INDENT;
+
+ e_editor_dom_selection_get_coordinates (editor_page,
+ &ev->before.start.x,
+ &ev->before.start.y,
+ &ev->before.end.x,
+ &ev->before.end.y);
+ }
+
+ block = get_parent_indented_block (
+ WEBKIT_DOM_NODE (selection_start_marker));
+ if (!block)
+ block = e_editor_dom_get_parent_block_node_from_child (
+ WEBKIT_DOM_NODE (selection_start_marker));
+
+ while (block && !after_selection_end) {
+ gint ii, length;
+ WebKitDOMNode *next_block;
+ WebKitDOMNodeList *list = NULL;
+
+ next_block = webkit_dom_node_get_next_sibling (block);
+
+ list = webkit_dom_element_query_selector_all (
+ WEBKIT_DOM_ELEMENT (block),
+ ".-x-evo-indented > *:not(.-x-evo-indented):not(li)",
+ NULL);
+
+ after_selection_end = webkit_dom_node_contains (
+ block, WEBKIT_DOM_NODE (selection_end_marker));
+
+ length = webkit_dom_node_list_get_length (list);
+ if (length == 0 && node_is_list_or_item (block)) {
+ unindent_list (document);
+ goto next;
+ }
+
+ if (length == 0) {
+ if (!after_selection_start) {
+ after_selection_start = webkit_dom_node_contains (
+ block, WEBKIT_DOM_NODE (selection_start_marker));
+ if (!after_selection_start)
+ goto next;
+ }
+
+ unindent_block (editor_page, block);
+
+ if (after_selection_end)
+ goto next;
+ }
+
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMNode *block_to_process;
+
+ block_to_process = webkit_dom_node_list_item (list, ii);
+
+ after_selection_end = webkit_dom_node_contains (
+ block_to_process,
+ WEBKIT_DOM_NODE (selection_end_marker));
+
+ if (!after_selection_start) {
+ after_selection_start = webkit_dom_node_contains (
+ block_to_process,
+ WEBKIT_DOM_NODE (selection_start_marker));
+ if (!after_selection_start) {
+ g_object_unref (block_to_process);
+ continue;
+ }
+ }
+
+ unindent_block (editor_page, block_to_process);
+
+ g_object_unref (block_to_process);
+ if (after_selection_end)
+ break;
+ }
+ next:
+ g_clear_object (&list);
+ block = next_block;
+ }
+
+ if (ev) {
+ e_editor_dom_selection_get_coordinates (editor_page,
+ &ev->after.start.x,
+ &ev->after.start.y,
+ &ev->after.end.x,
+ &ev->after.end.y);
+ e_editor_undo_redo_manager_insert_history_event (manager, ev);
+ }
+
+ e_editor_dom_selection_restore (editor_page);
+
+ e_editor_dom_force_spell_check_for_current_paragraph (editor_page);
+}
+
+static WebKitDOMNode *
+in_empty_block_in_quoted_content (WebKitDOMNode *element)
+{
+ WebKitDOMNode *first_child, *next_sibling;
+
+ first_child = webkit_dom_node_get_first_child (element);
+ if (!WEBKIT_DOM_IS_ELEMENT (first_child))
+ return NULL;
+
+ if (!element_has_class (WEBKIT_DOM_ELEMENT (first_child), "-x-evo-quoted"))
+ return NULL;
+
+ next_sibling = webkit_dom_node_get_next_sibling (first_child);
+ if (WEBKIT_DOM_IS_HTML_BR_ELEMENT (next_sibling))
+ return next_sibling;
+
+ if (!WEBKIT_DOM_IS_ELEMENT (next_sibling))
+ return NULL;
+
+ if (!element_has_id (WEBKIT_DOM_ELEMENT (next_sibling), "-x-evo-selection-start-marker"))
+ return NULL;
+
+ next_sibling = webkit_dom_node_get_next_sibling (next_sibling);
+ if (WEBKIT_DOM_IS_HTML_BR_ELEMENT (next_sibling))
+ return next_sibling;
+
+ return NULL;
+}
+
+/*
+ * e_html_editor_selection_save:
+ * @selection: an #EEditorSelection
+ *
+ * Saves current cursor position or current selection range. The selection can
+ * be later restored by calling e_html_editor_selection_restore().
+ *
+ * Note that calling e_html_editor_selection_save() overwrites previously saved
+ * position.
+ *
+ * Note that this method inserts special markings into the HTML code that are
+ * used to later restore the selection. It can happen that by deleting some
+ * segments of the document some of the markings are deleted too. In that case
+ * restoring the selection by e_html_editor_selection_restore() can fail. Also by
+ * moving text segments (Cut & Paste) can result in moving the markings
+ * elsewhere, thus e_html_editor_selection_restore() will restore the selection
+ * incorrectly.
+ *
+ * It is recommended to use this method only when you are not planning to make
+ * bigger changes to content or structure of the document (formatting changes
+ * are usually OK).
+ */
+void
+e_editor_dom_selection_save (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMDOMWindow *dom_window = NULL;
+ WebKitDOMDOMSelection *dom_selection = NULL;
+ WebKitDOMRange *range = NULL;
+ WebKitDOMNode *container, *next_sibling, *marker_node;
+ WebKitDOMNode *split_node, *parent_node, *anchor;
+ WebKitDOMElement *start_marker = NULL, *end_marker = NULL;
+ gboolean collapsed = FALSE;
+ glong offset, anchor_offset;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+
+ /* First remove all markers (if present) */
+ dom_remove_selection_markers (document);
+
+ dom_window = webkit_dom_document_get_default_view (document);
+ dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+ g_clear_object (&dom_window);
+
+ if (webkit_dom_dom_selection_get_range_count (dom_selection) < 1) {
+ g_clear_object (&dom_selection);
+ return;
+ }
+
+ range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+ if (!range) {
+ g_clear_object (&dom_selection);
+ return;
+ }
+
+ anchor = webkit_dom_dom_selection_get_anchor_node (dom_selection);
+ anchor_offset = webkit_dom_dom_selection_get_anchor_offset (dom_selection);
+
+ collapsed = webkit_dom_range_get_collapsed (range, NULL);
+ start_marker = dom_create_selection_marker (document, TRUE);
+
+ container = webkit_dom_range_get_start_container (range, NULL);
+ offset = webkit_dom_range_get_start_offset (range, NULL);
+ parent_node = webkit_dom_node_get_parent_node (container);
+
+ if (webkit_dom_node_is_same_node (anchor, container) && offset == anchor_offset)
+ webkit_dom_element_set_attribute (start_marker, "data-anchor", "", NULL);
+
+ if (element_has_class (WEBKIT_DOM_ELEMENT (parent_node), "-x-evo-quote-character")) {
+ WebKitDOMNode *node;
+
+ node = webkit_dom_node_get_parent_node (
+ webkit_dom_node_get_parent_node (parent_node));
+
+ if ((next_sibling = in_empty_block_in_quoted_content (node))) {
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (next_sibling),
+ WEBKIT_DOM_NODE (start_marker),
+ next_sibling,
+ NULL);
+ } else {
+ webkit_dom_node_insert_before (
+ node,
+ WEBKIT_DOM_NODE (start_marker),
+ webkit_dom_node_get_next_sibling (
+ webkit_dom_node_get_parent_node (parent_node)),
+ NULL);
+ }
+ goto insert_end_marker;
+ } else if (element_has_class (WEBKIT_DOM_ELEMENT (parent_node), "-x-evo-smiley-text")) {
+ WebKitDOMNode *node;
+
+ node = webkit_dom_node_get_parent_node (parent_node);
+ if (offset == 0) {
+ marker_node = webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (node),
+ WEBKIT_DOM_NODE (start_marker),
+ webkit_dom_node_get_next_sibling (node),
+ NULL);
+ goto insert_end_marker;
+ }
+ } else if (element_has_class (WEBKIT_DOM_ELEMENT (parent_node), "Apple-tab-span") && offset == 1) {
+ marker_node = webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (parent_node),
+ WEBKIT_DOM_NODE (start_marker),
+ webkit_dom_node_get_next_sibling (parent_node),
+ NULL);
+ goto insert_end_marker;
+ }
+
+ if (WEBKIT_DOM_IS_TEXT (container)) {
+ if (offset != 0) {
+ WebKitDOMText *split_text;
+
+ split_text = webkit_dom_text_split_text (
+ WEBKIT_DOM_TEXT (container), offset, NULL);
+ split_node = WEBKIT_DOM_NODE (split_text);
+ } else {
+ marker_node = webkit_dom_node_insert_before (
+ parent_node,
+ WEBKIT_DOM_NODE (start_marker),
+ container,
+ NULL);
+ goto insert_end_marker;
+ }
+ } else if (WEBKIT_DOM_IS_HTML_LI_ELEMENT (container)) {
+ marker_node = webkit_dom_node_insert_before (
+ container,
+ WEBKIT_DOM_NODE (start_marker),
+ webkit_dom_node_get_first_child (container),
+ NULL);
+ goto insert_end_marker;
+ } else if (WEBKIT_DOM_IS_HTML_TABLE_CELL_ELEMENT (container)) {
+ marker_node = webkit_dom_node_insert_before (
+ container,
+ WEBKIT_DOM_NODE (start_marker),
+ webkit_dom_node_get_first_child (container),
+ NULL);
+ goto insert_end_marker;
+ } else {
+ /* Insert the selection marker on the right position in
+ * an empty paragraph in the quoted content */
+ if ((next_sibling = in_empty_block_in_quoted_content (container))) {
+ marker_node = webkit_dom_node_insert_before (
+ container,
+ WEBKIT_DOM_NODE (start_marker),
+ next_sibling,
+ NULL);
+ goto insert_end_marker;
+ }
+ if (!webkit_dom_node_get_previous_sibling (container)) {
+ marker_node = webkit_dom_node_insert_before (
+ container,
+ WEBKIT_DOM_NODE (start_marker),
+ webkit_dom_node_get_first_child (container),
+ NULL);
+ goto insert_end_marker;
+ } else if (!webkit_dom_node_get_next_sibling (container)) {
+ WebKitDOMNode *tmp;
+
+ tmp = webkit_dom_node_get_last_child (container);
+ if (tmp && WEBKIT_DOM_IS_HTML_BR_ELEMENT (tmp))
+ marker_node = webkit_dom_node_insert_before (
+ container,
+ WEBKIT_DOM_NODE (start_marker),
+ tmp,
+ NULL);
+ else
+ marker_node = webkit_dom_node_append_child (
+ container,
+ WEBKIT_DOM_NODE (start_marker),
+ NULL);
+ goto insert_end_marker;
+ } else {
+ if (webkit_dom_node_get_first_child (container)) {
+ marker_node = webkit_dom_node_insert_before (
+ container,
+ WEBKIT_DOM_NODE (start_marker),
+ webkit_dom_node_get_first_child (container),
+ NULL);
+ goto insert_end_marker;
+ }
+ split_node = container;
+ }
+ }
+
+ /* Don't save selection straight into body */
+ if (WEBKIT_DOM_IS_HTML_BODY_ELEMENT (split_node)) {
+ g_clear_object (&range);
+ g_clear_object (&dom_selection);
+ return;
+ }
+
+ if (!split_node) {
+ marker_node = webkit_dom_node_insert_before (
+ container,
+ WEBKIT_DOM_NODE (start_marker),
+ webkit_dom_node_get_first_child (
+ WEBKIT_DOM_NODE (container)),
+ NULL);
+ } else {
+ marker_node = WEBKIT_DOM_NODE (start_marker);
+ parent_node = webkit_dom_node_get_parent_node (split_node);
+
+ webkit_dom_node_insert_before (
+ parent_node, marker_node, split_node, NULL);
+ }
+
+ webkit_dom_node_normalize (parent_node);
+
+ insert_end_marker:
+ end_marker = dom_create_selection_marker (document, FALSE);
+
+ if (collapsed) {
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (start_marker)),
+ WEBKIT_DOM_NODE (end_marker),
+ webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (start_marker)),
+ NULL);
+ goto out;
+ }
+
+ container = webkit_dom_range_get_end_container (range, NULL);
+ offset = webkit_dom_range_get_end_offset (range, NULL);
+ parent_node = webkit_dom_node_get_parent_node (container);
+
+ if (webkit_dom_node_is_same_node (anchor, container) && offset == anchor_offset)
+ webkit_dom_element_set_attribute (end_marker, "data-anchor", "", NULL);
+
+ if (element_has_class (WEBKIT_DOM_ELEMENT (parent_node), "-x-evo-quote-character")) {
+ WebKitDOMNode *node;
+
+ node = webkit_dom_node_get_parent_node (
+ webkit_dom_node_get_parent_node (parent_node));
+
+ if ((next_sibling = in_empty_block_in_quoted_content (node))) {
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (next_sibling),
+ WEBKIT_DOM_NODE (end_marker),
+ next_sibling,
+ NULL);
+ } else {
+ webkit_dom_node_insert_before (
+ node,
+ WEBKIT_DOM_NODE (end_marker),
+ webkit_dom_node_get_next_sibling (
+ webkit_dom_node_get_parent_node (parent_node)),
+ NULL);
+ }
+ goto out;
+ }
+
+ if (WEBKIT_DOM_IS_TEXT (container)) {
+ if (offset != 0) {
+ WebKitDOMText *split_text;
+
+ split_text = webkit_dom_text_split_text (
+ WEBKIT_DOM_TEXT (container), offset, NULL);
+ split_node = WEBKIT_DOM_NODE (split_text);
+ } else {
+ marker_node = webkit_dom_node_insert_before (
+ parent_node, WEBKIT_DOM_NODE (end_marker), container, NULL);
+ goto check;
+
+ }
+ } else if (WEBKIT_DOM_IS_HTML_LI_ELEMENT (container)) {
+ webkit_dom_node_append_child (
+ container, WEBKIT_DOM_NODE (end_marker), NULL);
+ goto out;
+ } else {
+ /* Insert the selection marker on the right position in
+ * an empty paragraph in the quoted content */
+ if ((next_sibling = in_empty_block_in_quoted_content (container))) {
+ webkit_dom_node_insert_before (
+ container,
+ WEBKIT_DOM_NODE (end_marker),
+ next_sibling,
+ NULL);
+ goto out;
+ }
+ if (!webkit_dom_node_get_previous_sibling (container)) {
+ split_node = parent_node;
+ } else if (!webkit_dom_node_get_next_sibling (container) &&
+ !WEBKIT_DOM_IS_HTML_BODY_ELEMENT (parent_node)) {
+ split_node = parent_node;
+ split_node = webkit_dom_node_get_next_sibling (split_node);
+ } else
+ split_node = container;
+ }
+
+ /* Don't save selection straight into body */
+ if (WEBKIT_DOM_IS_HTML_BODY_ELEMENT (split_node)) {
+ remove_node (WEBKIT_DOM_NODE (start_marker));
+ return;
+ }
+
+ marker_node = WEBKIT_DOM_NODE (end_marker);
+
+ if (split_node) {
+ parent_node = webkit_dom_node_get_parent_node (split_node);
+
+ if (WEBKIT_DOM_IS_HTML_BODY_ELEMENT (parent_node)) {
+ if (offset == 0)
+ webkit_dom_node_insert_before (
+ split_node,
+ marker_node,
+ webkit_dom_node_get_first_child (split_node),
+ NULL);
+ else
+ webkit_dom_node_append_child (
+ webkit_dom_node_get_previous_sibling (split_node),
+ marker_node,
+ NULL);
+ } else
+ webkit_dom_node_insert_before (
+ parent_node, marker_node, split_node, NULL);
+ } else {
+ WebKitDOMNode *first_child;
+
+ first_child = webkit_dom_node_get_first_child (container);
+ if (offset == 0 && WEBKIT_DOM_IS_TEXT (first_child))
+ webkit_dom_node_insert_before (
+ WEBKIT_DOM_NODE (container), marker_node, webkit_dom_node_get_first_child
(container), NULL);
+ else
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (container), marker_node, NULL);
+ }
+
+ webkit_dom_node_normalize (parent_node);
+
+ check:
+ if ((next_sibling = webkit_dom_node_get_next_sibling (marker_node))) {
+ if (!WEBKIT_DOM_IS_ELEMENT (next_sibling))
+ next_sibling = webkit_dom_node_get_next_sibling (next_sibling);
+ /* If the selection is collapsed ensure that the selection start marker
+ * is before the end marker */
+ if (next_sibling && webkit_dom_node_is_same_node (next_sibling, WEBKIT_DOM_NODE
(start_marker))) {
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (marker_node),
+ next_sibling,
+ marker_node,
+ NULL);
+ }
+ }
+ out:
+ if (!collapsed) {
+ if (start_marker && end_marker) {
+ webkit_dom_range_set_start_after (range, WEBKIT_DOM_NODE (start_marker), NULL);
+ webkit_dom_range_set_end_before (range, WEBKIT_DOM_NODE (end_marker), NULL);
+ } else {
+ g_warn_if_reached ();
+ }
+
+ webkit_dom_dom_selection_remove_all_ranges (dom_selection);
+ webkit_dom_dom_selection_add_range (dom_selection, range);
+ }
+
+ g_clear_object (&range);
+ g_clear_object (&dom_selection);
+}
+
+gboolean
+e_editor_dom_is_selection_position_node (WebKitDOMNode *node)
+{
+ WebKitDOMElement *element;
+
+ if (!node || !WEBKIT_DOM_IS_ELEMENT (node))
+ return FALSE;
+
+ element = WEBKIT_DOM_ELEMENT (node);
+
+ return element_has_id (element, "-x-evo-selection-start-marker") ||
+ element_has_id (element, "-x-evo-selection-end-marker");
+}
+
+/*
+ * e_html_editor_selection_restore:
+ * @selection: an #EEditorSelection
+ *
+ * Restores cursor position or selection range that was saved by
+ * e_html_editor_selection_save().
+ *
+ * Note that calling this function without calling e_html_editor_selection_save()
+ * before is a programming error and the behavior is undefined.
+ */
+void
+e_editor_dom_selection_restore (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *marker;
+ WebKitDOMNode *selection_start_marker, *selection_end_marker;
+ WebKitDOMNode *parent_start, *parent_end, *anchor;
+ WebKitDOMRange *range = NULL;
+ WebKitDOMDOMSelection *dom_selection = NULL;
+ WebKitDOMDOMWindow *dom_window = NULL;
+ gboolean start_is_anchor = FALSE;
+ glong offset;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+ dom_window = webkit_dom_document_get_default_view (document);
+ dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+ range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+ g_clear_object (&dom_window);
+ if (!range) {
+ WebKitDOMHTMLElement *body;
+
+ range = webkit_dom_document_create_range (document);
+ body = webkit_dom_document_get_body (document);
+
+ webkit_dom_range_select_node_contents (range, WEBKIT_DOM_NODE (body), NULL);
+ webkit_dom_range_collapse (range, TRUE, NULL);
+ webkit_dom_dom_selection_add_range (dom_selection, range);
+ }
+
+ selection_start_marker = webkit_dom_range_get_start_container (range, NULL);
+ if (selection_start_marker) {
+ gboolean ok = FALSE;
+ selection_start_marker =
+ webkit_dom_node_get_next_sibling (selection_start_marker);
+
+ ok = e_editor_dom_is_selection_position_node (selection_start_marker);
+
+ if (ok) {
+ ok = FALSE;
+ if (webkit_dom_range_get_collapsed (range, NULL)) {
+ selection_end_marker = webkit_dom_node_get_next_sibling (
+ selection_start_marker);
+
+ ok = e_editor_dom_is_selection_position_node (selection_end_marker);
+ if (ok) {
+ WebKitDOMNode *next_sibling;
+
+ next_sibling = webkit_dom_node_get_next_sibling
(selection_end_marker);
+
+ if (next_sibling && !WEBKIT_DOM_IS_HTML_BR_ELEMENT (next_sibling)) {
+ parent_start = webkit_dom_node_get_parent_node
(selection_end_marker);
+
+ remove_node (selection_start_marker);
+ remove_node (selection_end_marker);
+
+ webkit_dom_node_normalize (parent_start);
+ g_clear_object (&range);
+ g_clear_object (&dom_selection);
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ g_clear_object (&range);
+ range = webkit_dom_document_create_range (document);
+ if (!range) {
+ g_clear_object (&dom_selection);
+ return;
+ }
+
+ marker = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-start-marker");
+ if (!marker) {
+ marker = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-end-marker");
+ if (marker)
+ remove_node (WEBKIT_DOM_NODE (marker));
+ g_clear_object (&dom_selection);
+ g_clear_object (&range);
+ return;
+ }
+
+ start_is_anchor = webkit_dom_element_has_attribute (marker, "data-anchor");
+ parent_start = webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (marker));
+
+ webkit_dom_range_set_start_after (range, WEBKIT_DOM_NODE (marker), NULL);
+ remove_node (WEBKIT_DOM_NODE (marker));
+
+ marker = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-end-marker");
+ if (!marker) {
+ marker = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-start-marker");
+ if (marker)
+ remove_node (WEBKIT_DOM_NODE (marker));
+ g_clear_object (&dom_selection);
+ g_clear_object (&range);
+ return;
+ }
+
+ parent_end = webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (marker));
+
+ webkit_dom_range_set_end_before (range, WEBKIT_DOM_NODE (marker), NULL);
+ remove_node (WEBKIT_DOM_NODE (marker));
+
+ webkit_dom_dom_selection_remove_all_ranges (dom_selection);
+ if (webkit_dom_node_is_same_node (parent_start, parent_end))
+ webkit_dom_node_normalize (parent_start);
+ else {
+ webkit_dom_node_normalize (parent_start);
+ webkit_dom_node_normalize (parent_end);
+ }
+
+ if (start_is_anchor) {
+ anchor = webkit_dom_range_get_end_container (range, NULL);
+ offset = webkit_dom_range_get_end_offset (range, NULL);
+
+ webkit_dom_range_collapse (range, TRUE, NULL);
+ } else {
+ anchor = webkit_dom_range_get_start_container (range, NULL);
+ offset = webkit_dom_range_get_start_offset (range, NULL);
+
+ webkit_dom_range_collapse (range, FALSE, NULL);
+ }
+ webkit_dom_dom_selection_add_range (dom_selection, range);
+ webkit_dom_dom_selection_extend (dom_selection, anchor, offset, NULL);
+
+ g_clear_object (&dom_selection);
+ g_clear_object (&range);
+}
+
+static gint
+find_where_to_break_line (WebKitDOMCharacterData *node,
+ gint max_length)
+{
+ gboolean last_break_position_is_dash = FALSE;
+ gchar *str, *text_start;
+ gunichar uc;
+ gint pos = 1, last_break_position = 0, ret_val = 0;
+
+ text_start = webkit_dom_character_data_get_data (node);
+
+ str = text_start;
+ do {
+ uc = g_utf8_get_char (str);
+ if (!uc) {
+ ret_val = pos <= max_length ? pos : last_break_position > 0 ? last_break_position - 1
: 0;
+ goto out;
+ }
+
+ if ((g_unichar_isspace (uc) && !(g_unichar_break_type (uc) ==
G_UNICODE_BREAK_NON_BREAKING_GLUE)) ||
+ *str == '-') {
+ if ((last_break_position_is_dash = *str == '-')) {
+ /* There was no space before the dash */
+ if (pos - 1 != last_break_position) {
+ gchar *rest;
+
+ rest = g_utf8_next_char (str);
+ if (rest && *rest) {
+ gunichar next_char;
+
+ /* There is no space after the dash */
+ next_char = g_utf8_get_char (rest);
+ if (g_unichar_isspace (next_char))
+ last_break_position_is_dash = FALSE;
+ else
+ last_break_position = pos;
+ } else
+ last_break_position_is_dash = FALSE;
+ } else
+ last_break_position_is_dash = FALSE;
+ } else
+ last_break_position = pos;
+ }
+
+ if ((pos == max_length)) {
+ /* Look one character after the limit to check if there
+ * is a space (skip dash) that we are allowed to break at, if so
+ * break it there. */
+ if (*str) {
+ str = g_utf8_next_char (str);
+ uc = g_utf8_get_char (str);
+
+ if ((g_unichar_isspace (uc) &&
+ !(g_unichar_break_type (uc) == G_UNICODE_BREAK_NON_BREAKING_GLUE)))
+ last_break_position = ++pos;
+ }
+ break;
+ }
+
+ pos++;
+ str = g_utf8_next_char (str);
+ } while (*str);
+
+ if (last_break_position != 0)
+ ret_val = last_break_position - 1;
+ out:
+ g_free (text_start);
+
+ /* Always break after the dash character. */
+ if (last_break_position_is_dash)
+ ret_val++;
+
+ /* No character to break at is found. We should split at max_length, but
+ * we will leave the decision on caller as it depends on context. */
+ if (ret_val == 0 && last_break_position == 0)
+ ret_val = -1;
+
+ return ret_val;
+}
+
+/*
+ * e_html_editor_selection_is_collapsed:
+ * @selection: an #EEditorSelection
+ *
+ * Returns if selection is collapsed.
+ *
+ * Returns: Whether the selection is collapsed (just caret) or not (someting is selected).
+ */
+gboolean
+e_editor_dom_selection_is_collapsed (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMDOMWindow *dom_window = NULL;
+ WebKitDOMDOMSelection *dom_selection = NULL;
+ gboolean collapsed;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+ document = e_editor_page_get_document (editor_page);
+ if (!(dom_window = webkit_dom_document_get_default_view (document)))
+ return FALSE;
+
+ if (!(dom_selection = webkit_dom_dom_window_get_selection (dom_window))) {
+ g_clear_object (&dom_window);
+ return FALSE;
+ }
+
+ collapsed = webkit_dom_dom_selection_get_is_collapsed (dom_selection);
+
+ g_clear_object (&dom_selection);
+
+ return collapsed;
+}
+
+void
+e_editor_dom_scroll_to_caret (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMDOMWindow *dom_window = NULL;
+ WebKitDOMElement *selection_start_marker;
+ glong element_top, element_left;
+ glong window_top, window_left, window_right, window_bottom;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+ e_editor_dom_selection_save (editor_page);
+
+ selection_start_marker = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-start-marker");
+ if (!selection_start_marker)
+ return;
+
+ dom_window = webkit_dom_document_get_default_view (document);
+
+ window_top = webkit_dom_dom_window_get_scroll_y (dom_window);
+ window_left = webkit_dom_dom_window_get_scroll_x (dom_window);
+ window_bottom = window_top + webkit_dom_dom_window_get_inner_height (dom_window);
+ window_right = window_left + webkit_dom_dom_window_get_inner_width (dom_window);
+
+ element_left = webkit_dom_element_get_offset_left (selection_start_marker);
+ element_top = webkit_dom_element_get_offset_top (selection_start_marker);
+
+ /* Check if caret is inside viewport, if not move to it */
+ if (!(element_top >= window_top && element_top <= window_bottom &&
+ element_left >= window_left && element_left <= window_right)) {
+ webkit_dom_element_scroll_into_view (selection_start_marker, TRUE);
+ }
+
+ e_editor_dom_selection_restore (editor_page);
+
+ g_clear_object (&dom_window);
+}
+
+static void
+mark_and_remove_trailing_space (WebKitDOMDocument *document,
+ WebKitDOMNode *node)
+{
+ WebKitDOMElement *element;
+
+ element = webkit_dom_document_create_element (document, "SPAN", NULL);
+ webkit_dom_element_set_attribute (element, "data-hidden-space", "", NULL);
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (node),
+ WEBKIT_DOM_NODE (element),
+ webkit_dom_node_get_next_sibling (node),
+ NULL);
+ webkit_dom_character_data_replace_data (
+ WEBKIT_DOM_CHARACTER_DATA (node),
+ webkit_dom_character_data_get_length (WEBKIT_DOM_CHARACTER_DATA (node)),
+ 1,
+ "",
+ NULL);
+}
+
+static void
+mark_and_remove_leading_space (WebKitDOMDocument *document,
+ WebKitDOMNode *node)
+{
+ WebKitDOMElement *element;
+
+ element = webkit_dom_document_create_element (document, "SPAN", NULL);
+ webkit_dom_element_set_attribute (element, "data-hidden-space", "", NULL);
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (node),
+ WEBKIT_DOM_NODE (element),
+ node,
+ NULL);
+ webkit_dom_character_data_replace_data (
+ WEBKIT_DOM_CHARACTER_DATA (node), 0, 1, "", NULL);
+}
+
+static WebKitDOMElement *
+wrap_lines (EEditorPage *editor_page,
+ WebKitDOMNode *block,
+ gboolean remove_all_br,
+ gint length_to_wrap,
+ gint word_wrap_length)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *selection_start_marker, *selection_end_marker;
+ WebKitDOMNode *node, *start_node, *block_clone = NULL;
+ WebKitDOMNode *start_point = NULL, *first_child, *last_child;
+ guint line_length;
+ gulong length_left;
+ gchar *text_content;
+ gboolean compensated = FALSE;
+ gboolean check_next_node = FALSE;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+ document = e_editor_page_get_document (editor_page);
+
+ if (!webkit_dom_node_has_child_nodes (block))
+ return WEBKIT_DOM_ELEMENT (block);
+
+ /* Avoid wrapping when the block contains just the BR element alone
+ * or with selection markers. */
+ if ((first_child = webkit_dom_node_get_first_child (block)) &&
+ WEBKIT_DOM_IS_HTML_BR_ELEMENT (first_child)) {
+ WebKitDOMNode *next_sibling;
+
+ if ((next_sibling = webkit_dom_node_get_next_sibling (first_child))) {
+ if (e_editor_dom_is_selection_position_node (next_sibling) &&
+ (next_sibling = webkit_dom_node_get_next_sibling (next_sibling)) &&
+ e_editor_dom_is_selection_position_node (next_sibling) &&
+ !webkit_dom_node_get_next_sibling (next_sibling))
+ return WEBKIT_DOM_ELEMENT (block);
+ } else
+ return WEBKIT_DOM_ELEMENT (block);
+ }
+
+ block_clone = webkit_dom_node_clone_node_with_error (block, TRUE, NULL);
+
+ /* When we wrap, we are wrapping just the text after caret, text
+ * before the caret is already wrapped, so unwrap the text after
+ * the caret position */
+ selection_end_marker = webkit_dom_element_query_selector (
+ WEBKIT_DOM_ELEMENT (block_clone),
+ "span#-x-evo-selection-end-marker",
+ NULL);
+
+ if (selection_end_marker) {
+ WebKitDOMNode *nd = WEBKIT_DOM_NODE (selection_end_marker);
+
+ while (nd) {
+ WebKitDOMNode *parent_node;
+ WebKitDOMNode *next_nd = webkit_dom_node_get_next_sibling (nd);
+
+ parent_node = webkit_dom_node_get_parent_node (nd);
+ if (!next_nd && parent_node && !webkit_dom_node_is_same_node (parent_node,
block_clone))
+ next_nd = webkit_dom_node_get_next_sibling (parent_node);
+
+ if (WEBKIT_DOM_IS_HTML_BR_ELEMENT (nd)) {
+ if (remove_all_br)
+ remove_node (nd);
+ else if (element_has_class (WEBKIT_DOM_ELEMENT (nd), "-x-evo-wrap-br"))
+ remove_node (nd);
+ } else if (WEBKIT_DOM_IS_ELEMENT (nd) &&
+ webkit_dom_element_has_attribute (WEBKIT_DOM_ELEMENT (nd),
"data-hidden-space"))
+ webkit_dom_html_element_set_outer_text (
+ WEBKIT_DOM_HTML_ELEMENT (nd), " ", NULL);
+
+ nd = next_nd;
+ }
+ } else {
+ gint ii, length;
+ WebKitDOMNodeList *list = NULL;
+
+ list = webkit_dom_element_query_selector_all (
+ WEBKIT_DOM_ELEMENT (block_clone), "span[data-hidden-space]", NULL);
+ length = webkit_dom_node_list_get_length (list);
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMNode *hidden_space_node;
+
+ hidden_space_node = webkit_dom_node_list_item (list, ii);
+ webkit_dom_html_element_set_outer_text (
+ WEBKIT_DOM_HTML_ELEMENT (hidden_space_node), " ", NULL);
+ g_object_unref (hidden_space_node);
+ }
+ g_clear_object (&list);
+ }
+
+ /* We have to start from the end of the last wrapped line */
+ selection_start_marker = webkit_dom_element_query_selector (
+ WEBKIT_DOM_ELEMENT (block_clone),
+ "span#-x-evo-selection-start-marker",
+ NULL);
+
+ if (selection_start_marker) {
+ gboolean first_removed = FALSE;
+ WebKitDOMNode *nd;
+
+ nd = webkit_dom_node_get_previous_sibling (
+ WEBKIT_DOM_NODE (selection_start_marker));
+ while (nd) {
+ WebKitDOMNode *prev_nd = webkit_dom_node_get_previous_sibling (nd);
+
+ if (!prev_nd && !webkit_dom_node_is_same_node (webkit_dom_node_get_parent_node (nd),
block_clone))
+ prev_nd = webkit_dom_node_get_previous_sibling
(webkit_dom_node_get_parent_node (nd));
+
+ if (WEBKIT_DOM_IS_HTML_BR_ELEMENT (nd)) {
+ if (first_removed) {
+ start_point = nd;
+ break;
+ } else {
+ remove_node (nd);
+ first_removed = TRUE;
+ }
+ } else if (WEBKIT_DOM_IS_ELEMENT (nd) &&
+ webkit_dom_element_has_attribute (WEBKIT_DOM_ELEMENT (nd),
"data-hidden-space")) {
+ webkit_dom_html_element_set_outer_text (
+ WEBKIT_DOM_HTML_ELEMENT (nd), " ", NULL);
+ } else if (!prev_nd) {
+ WebKitDOMNode *parent;
+
+ parent = webkit_dom_node_get_parent_node (nd);
+ if (!WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (parent))
+ start_point = nd;
+ }
+
+ nd = prev_nd;
+ }
+ }
+
+ webkit_dom_node_normalize (block_clone);
+ node = webkit_dom_node_get_first_child (block_clone);
+ if (node) {
+ text_content = webkit_dom_node_get_text_content (node);
+ if (g_strcmp0 ("\n", text_content) == 0)
+ node = webkit_dom_node_get_next_sibling (node);
+ g_free (text_content);
+ }
+
+ if (start_point) {
+ if (WEBKIT_DOM_IS_HTML_BR_ELEMENT (start_point))
+ node = webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (start_point));
+ else
+ node = start_point;
+ start_node = block_clone;
+ } else
+ start_node = node;
+
+ line_length = 0;
+ while (node) {
+ gint offset = 0;
+ WebKitDOMElement *element;
+
+ if (WEBKIT_DOM_IS_TEXT (node)) {
+ const gchar *newline;
+ WebKitDOMNode *next_sibling;
+
+ /* If there is temporary hidden space we remove it */
+ text_content = webkit_dom_node_get_text_content (node);
+ if (strstr (text_content, UNICODE_ZERO_WIDTH_SPACE)) {
+ if (g_str_has_prefix (text_content, UNICODE_ZERO_WIDTH_SPACE))
+ webkit_dom_character_data_delete_data (
+ WEBKIT_DOM_CHARACTER_DATA (node),
+ 0,
+ 1,
+ NULL);
+ if (g_str_has_suffix (text_content, UNICODE_ZERO_WIDTH_SPACE))
+ webkit_dom_character_data_delete_data (
+ WEBKIT_DOM_CHARACTER_DATA (node),
+ g_utf8_strlen (text_content, -1) - 1,
+ 1,
+ NULL);
+ g_free (text_content);
+ text_content = webkit_dom_node_get_text_content (node);
+ }
+ newline = strstr (text_content, "\n");
+
+ next_sibling = node;
+ while (newline) {
+ next_sibling = WEBKIT_DOM_NODE (webkit_dom_text_split_text (
+ WEBKIT_DOM_TEXT (next_sibling),
+ g_utf8_pointer_to_offset (text_content, newline),
+ NULL));
+
+ if (!next_sibling)
+ break;
+
+ element = webkit_dom_document_create_element (
+ document, "BR", NULL);
+ element_add_class (element, "-x-evo-wrap-br");
+
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (next_sibling),
+ WEBKIT_DOM_NODE (element),
+ next_sibling,
+ NULL);
+
+ g_free (text_content);
+
+ text_content = webkit_dom_node_get_text_content (next_sibling);
+ if (g_str_has_prefix (text_content, "\n")) {
+ webkit_dom_character_data_delete_data (
+ WEBKIT_DOM_CHARACTER_DATA (next_sibling), 0, 1, NULL);
+ g_free (text_content);
+ text_content =
+ webkit_dom_node_get_text_content (next_sibling);
+ }
+ newline = strstr (text_content, "\n");
+ }
+ g_free (text_content);
+ } else if (WEBKIT_DOM_IS_ELEMENT (node)) {
+ if (e_editor_dom_is_selection_position_node (node)) {
+ if (line_length == 0) {
+ WebKitDOMNode *tmp_node;
+
+ tmp_node = webkit_dom_node_get_previous_sibling (node);
+ /* Only check if there is some node before the selection marker. */
+ if (tmp_node && !e_editor_dom_is_selection_position_node (tmp_node))
+ check_next_node = TRUE;
+ }
+ node = webkit_dom_node_get_next_sibling (node);
+ continue;
+ }
+
+ check_next_node = FALSE;
+ /* If element is ANCHOR we wrap it separately */
+ if (WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (node)) {
+ glong anchor_length;
+ WebKitDOMNode *next_sibling;
+
+ text_content = webkit_dom_node_get_text_content (node);
+ anchor_length = g_utf8_strlen (text_content, -1);
+ g_free (text_content);
+
+ next_sibling = webkit_dom_node_get_next_sibling (node);
+ /* If the anchor doesn't fit on the line move the inner
+ * nodes out of it and start to wrap them. */
+ if ((line_length + anchor_length) > length_to_wrap) {
+ WebKitDOMNode *inner_node;
+
+ while ((inner_node = webkit_dom_node_get_first_child (node))) {
+ g_object_set_data (
+ G_OBJECT (inner_node),
+ "-x-evo-anchor-text",
+ GINT_TO_POINTER (1));
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (node),
+ inner_node,
+ next_sibling,
+ NULL);
+ }
+ next_sibling = webkit_dom_node_get_next_sibling (node);
+
+ remove_node (node);
+ node = next_sibling;
+ continue;
+ }
+
+ line_length += anchor_length;
+ node = next_sibling;
+ continue;
+ }
+
+ if (element_has_class (WEBKIT_DOM_ELEMENT (node), "Apple-tab-span")) {
+ WebKitDOMNode *sibling;
+ gint tab_length;
+
+ sibling = webkit_dom_node_get_previous_sibling (node);
+ if (sibling && WEBKIT_DOM_IS_ELEMENT (sibling) &&
+ element_has_class (WEBKIT_DOM_ELEMENT (sibling), "Apple-tab-span"))
+ tab_length = TAB_LENGTH;
+ else {
+ tab_length = TAB_LENGTH - (line_length + compensated ? 0 :
(word_wrap_length - length_to_wrap)) % TAB_LENGTH;
+ compensated = TRUE;
+ }
+
+ if (line_length + tab_length > length_to_wrap) {
+ if (webkit_dom_node_get_next_sibling (node)) {
+ element = webkit_dom_document_create_element (
+ document, "BR", NULL);
+ element_add_class (element, "-x-evo-wrap-br");
+ node = webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (node),
+ WEBKIT_DOM_NODE (element),
+ webkit_dom_node_get_next_sibling (node),
+ NULL);
+ }
+ line_length = 0;
+ compensated = FALSE;
+ } else
+ line_length += tab_length;
+
+ sibling = webkit_dom_node_get_next_sibling (node);
+ node = sibling;
+ continue;
+ }
+ /* When we are not removing user-entered BR elements (lines wrapped by user),
+ * we need to skip those elements */
+ if (!remove_all_br && WEBKIT_DOM_IS_HTML_BR_ELEMENT (node)) {
+ if (!element_has_class (WEBKIT_DOM_ELEMENT (node), "-x-evo-wrap-br")) {
+ line_length = 0;
+ compensated = FALSE;
+ node = webkit_dom_node_get_next_sibling (node);
+ continue;
+ }
+ }
+ goto next_node;
+ } else {
+ WebKitDOMNode *sibling;
+
+ sibling = webkit_dom_node_get_next_sibling (node);
+ node = sibling;
+ continue;
+ }
+
+ /* If length of this node + what we already have is still less
+ * then length_to_wrap characters, then just concatenate it and
+ * continue to next node */
+ length_left = webkit_dom_character_data_get_length (
+ WEBKIT_DOM_CHARACTER_DATA (node));
+
+ if ((length_left + line_length) <= length_to_wrap) {
+ if (check_next_node)
+ goto check_node;
+ line_length += length_left;
+ if (line_length == length_to_wrap) {
+ line_length = 0;
+
+ element = webkit_dom_document_create_element (document, "BR", NULL);
+ element_add_class (element, "-x-evo-wrap-br");
+
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (node),
+ WEBKIT_DOM_NODE (element),
+ webkit_dom_node_get_next_sibling (node),
+ NULL);
+ }
+ goto next_node;
+ }
+
+ /* wrap until we have something */
+ while (node && (length_left + line_length) > length_to_wrap) {
+ gboolean insert_and_continue;
+ gint max_length;
+
+ check_node:
+ insert_and_continue = FALSE;
+
+ if (!WEBKIT_DOM_IS_CHARACTER_DATA (node))
+ goto next_node;
+
+ element = webkit_dom_document_create_element (document, "BR", NULL);
+ element_add_class (element, "-x-evo-wrap-br");
+
+ max_length = length_to_wrap - line_length;
+ if (max_length < 0)
+ max_length = length_to_wrap;
+ else if (max_length == 0) {
+ if (check_next_node) {
+ insert_and_continue = TRUE;
+ goto check;
+ }
+
+ /* Break before the current node and continue. */
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (node),
+ WEBKIT_DOM_NODE (element),
+ node,
+ NULL);
+ line_length = 0;
+ continue;
+ }
+
+ /* Allow anchors to break on any character. */
+ if (g_object_steal_data (G_OBJECT (node), "-x-evo-anchor-text"))
+ offset = max_length;
+ else {
+ /* Find where we can line-break the node so that it
+ * effectively fills the rest of current row. */
+ offset = find_where_to_break_line (
+ WEBKIT_DOM_CHARACTER_DATA (node), max_length);
+
+ /* When pressing delete on the end of line to concatenate
+ * the last word from the line and first word from the
+ * next line we will end with the second word split
+ * somewhere in the middle (to be precise it will be
+ * split after the last character that will fit on the
+ * previous line. To avoid that we need to put the
+ * concatenated word on the next line. */
+ if (offset == -1 || check_next_node) {
+ WebKitDOMNode *prev_sibling;
+
+ check:
+ check_next_node = FALSE;
+ prev_sibling = webkit_dom_node_get_previous_sibling (node);
+ if (prev_sibling && e_editor_dom_is_selection_position_node
(prev_sibling)) {
+ WebKitDOMNode *prev_br = NULL;
+
+ prev_sibling = webkit_dom_node_get_previous_sibling
(prev_sibling);
+
+ /* Collapsed selection */
+ if (prev_sibling && e_editor_dom_is_selection_position_node
(prev_sibling))
+ prev_sibling = webkit_dom_node_get_previous_sibling
(prev_sibling);
+
+ if (prev_sibling && WEBKIT_DOM_IS_HTML_BR_ELEMENT
(prev_sibling) &&
+ element_has_class (WEBKIT_DOM_ELEMENT (prev_sibling),
"-x-evo-wrap-br")) {
+ prev_br = prev_sibling;
+ prev_sibling = webkit_dom_node_get_previous_sibling
(prev_sibling);
+ }
+
+ if (prev_sibling && WEBKIT_DOM_IS_CHARACTER_DATA
(prev_sibling)) {
+ gchar *data;
+ glong text_length, length = 0;
+
+ data = webkit_dom_character_data_get_data (
+ WEBKIT_DOM_CHARACTER_DATA (prev_sibling));
+ text_length = webkit_dom_character_data_get_length (
+ WEBKIT_DOM_CHARACTER_DATA (prev_sibling));
+
+ /* Find the last character where we can break. */
+ while (text_length - length > 0) {
+ if (strchr (" ", data[text_length - length -
1])) {
+ length++;
+ break;
+ } else if (data[text_length - length - 1] ==
'-' &&
+ text_length - length > 1 &&
+ !strchr (" ", data[text_length -
length - 2]))
+ break;
+ length++;
+ }
+
+ if (text_length != length) {
+ WebKitDOMNode *nd;
+
+ webkit_dom_text_split_text (
+ WEBKIT_DOM_TEXT (prev_sibling),
+ text_length - length,
+ NULL);
+
+ if ((nd = webkit_dom_node_get_next_sibling
(prev_sibling))) {
+ gchar *nd_content;
+
+ nd_content =
webkit_dom_node_get_text_content (nd);
+ if (nd_content && *nd_content) {
+ if (*nd_content == ' ')
+
mark_and_remove_leading_space (document, nd);
+
+ if
(!webkit_dom_node_get_next_sibling (nd) &&
+ g_str_has_suffix
(nd_content, " "))
+
mark_and_remove_trailing_space (document, nd);
+
+ g_free (nd_content);
+ }
+
+ if (nd) {
+ if (prev_br)
+ remove_node (prev_br);
+
webkit_dom_node_insert_before (
+
webkit_dom_node_get_parent_node (nd),
+ WEBKIT_DOM_NODE
(element),
+ nd,
+ NULL);
+
+ offset = 0;
+ line_length = length;
+ continue;
+ }
+ }
+ }
+ }
+ }
+ if (insert_and_continue) {
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (node),
+ WEBKIT_DOM_NODE (element),
+ node,
+ NULL);
+
+ offset = 0;
+ line_length = 0;
+ insert_and_continue = FALSE;
+ continue;
+ }
+
+ offset = offset != -1 ? offset : max_length;
+ }
+ }
+
+ if (offset >= 0) {
+ WebKitDOMNode *nd;
+
+ if (offset != length_left && offset != 0) {
+ webkit_dom_text_split_text (
+ WEBKIT_DOM_TEXT (node), offset, NULL);
+
+ nd = webkit_dom_node_get_next_sibling (node);
+ } else
+ nd = node;
+
+ if (nd) {
+ gboolean no_sibling = FALSE;
+ gchar *nd_content;
+
+ nd_content = webkit_dom_node_get_text_content (nd);
+ if (nd_content && *nd_content) {
+ if (*nd_content == ' ')
+ mark_and_remove_leading_space (document, nd);
+
+ if (!webkit_dom_node_get_next_sibling (nd) &&
+ length_left <= length_to_wrap &&
+ g_str_has_suffix (nd_content, " ")) {
+ mark_and_remove_trailing_space (document, nd);
+ no_sibling = TRUE;
+ }
+
+ g_free (nd_content);
+ }
+
+ if (!no_sibling)
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (node),
+ WEBKIT_DOM_NODE (element),
+ nd,
+ NULL);
+
+ offset = 0;
+
+ nd_content = webkit_dom_node_get_text_content (nd);
+ if (!*nd_content)
+ remove_node (nd);
+ g_free (nd_content);
+
+ if (no_sibling)
+ node = NULL;
+ else
+ node = webkit_dom_node_get_next_sibling (
+ WEBKIT_DOM_NODE (element));
+ } else {
+ webkit_dom_node_append_child (
+ webkit_dom_node_get_parent_node (node),
+ WEBKIT_DOM_NODE (element),
+ NULL);
+ }
+ }
+ if (node && WEBKIT_DOM_IS_CHARACTER_DATA (node))
+ length_left = webkit_dom_character_data_get_length (
+ WEBKIT_DOM_CHARACTER_DATA (node));
+
+ line_length = 0;
+ compensated = FALSE;
+ }
+ line_length += length_left - offset;
+ next_node:
+ if (!node)
+ break;
+
+ if (WEBKIT_DOM_IS_HTML_LI_ELEMENT (node)) {
+ line_length = 0;
+ compensated = FALSE;
+ }
+
+ /* Move to next node */
+ if (webkit_dom_node_has_child_nodes (node)) {
+ node = webkit_dom_node_get_first_child (node);
+ } else if (webkit_dom_node_get_next_sibling (node)) {
+ node = webkit_dom_node_get_next_sibling (node);
+ } else {
+ WebKitDOMNode *tmp_parent;
+
+ if (webkit_dom_node_is_equal_node (node, start_node))
+ break;
+
+ /* Find a next node that we can process. */
+ tmp_parent = webkit_dom_node_get_parent_node (node);
+ if (tmp_parent && webkit_dom_node_get_next_sibling (tmp_parent))
+ node = webkit_dom_node_get_next_sibling (tmp_parent);
+ else {
+ WebKitDOMNode *tmp;
+
+ tmp = tmp_parent;
+ /* Find a node that is not a start node (that would mean
+ * that we already processed the whole block) and it has
+ * a sibling that we can process. */
+ while (tmp && !webkit_dom_node_is_equal_node (tmp, start_node) &&
+ !webkit_dom_node_get_next_sibling (tmp)) {
+ tmp = webkit_dom_node_get_parent_node (tmp);
+ }
+
+ /* If we found a node to process, let's process its
+ * sibling, otherwise give up. */
+ if (tmp)
+ node = webkit_dom_node_get_next_sibling (tmp);
+ else
+ break;
+ }
+ }
+ }
+
+ last_child = webkit_dom_node_get_last_child (block_clone);
+ if (last_child && WEBKIT_DOM_IS_HTML_BR_ELEMENT (last_child) &&
+ element_has_class (WEBKIT_DOM_ELEMENT (last_child), "-x-evo-wrap-br"))
+ remove_node (last_child);
+
+ webkit_dom_node_normalize (block_clone);
+
+ node = webkit_dom_node_get_parent_node (block);
+ if (node) {
+ /* Replace block with wrapped one */
+ webkit_dom_node_replace_child (
+ node, block_clone, block, NULL);
+ }
+
+ return WEBKIT_DOM_ELEMENT (block_clone);
+}
+
+void
+e_editor_dom_remove_wrapping_from_element (WebKitDOMElement *element)
+{
+ WebKitDOMNodeList *list = NULL;
+ gint ii, length;
+
+ g_return_if_fail (element != NULL);
+
+ list = webkit_dom_element_query_selector_all (
+ element, "br.-x-evo-wrap-br", NULL);
+ length = webkit_dom_node_list_get_length (list);
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMNode *node = webkit_dom_node_list_item (list, ii);
+ WebKitDOMNode *parent;
+
+ parent = e_editor_dom_get_parent_block_node_from_child (node);
+ if (!webkit_dom_element_has_attribute (WEBKIT_DOM_ELEMENT (parent), "data-user-wrapped"))
+ remove_node (node);
+ g_object_unref (node);
+ }
+
+ g_clear_object (&list);
+
+ list = webkit_dom_element_query_selector_all (
+ element, "span[data-hidden-space]", NULL);
+ length = webkit_dom_node_list_get_length (list);
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMNode *hidden_space_node;
+ WebKitDOMNode *parent;
+
+ hidden_space_node = webkit_dom_node_list_item (list, ii);
+ parent = e_editor_dom_get_parent_block_node_from_child (hidden_space_node);
+ if (!webkit_dom_element_has_attribute (WEBKIT_DOM_ELEMENT (parent), "data-user-wrapped")) {
+ webkit_dom_html_element_set_outer_text (
+ WEBKIT_DOM_HTML_ELEMENT (hidden_space_node), " ", NULL);
+ }
+ g_object_unref (hidden_space_node);
+ }
+ g_clear_object (&list);
+
+ webkit_dom_node_normalize (WEBKIT_DOM_NODE (element));
+}
+
+void
+e_editor_dom_remove_quoting_from_element (WebKitDOMElement *element)
+{
+ gint ii, length;
+ WebKitDOMNodeList *list = NULL;
+
+ g_return_if_fail (element != NULL);
+
+ list = webkit_dom_element_query_selector_all (
+ element, "span.-x-evo-quoted", NULL);
+ length = webkit_dom_node_list_get_length (list);
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMNode *node = webkit_dom_node_list_item (list, ii);
+ remove_node (node);
+ g_object_unref (node);
+ }
+ g_clear_object (&list);
+
+ list = webkit_dom_element_query_selector_all (
+ element, "br.-x-evo-temp-br", NULL);
+ length = webkit_dom_node_list_get_length (list);
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMNode *node = webkit_dom_node_list_item (list, ii);
+ remove_node (node);
+ g_object_unref (node);
+ }
+ g_clear_object (&list);
+
+ webkit_dom_node_normalize (WEBKIT_DOM_NODE (element));
+}
+
+WebKitDOMElement *
+e_editor_dom_get_paragraph_element (EEditorPage *editor_page,
+ gint width,
+ gint offset)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *element;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+ document = e_editor_page_get_document (editor_page);
+ element = webkit_dom_document_create_element (document, "p", NULL);
+ e_editor_dom_set_paragraph_style (editor_page, element, width, offset, NULL);
+
+ return element;
+}
+
+WebKitDOMElement *
+e_editor_dom_put_node_into_paragraph (EEditorPage *editor_page,
+ WebKitDOMNode *node,
+ gboolean with_input)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMRange *range = NULL;
+ WebKitDOMElement *container;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+ document = e_editor_page_get_document (editor_page);
+ range = webkit_dom_document_create_range (document);
+ container = e_editor_dom_get_paragraph_element (editor_page, -1, 0);
+ webkit_dom_range_select_node (range, node, NULL);
+ webkit_dom_range_surround_contents (range, WEBKIT_DOM_NODE (container), NULL);
+ /* We have to move caret position inside this container */
+ if (with_input)
+ dom_add_selection_markers_into_element_end (document, container, NULL, NULL);
+
+ g_clear_object (&range);
+
+ return container;
+}
+
+static gint
+selection_get_citation_level (WebKitDOMNode *node)
+{
+ WebKitDOMNode *parent = webkit_dom_node_get_parent_node (node);
+ gint level = 0;
+
+ while (parent && !WEBKIT_DOM_IS_HTML_BODY_ELEMENT (parent)) {
+ if (WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (parent) &&
+ webkit_dom_element_has_attribute (WEBKIT_DOM_ELEMENT (parent), "type"))
+ level++;
+
+ parent = webkit_dom_node_get_parent_node (parent);
+ }
+
+ return level;
+}
+
+WebKitDOMElement *
+e_editor_dom_wrap_paragraph_length (EEditorPage *editor_page,
+ WebKitDOMElement *paragraph,
+ gint length)
+{
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+ g_return_val_if_fail (WEBKIT_DOM_IS_ELEMENT (paragraph), NULL);
+ g_return_val_if_fail (length >= MINIMAL_PARAGRAPH_WIDTH, NULL);
+
+ return wrap_lines (editor_page, WEBKIT_DOM_NODE (paragraph), FALSE, length,
+ e_editor_page_get_word_wrap_length (editor_page));
+}
+
+/*
+ * e_html_editor_selection_wrap_lines:
+ * @selection: an #EEditorSelection
+ *
+ * Wraps all lines in current selection to be 71 characters long.
+ */
+
+void
+e_editor_dom_selection_wrap (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *selection_start_marker, *selection_end_marker;
+ WebKitDOMNode *block, *next_block;
+ EEditorHistoryEvent *ev = NULL;
+ EEditorUndoRedoManager *manager;
+ gboolean after_selection_end = FALSE, html_mode;
+ gint word_wrap_length;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+ word_wrap_length = e_editor_page_get_word_wrap_length (editor_page);
+
+ e_editor_dom_selection_save (editor_page);
+ selection_start_marker = webkit_dom_document_query_selector (
+ document, "span#-x-evo-selection-start-marker", NULL);
+ selection_end_marker = webkit_dom_document_query_selector (
+ document, "span#-x-evo-selection-end-marker", NULL);
+
+ /* If the selection was not saved, move it into the first child of body */
+ if (!selection_start_marker || !selection_end_marker) {
+ WebKitDOMHTMLElement *body;
+ WebKitDOMNode *child;
+
+ body = webkit_dom_document_get_body (document);
+ child = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (body));
+
+ dom_add_selection_markers_into_element_start (
+ document,
+ WEBKIT_DOM_ELEMENT (child),
+ &selection_start_marker,
+ &selection_end_marker);
+ }
+
+ manager = e_editor_page_get_undo_redo_manager (editor_page);
+ if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+ ev = g_new0 (EEditorHistoryEvent, 1);
+ ev->type = HISTORY_WRAP;
+
+ e_editor_dom_selection_get_coordinates (editor_page,
+ &ev->before.start.x,
+ &ev->before.start.y,
+ &ev->before.end.x,
+ &ev->before.end.y);
+
+ ev->data.style.from = 1;
+ ev->data.style.to = 1;
+ }
+
+ block = e_editor_dom_get_parent_block_node_from_child (
+ WEBKIT_DOM_NODE (selection_start_marker));
+
+ html_mode = e_editor_page_get_html_mode (editor_page);
+
+ /* Process all blocks that are in the selection one by one */
+ while (block && !after_selection_end) {
+ gboolean quoted = FALSE;
+ gint citation_level, quote;
+ WebKitDOMElement *wrapped_paragraph;
+
+ next_block = webkit_dom_node_get_next_sibling (block);
+
+ /* Don't try to wrap the 'Normal' blocks as they are already wrapped and*/
+ /* also skip blocks that we already wrapped with this function. */
+ if ((!html_mode && webkit_dom_element_has_attribute (WEBKIT_DOM_ELEMENT (block),
"data-evo-paragraph")) ||
+ webkit_dom_element_has_attribute (WEBKIT_DOM_ELEMENT (block), "data-user-wrapped")) {
+ block = next_block;
+ continue;
+ }
+
+ if (webkit_dom_element_query_selector (
+ WEBKIT_DOM_ELEMENT (block), "span.-x-evo-quoted", NULL)) {
+ quoted = TRUE;
+ e_editor_dom_remove_quoting_from_element (WEBKIT_DOM_ELEMENT (block));
+ }
+
+ if (!html_mode)
+ e_editor_dom_remove_wrapping_from_element (WEBKIT_DOM_ELEMENT (block));
+
+ after_selection_end = webkit_dom_node_contains (
+ block, WEBKIT_DOM_NODE (selection_end_marker));
+
+ citation_level = selection_get_citation_level (block);
+ quote = citation_level ? citation_level * 2 : 0;
+
+ wrapped_paragraph = e_editor_dom_wrap_paragraph_length (
+ editor_page, WEBKIT_DOM_ELEMENT (block), word_wrap_length - quote);
+
+ webkit_dom_element_set_attribute (
+ wrapped_paragraph, "data-user-wrapped", "", NULL);
+
+ if (quoted && !html_mode)
+ e_editor_dom_quote_plain_text_element (editor_page, wrapped_paragraph);
+
+ block = next_block;
+ }
+
+ if (ev) {
+ e_editor_dom_selection_get_coordinates (editor_page,
+ &ev->after.start.x,
+ &ev->after.start.y,
+ &ev->after.end.x,
+ &ev->after.end.y);
+ e_editor_undo_redo_manager_insert_history_event (manager, ev);
+ }
+
+ e_editor_dom_selection_restore (editor_page);
+
+ e_editor_dom_force_spell_check_in_viewport (editor_page);
+}
+
+void
+e_editor_dom_wrap_paragraphs_in_document (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMNodeList *list = NULL;
+ gint ii, length;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+ list = webkit_dom_document_query_selector_all (
+ document, "[data-evo-paragraph]:not(#-x-evo-input-start)", NULL);
+
+ length = webkit_dom_node_list_get_length (list);
+
+ for (ii = 0; ii < length; ii++) {
+ gint word_wrap_length, quote, citation_level;
+ WebKitDOMNode *node = webkit_dom_node_list_item (list, ii);
+
+ citation_level = selection_get_citation_level (node);
+ quote = citation_level ? citation_level * 2 : 0;
+ word_wrap_length = e_editor_page_get_word_wrap_length (editor_page);
+
+ if (node_is_list (node)) {
+ WebKitDOMNode *item = webkit_dom_node_get_first_child (node);
+
+ while (item && WEBKIT_DOM_IS_HTML_LI_ELEMENT (item)) {
+ e_editor_dom_wrap_paragraph_length (
+ editor_page, WEBKIT_DOM_ELEMENT (item), word_wrap_length - quote);
+ item = webkit_dom_node_get_next_sibling (item);
+ }
+ } else {
+ e_editor_dom_wrap_paragraph_length (
+ editor_page, WEBKIT_DOM_ELEMENT (node), word_wrap_length - quote);
+ }
+ g_object_unref (node);
+ }
+ g_clear_object (&list);
+}
+
+WebKitDOMElement *
+e_editor_dom_wrap_paragraph (EEditorPage *editor_page,
+ WebKitDOMElement *paragraph)
+{
+ gint indentation_level, citation_level, quote;
+ gint word_wrap_length, final_width, offset = 0;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+ g_return_val_if_fail (WEBKIT_DOM_IS_ELEMENT (paragraph), NULL);
+
+ indentation_level = get_indentation_level (paragraph);
+ citation_level = selection_get_citation_level (WEBKIT_DOM_NODE (paragraph));
+
+ if (node_is_list_or_item (WEBKIT_DOM_NODE (paragraph))) {
+ gint list_level = get_list_level (WEBKIT_DOM_NODE (paragraph));
+ indentation_level = 0;
+
+ if (list_level > 0)
+ offset = list_level * -SPACES_PER_LIST_LEVEL;
+ else
+ offset = -SPACES_PER_LIST_LEVEL;
+ }
+
+ quote = citation_level ? citation_level * 2 : 0;
+
+ word_wrap_length = e_editor_page_get_word_wrap_length (editor_page);
+ final_width = word_wrap_length - quote + offset;
+ final_width -= SPACES_PER_INDENTATION * indentation_level;
+
+ return e_editor_dom_wrap_paragraph_length (
+ editor_page, WEBKIT_DOM_ELEMENT (paragraph), final_width);
+}
+
+static gboolean
+get_has_style (EEditorPage *editor_page,
+ const gchar *style_tag)
+{
+ WebKitDOMNode *node;
+ WebKitDOMElement *element;
+ WebKitDOMRange *range = NULL;
+ gboolean result;
+ gint tag_len;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+ range = e_editor_dom_get_current_range (editor_page);
+ if (!range)
+ return FALSE;
+
+ node = webkit_dom_range_get_start_container (range, NULL);
+ if (WEBKIT_DOM_IS_ELEMENT (node))
+ element = WEBKIT_DOM_ELEMENT (node);
+ else
+ element = webkit_dom_node_get_parent_element (node);
+ g_clear_object (&range);
+
+ tag_len = strlen (style_tag);
+ result = FALSE;
+ while (!result && element) {
+ gchar *element_tag;
+ gboolean accept_citation = FALSE;
+
+ element_tag = webkit_dom_element_get_tag_name (element);
+
+ if (g_ascii_strncasecmp (style_tag, "citation", 8) == 0) {
+ accept_citation = TRUE;
+ result = WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (element);
+ if (element_has_class (element, "-x-evo-indented"))
+ result = FALSE;
+ } else {
+ result = ((tag_len == strlen (element_tag)) &&
+ (g_ascii_strncasecmp (element_tag, style_tag, tag_len) == 0));
+ }
+
+ /* Special case: <blockquote type=cite> marks quotation, while
+ * just <blockquote> is used for indentation. If the <blockquote>
+ * has type=cite, then ignore it unless style_tag is "citation" */
+ if (result && WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (element)) {
+ if (webkit_dom_element_has_attribute (element, "type")) {
+ gchar *type = webkit_dom_element_get_attribute (element, "type");
+ if (!accept_citation && (type && g_ascii_strncasecmp (type, "cite", 4) == 0))
{
+ result = FALSE;
+ }
+ g_free (type);
+ } else {
+ if (accept_citation)
+ result = FALSE;
+ }
+ }
+
+ g_free (element_tag);
+
+ if (result)
+ break;
+
+ element = webkit_dom_node_get_parent_element (
+ WEBKIT_DOM_NODE (element));
+ }
+
+ return result;
+}
+
+typedef gboolean (*IsRightFormatNodeFunc) (WebKitDOMElement *element);
+
+static gboolean
+dom_selection_is_font_format (EEditorPage *editor_page,
+ IsRightFormatNodeFunc func,
+ gboolean *previous_value)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMDOMWindow *dom_window = NULL;
+ WebKitDOMDOMSelection *dom_selection = NULL;
+ WebKitDOMNode *start, *end, *sibling;
+ WebKitDOMRange *range = NULL;
+ gboolean ret_val = FALSE;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+ if (!e_editor_page_get_html_mode (editor_page))
+ goto out;
+
+ document = e_editor_page_get_document (editor_page);
+ dom_window = webkit_dom_document_get_default_view (document);
+ dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+ g_clear_object (&dom_window);
+
+ if (!webkit_dom_dom_selection_get_range_count (dom_selection))
+ goto out;
+
+ range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+ if (!range)
+ goto out;
+
+ if (webkit_dom_range_get_collapsed (range, NULL) && previous_value) {
+ WebKitDOMNode *node;
+ gchar* text_content;
+
+ node = webkit_dom_range_get_common_ancestor_container (range, NULL);
+ /* If we are changing the format of block we have to re-set the
+ * format property, otherwise it will be turned off because of no
+ * text in block. */
+ text_content = webkit_dom_node_get_text_content (node);
+ if (g_strcmp0 (text_content, "") == 0) {
+ g_free (text_content);
+ ret_val = *previous_value;
+ goto out;
+ }
+ g_free (text_content);
+ }
+
+ /* Range without start or end point is a wrong range. */
+ start = webkit_dom_range_get_start_container (range, NULL);
+ end = webkit_dom_range_get_end_container (range, NULL);
+ if (!start || !end)
+ goto out;
+
+ if (WEBKIT_DOM_IS_TEXT (start))
+ start = webkit_dom_node_get_parent_node (start);
+ while (start && WEBKIT_DOM_IS_ELEMENT (start) && !WEBKIT_DOM_IS_HTML_BODY_ELEMENT (start)) {
+ /* Find the start point's parent node with given formatting. */
+ if (func (WEBKIT_DOM_ELEMENT (start))) {
+ ret_val = TRUE;
+ break;
+ }
+ start = webkit_dom_node_get_parent_node (start);
+ }
+
+ /* Start point doesn't have the given formatting. */
+ if (!ret_val)
+ goto out;
+
+ /* If the selection is collapsed, we can return early. */
+ if (webkit_dom_range_get_collapsed (range, NULL))
+ goto out;
+
+ /* The selection is in the same node and that node is supposed to have
+ * the same formatting (otherwise it is split up with formatting element. */
+ if (webkit_dom_node_is_same_node (
+ webkit_dom_range_get_start_container (range, NULL),
+ webkit_dom_range_get_end_container (range, NULL)))
+ goto out;
+
+ ret_val = FALSE;
+
+ if (WEBKIT_DOM_IS_TEXT (end))
+ end = webkit_dom_node_get_parent_node (end);
+ while (end && WEBKIT_DOM_IS_ELEMENT (end) && !WEBKIT_DOM_IS_HTML_BODY_ELEMENT (end)) {
+ /* Find the end point's parent node with given formatting. */
+ if (func (WEBKIT_DOM_ELEMENT (end))) {
+ ret_val = TRUE;
+ break;
+ }
+ end = webkit_dom_node_get_parent_node (end);
+ }
+
+ if (!ret_val)
+ goto out;
+
+ ret_val = FALSE;
+
+ /* Now go between the end points and check the inner nodes for format validity. */
+ sibling = start;
+ while ((sibling = webkit_dom_node_get_next_sibling (sibling))) {
+ if (webkit_dom_node_is_same_node (sibling, end)) {
+ ret_val = TRUE;
+ goto out;
+ }
+
+ if (WEBKIT_DOM_IS_TEXT (sibling))
+ goto out;
+ else if (func (WEBKIT_DOM_ELEMENT (sibling)))
+ continue;
+ else if (webkit_dom_node_get_first_child (sibling)) {
+ WebKitDOMNode *first_child;
+
+ first_child = webkit_dom_node_get_first_child (sibling);
+ if (!webkit_dom_node_get_next_sibling (first_child))
+ if (WEBKIT_DOM_IS_ELEMENT (first_child) && func (WEBKIT_DOM_ELEMENT
(first_child)))
+ continue;
+ else
+ goto out;
+ else
+ goto out;
+ } else
+ goto out;
+ }
+
+ sibling = end;
+ while ((sibling = webkit_dom_node_get_previous_sibling (sibling))) {
+ if (webkit_dom_node_is_same_node (sibling, start))
+ break;
+
+ if (WEBKIT_DOM_IS_TEXT (sibling))
+ goto out;
+ else if (func (WEBKIT_DOM_ELEMENT (sibling)))
+ continue;
+ else if (webkit_dom_node_get_first_child (sibling)) {
+ WebKitDOMNode *first_child;
+
+ first_child = webkit_dom_node_get_first_child (sibling);
+ if (!webkit_dom_node_get_next_sibling (first_child))
+ if (WEBKIT_DOM_IS_ELEMENT (first_child) && func (WEBKIT_DOM_ELEMENT
(first_child)))
+ continue;
+ else
+ goto out;
+ else
+ goto out;
+ } else
+ goto out;
+ }
+
+ ret_val = TRUE;
+ out:
+ g_clear_object (&range);
+ g_clear_object (&dom_selection);
+
+ return ret_val;
+}
+
+static gboolean
+is_underline_element (WebKitDOMElement *element)
+{
+ if (!element || !WEBKIT_DOM_IS_ELEMENT (element))
+ return FALSE;
+
+ return element_has_tag (element, "u");
+}
+
+/*
+ * e_html_editor_selection_is_underline:
+ * @selection: an #EEditorSelection
+ *
+ * Returns whether current selection or letter at current cursor position
+ * is underlined.
+ *
+ * Returns @TRUE when selection is underlined, @FALSE otherwise.
+ */
+gboolean
+e_editor_dom_selection_is_underline (EEditorPage *editor_page)
+{
+ gboolean is_underline;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+ is_underline = e_editor_page_get_underline (editor_page);
+ is_underline = dom_selection_is_font_format (
+ editor_page, (IsRightFormatNodeFunc) is_underline_element, &is_underline);
+
+ return is_underline;
+}
+
+static WebKitDOMElement *
+set_font_style (WebKitDOMDocument *document,
+ const gchar *element_name,
+ gboolean value)
+{
+ WebKitDOMElement *element;
+ WebKitDOMNode *parent;
+
+ element = webkit_dom_document_get_element_by_id (document, "-x-evo-selection-end-marker");
+ parent = webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element));
+ if (value) {
+ WebKitDOMNode *node;
+ WebKitDOMElement *el;
+ gchar *name;
+
+ el = webkit_dom_document_create_element (document, element_name, NULL);
+ webkit_dom_html_element_set_inner_text (
+ WEBKIT_DOM_HTML_ELEMENT (el), UNICODE_ZERO_WIDTH_SPACE, NULL);
+
+ node = webkit_dom_node_get_previous_sibling (WEBKIT_DOM_NODE (element));
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (el), node, NULL);
+ name = webkit_dom_node_get_local_name (parent);
+ if (g_strcmp0 (name, element_name) == 0 && g_strcmp0 (name, "font") != 0)
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (parent),
+ WEBKIT_DOM_NODE (el),
+ webkit_dom_node_get_next_sibling (parent),
+ NULL);
+ else
+ webkit_dom_node_insert_before (
+ parent,
+ WEBKIT_DOM_NODE (el),
+ WEBKIT_DOM_NODE (element),
+ NULL);
+ g_free (name);
+
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (el), WEBKIT_DOM_NODE (element), NULL);
+
+ return el;
+ } else {
+ gboolean no_sibling;
+ WebKitDOMNode *node, *sibling;
+
+ node = webkit_dom_node_get_previous_sibling (WEBKIT_DOM_NODE (element));
+
+ /* Turning the formatting in the middle of element. */
+ sibling = webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (element));
+ no_sibling = sibling &&
+ !WEBKIT_DOM_IS_HTML_BR_ELEMENT (sibling) &&
+ !webkit_dom_node_get_next_sibling (sibling);
+
+ if (no_sibling) {
+ WebKitDOMNode *clone;
+ WebKitDOMNode *sibling;
+
+ clone = webkit_dom_node_clone_node_with_error (
+ WEBKIT_DOM_NODE (parent), FALSE, NULL);
+
+ while ((sibling = webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (element))))
+ webkit_dom_node_insert_before (
+ clone,
+ sibling,
+ webkit_dom_node_get_first_child (clone),
+ NULL);
+
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (parent),
+ clone,
+ webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (parent)),
+ NULL);
+ }
+
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (parent),
+ WEBKIT_DOM_NODE (element),
+ webkit_dom_node_get_next_sibling (parent),
+ NULL);
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (parent),
+ node,
+ webkit_dom_node_get_next_sibling (parent),
+ NULL);
+
+ if (WEBKIT_DOM_IS_HTML_BR_ELEMENT (sibling) && !no_sibling) {
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (parent),
+ node,
+ webkit_dom_node_get_next_sibling (parent),
+ NULL);
+ }
+
+ webkit_dom_html_element_insert_adjacent_text (
+ WEBKIT_DOM_HTML_ELEMENT (parent),
+ "afterend",
+ UNICODE_ZERO_WIDTH_SPACE,
+ NULL);
+
+ remove_node_if_empty (parent);
+ }
+
+ return NULL;
+}
+
+static void
+selection_set_font_style (EEditorPage *editor_page,
+ EContentEditorCommand command,
+ gboolean value)
+{
+ EEditorHistoryEvent *ev = NULL;
+ EEditorUndoRedoManager *manager;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ e_editor_dom_selection_save (editor_page);
+
+ manager = e_editor_page_get_undo_redo_manager (editor_page);
+ if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+ ev = g_new0 (EEditorHistoryEvent, 1);
+ if (command == E_CONTENT_EDITOR_COMMAND_BOLD)
+ ev->type = HISTORY_BOLD;
+ else if (command == E_CONTENT_EDITOR_COMMAND_ITALIC)
+ ev->type = HISTORY_ITALIC;
+ else if (command == E_CONTENT_EDITOR_COMMAND_UNDERLINE)
+ ev->type = HISTORY_UNDERLINE;
+ else if (command == E_CONTENT_EDITOR_COMMAND_STRIKETHROUGH)
+ ev->type = HISTORY_STRIKETHROUGH;
+
+ e_editor_dom_selection_get_coordinates (editor_page,
+ &ev->before.start.x,
+ &ev->before.start.y,
+ &ev->before.end.x,
+ &ev->before.end.y);
+
+ ev->data.style.from = !value;
+ ev->data.style.to = value;
+ }
+
+ if (e_editor_dom_selection_is_collapsed (editor_page)) {
+ const gchar *element_name = NULL;
+
+ if (command == E_CONTENT_EDITOR_COMMAND_BOLD)
+ element_name = "b";
+ else if (command == E_CONTENT_EDITOR_COMMAND_ITALIC)
+ element_name = "i";
+ else if (command == E_CONTENT_EDITOR_COMMAND_UNDERLINE)
+ element_name = "u";
+ else if (command == E_CONTENT_EDITOR_COMMAND_STRIKETHROUGH)
+ element_name = "strike";
+
+ if (element_name)
+ set_font_style (e_editor_page_get_document (editor_page), element_name, value);
+ e_editor_dom_selection_restore (editor_page);
+
+ goto exit;
+ }
+ e_editor_dom_selection_restore (editor_page);
+
+ e_editor_dom_exec_command (editor_page, command, NULL);
+exit:
+ if (ev) {
+ e_editor_dom_selection_get_coordinates (editor_page,
+ &ev->after.start.x,
+ &ev->after.start.y,
+ &ev->after.end.x,
+ &ev->after.end.y);
+ e_editor_undo_redo_manager_insert_history_event (manager, ev);
+ }
+
+ e_editor_dom_force_spell_check_for_current_paragraph (editor_page);
+}
+
+/*
+ * e_html_editor_selection_set_underline:
+ * @selection: an #EEditorSelection
+ * @underline: @TRUE to enable underline, @FALSE to disable
+ *
+ * Toggles underline formatting of current selection or letter at current
+ * cursor position, depending on whether @underline is @TRUE or @FALSE.
+ */
+void
+e_editor_dom_selection_set_underline (EEditorPage *editor_page,
+ gboolean underline)
+{
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ if (e_editor_dom_selection_is_underline (editor_page) == underline)
+ return;
+
+ selection_set_font_style (
+ editor_page, E_CONTENT_EDITOR_COMMAND_UNDERLINE, underline);
+}
+
+static gboolean
+is_subscript_element (WebKitDOMElement *element)
+{
+ if (!element || !WEBKIT_DOM_IS_ELEMENT (element))
+ return FALSE;
+
+ return element_has_tag (element, "sub");
+}
+
+/*
+ * e_html_editor_selection_is_subscript:
+ * @selection: an #EEditorSelection
+ *
+ * Returns whether current selection or letter at current cursor position
+ * is in subscript.
+ *
+ * Returns @TRUE when selection is in subscript, @FALSE otherwise.
+ */
+gboolean
+e_editor_dom_selection_is_subscript (EEditorPage *editor_page)
+{
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+ return dom_selection_is_font_format (
+ editor_page, (IsRightFormatNodeFunc) is_subscript_element, NULL);
+}
+
+/*
+ * e_html_editor_selection_set_subscript:
+ * @selection: an #EEditorSelection
+ * @subscript: @TRUE to enable subscript, @FALSE to disable
+ *
+ * Toggles subscript of current selection or letter at current cursor position,
+ * depending on whether @subscript is @TRUE or @FALSE.
+ */
+void
+e_editor_dom_selection_set_subscript (EEditorPage *editor_page,
+ gboolean subscript)
+{
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ if (e_editor_dom_selection_is_subscript (editor_page) == subscript)
+ return;
+
+ e_editor_dom_exec_command (editor_page, E_CONTENT_EDITOR_COMMAND_SUBSCRIPT, NULL);
+}
+
+static gboolean
+is_superscript_element (WebKitDOMElement *element)
+{
+ if (!element || !WEBKIT_DOM_IS_ELEMENT (element))
+ return FALSE;
+
+ return element_has_tag (element, "sup");
+}
+
+/*
+ * e_html_editor_selection_is_superscript:
+ * @selection: an #EEditorSelection
+ *
+ * Returns whether current selection or letter at current cursor position
+ * is in superscript.
+ *
+ * Returns @TRUE when selection is in superscript, @FALSE otherwise.
+ */
+gboolean
+e_editor_dom_selection_is_superscript (EEditorPage *editor_page)
+{
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+ return dom_selection_is_font_format (
+ editor_page, (IsRightFormatNodeFunc) is_superscript_element, NULL);
+}
+
+/*
+ * e_html_editor_selection_set_superscript:
+ * @selection: an #EEditorSelection
+ * @superscript: @TRUE to enable superscript, @FALSE to disable
+ *
+ * Toggles superscript of current selection or letter at current cursor position,
+ * depending on whether @superscript is @TRUE or @FALSE.
+ */
+void
+e_editor_dom_selection_set_superscript (EEditorPage *editor_page,
+ gboolean superscript)
+{
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ if (e_editor_dom_selection_is_superscript (editor_page) == superscript)
+ return;
+
+ e_editor_dom_exec_command (editor_page, E_CONTENT_EDITOR_COMMAND_SUPERSCRIPT, NULL);
+}
+
+static gboolean
+is_strikethrough_element (WebKitDOMElement *element)
+{
+ if (!element || !WEBKIT_DOM_IS_ELEMENT (element))
+ return FALSE;
+
+ return element_has_tag (element, "strike");
+}
+
+/*
+ * e_html_editor_selection_is_strikethrough:
+ * @selection: an #EEditorSelection
+ *
+ * Returns whether current selection or letter at current cursor position
+ * is striked through.
+ *
+ * Returns @TRUE when selection is striked through, @FALSE otherwise.
+ */
+gboolean
+e_editor_dom_selection_is_strikethrough (EEditorPage *editor_page)
+{
+ gboolean is_strikethrough;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+ is_strikethrough = e_editor_page_get_strikethrough (editor_page);
+ is_strikethrough = dom_selection_is_font_format (
+ editor_page, (IsRightFormatNodeFunc) is_strikethrough_element, &is_strikethrough);
+
+ return is_strikethrough;
+}
+
+/*
+ * e_html_editor_selection_set_strikethrough:
+ * @selection: an #EEditorSelection
+ * @strikethrough: @TRUE to enable strikethrough, @FALSE to disable
+ *
+ * Toggles strike through formatting of current selection or letter at current
+ * cursor position, depending on whether @strikethrough is @TRUE or @FALSE.
+ */
+void
+e_editor_dom_selection_set_strikethrough (EEditorPage *editor_page,
+ gboolean strikethrough)
+{
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ if (e_editor_dom_selection_is_strikethrough (editor_page) == strikethrough)
+ return;
+
+ selection_set_font_style (
+ editor_page, E_CONTENT_EDITOR_COMMAND_STRIKETHROUGH, strikethrough);
+}
+
+static gboolean
+is_monospace_element (WebKitDOMElement *element)
+{
+ gchar *value;
+ gboolean ret_val = FALSE;
+
+ if (!element)
+ return FALSE;
+
+ if (!WEBKIT_DOM_IS_HTML_FONT_ELEMENT (element))
+ return FALSE;
+
+ value = webkit_dom_element_get_attribute (element, "face");
+ if (value && g_strcmp0 (value, "monospace") == 0)
+ ret_val = TRUE;
+
+ g_free (value);
+
+ return ret_val;
+}
+
+/*
+ * e_html_editor_selection_is_monospaced:
+ * @selection: an #EEditorSelection
+ *
+ * Returns whether current selection or letter at current cursor position
+ * is monospaced.
+ *
+ * Returns @TRUE when selection is monospaced, @FALSE otherwise.
+ */
+gboolean
+e_editor_dom_selection_is_monospace (EEditorPage *editor_page)
+{
+ gboolean is_monospace;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+ is_monospace = e_editor_page_get_monospace (editor_page);
+ is_monospace = dom_selection_is_font_format (
+ editor_page, (IsRightFormatNodeFunc) is_monospace_element, &is_monospace);
+
+ return is_monospace;
+}
+
+static void
+monospace_selection (EEditorPage *editor_page,
+ WebKitDOMElement *monospace_element)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *selection_start_marker, *selection_end_marker;
+ WebKitDOMNode *sibling, *node, *monospace, *block;
+ WebKitDOMNodeList *list = NULL;
+ gboolean selection_end = FALSE;
+ gboolean first = TRUE;
+ gint length, ii;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+ e_editor_dom_selection_save (editor_page);
+
+ selection_start_marker = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-start-marker");
+ selection_end_marker = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-end-marker");
+
+ block = WEBKIT_DOM_NODE (get_parent_block_element (WEBKIT_DOM_NODE (selection_start_marker)));
+
+ monospace = WEBKIT_DOM_NODE (monospace_element);
+ node = WEBKIT_DOM_NODE (selection_start_marker);
+ /* Go through first block in selection. */
+ while (block && node && !webkit_dom_node_is_same_node (block, node)) {
+ if (webkit_dom_node_get_next_sibling (node)) {
+ /* Prepare the monospaced element. */
+ monospace = webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (node),
+ first ? monospace : webkit_dom_node_clone_node_with_error (monospace, FALSE,
NULL),
+ first ? node : webkit_dom_node_get_next_sibling (node),
+ NULL);
+ } else
+ break;
+
+ /* Move the nodes into monospaced element. */
+ while (((sibling = webkit_dom_node_get_next_sibling (monospace)))) {
+ webkit_dom_node_append_child (monospace, sibling, NULL);
+ if (webkit_dom_node_is_same_node (WEBKIT_DOM_NODE (selection_end_marker), sibling)) {
+ selection_end = TRUE;
+ break;
+ }
+ }
+
+ node = webkit_dom_node_get_parent_node (monospace);
+ first = FALSE;
+ }
+
+ /* Just one block was selected. */
+ if (selection_end)
+ goto out;
+
+ /* Middle blocks (blocks not containing the end of the selection. */
+ block = webkit_dom_node_get_next_sibling (block);
+ while (block && !selection_end) {
+ WebKitDOMNode *next_block;
+
+ selection_end = webkit_dom_node_contains (
+ block, WEBKIT_DOM_NODE (selection_end_marker));
+
+ if (selection_end)
+ break;
+
+ next_block = webkit_dom_node_get_next_sibling (block);
+
+ monospace = webkit_dom_node_insert_before (
+ block,
+ webkit_dom_node_clone_node_with_error (monospace, FALSE, NULL),
+ webkit_dom_node_get_first_child (block),
+ NULL);
+
+ while (((sibling = webkit_dom_node_get_next_sibling (monospace))))
+ webkit_dom_node_append_child (monospace, sibling, NULL);
+
+ block = next_block;
+ }
+
+ /* Block containing the end of selection. */
+ node = WEBKIT_DOM_NODE (selection_end_marker);
+ while (block && node && !webkit_dom_node_is_same_node (block, node)) {
+ monospace = webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (node),
+ webkit_dom_node_clone_node_with_error (monospace, FALSE, NULL),
+ webkit_dom_node_get_next_sibling (node),
+ NULL);
+
+ while (((sibling = webkit_dom_node_get_previous_sibling (monospace)))) {
+ webkit_dom_node_insert_before (
+ monospace,
+ sibling,
+ webkit_dom_node_get_first_child (monospace),
+ NULL);
+ }
+
+ node = webkit_dom_node_get_parent_node (monospace);
+ }
+ out:
+ /* Merge all the monospace elements inside other monospace elements. */
+ list = webkit_dom_document_query_selector_all (
+ document, "font[face=monospace] > font[face=monospace]", NULL);
+ length = webkit_dom_node_list_get_length (list);
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMNode *item;
+ WebKitDOMNode *child;
+
+ item = webkit_dom_node_list_item (list, ii);
+ while ((child = webkit_dom_node_get_first_child (item))) {
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (item),
+ child,
+ item,
+ NULL);
+ }
+ remove_node (item);
+ g_object_unref (item);
+ }
+ g_clear_object (&list);
+
+ /* Merge all the adjacent monospace elements. */
+ list = webkit_dom_document_query_selector_all (
+ document, "font[face=monospace] + font[face=monospace]", NULL);
+ length = webkit_dom_node_list_get_length (list);
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMNode *item;
+ WebKitDOMNode *child;
+
+ item = webkit_dom_node_list_item (list, ii);
+ /* The + CSS selector will return some false positives as it doesn't
+ * take text between elements into account so it will return this:
+ * <font face="monospace">xx</font>yy<font face="monospace">zz</font>
+ * as valid, but it isn't so we have to check if previous node
+ * is indeed element or not. */
+ if (WEBKIT_DOM_IS_ELEMENT (webkit_dom_node_get_previous_sibling (item))) {
+ while ((child = webkit_dom_node_get_first_child (item))) {
+ webkit_dom_node_append_child (
+ webkit_dom_node_get_previous_sibling (item), child, NULL);
+ }
+ remove_node (item);
+ }
+ g_object_unref (item);
+ }
+ g_clear_object (&list);
+
+ e_editor_dom_selection_restore (editor_page);
+}
+
+static void
+unmonospace_selection (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *selection_start_marker;
+ WebKitDOMElement *selection_end_marker;
+ WebKitDOMElement *selection_start_clone;
+ WebKitDOMElement *selection_end_clone;
+ WebKitDOMNode *sibling, *node;
+ WebKitDOMNode *block, *clone, *monospace;
+ gboolean selection_end = FALSE;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+ e_editor_dom_selection_save (editor_page);
+
+ selection_start_marker = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-start-marker");
+ selection_end_marker = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-end-marker");
+
+ block = WEBKIT_DOM_NODE (get_parent_block_element (WEBKIT_DOM_NODE (selection_start_marker)));
+
+ node = WEBKIT_DOM_NODE (selection_start_marker);
+ monospace = webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (selection_start_marker));
+ while (monospace && !is_monospace_element (WEBKIT_DOM_ELEMENT (monospace)))
+ monospace = webkit_dom_node_get_parent_node (monospace);
+
+ /* No monospaced element was found as a parent of selection start node. */
+ if (!monospace)
+ goto out;
+
+ /* Make a clone of current monospaced element. */
+ clone = webkit_dom_node_clone_node_with_error (monospace, TRUE, NULL);
+
+ /* First block */
+ /* Remove all the nodes that are after the selection start point as they
+ * will be in the cloned node. */
+ while (monospace && node && !webkit_dom_node_is_same_node (monospace, node)) {
+ WebKitDOMNode *tmp;
+ while (((sibling = webkit_dom_node_get_next_sibling (node))))
+ remove_node (sibling);
+
+ tmp = webkit_dom_node_get_parent_node (node);
+ if (webkit_dom_node_get_next_sibling (node))
+ remove_node (node);
+ node = tmp;
+ }
+
+ selection_start_clone = webkit_dom_element_query_selector (
+ WEBKIT_DOM_ELEMENT (clone), "#-x-evo-selection-start-marker", NULL);
+ selection_end_clone = webkit_dom_element_query_selector (
+ WEBKIT_DOM_ELEMENT (clone), "#-x-evo-selection-end-marker", NULL);
+
+ /* No selection start node in the block where it is supposed to be, return. */
+ if (!selection_start_clone)
+ goto out;
+
+ /* Remove all the nodes until we hit the selection start point as these
+ * nodes will stay monospaced and they are already in original element. */
+ node = webkit_dom_node_get_first_child (clone);
+ while (node) {
+ WebKitDOMNode *next_sibling;
+
+ next_sibling = webkit_dom_node_get_next_sibling (node);
+ if (webkit_dom_node_get_first_child (node)) {
+ if (webkit_dom_node_contains (node, WEBKIT_DOM_NODE (selection_start_clone))) {
+ node = webkit_dom_node_get_first_child (node);
+ continue;
+ } else
+ remove_node (node);
+ } else if (webkit_dom_node_is_same_node (node, WEBKIT_DOM_NODE (selection_start_clone)))
+ break;
+ else
+ remove_node (node);
+
+ node = next_sibling;
+ }
+
+ /* Insert the clone into the tree. Do it after the previous clean up. If
+ * we would do it the other way the line would contain duplicated text nodes
+ * and the block would be expading and shrinking while we would modify it. */
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (monospace),
+ clone,
+ webkit_dom_node_get_next_sibling (monospace),
+ NULL);
+
+ /* Move selection start point the right place. */
+ remove_node (WEBKIT_DOM_NODE (selection_start_marker));
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (clone),
+ WEBKIT_DOM_NODE (selection_start_clone),
+ clone,
+ NULL);
+
+ /* Move all the nodes the are supposed to lose the monospace formatting
+ * out of monospaced element. */
+ node = webkit_dom_node_get_first_child (clone);
+ while (node) {
+ WebKitDOMNode *next_sibling;
+
+ next_sibling = webkit_dom_node_get_next_sibling (node);
+ if (webkit_dom_node_get_first_child (node)) {
+ if (selection_end_clone &&
+ webkit_dom_node_contains (node, WEBKIT_DOM_NODE (selection_end_clone))) {
+ node = webkit_dom_node_get_first_child (node);
+ continue;
+ } else
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (clone),
+ node,
+ clone,
+ NULL);
+ } else if (selection_end_clone &&
+ webkit_dom_node_is_same_node (node, WEBKIT_DOM_NODE (selection_end_clone))) {
+ selection_end = TRUE;
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (clone),
+ node,
+ clone,
+ NULL);
+ break;
+ } else
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (clone),
+ node,
+ clone,
+ NULL);
+
+ node = next_sibling;
+ }
+
+ if (!webkit_dom_node_get_first_child (clone))
+ remove_node (clone);
+
+ /* Just one block was selected and we hit the selection end point. */
+ if (selection_end)
+ goto out;
+
+ /* Middle blocks */
+ block = webkit_dom_node_get_next_sibling (block);
+ while (block && !selection_end) {
+ WebKitDOMNode *next_block, *child, *parent;
+ WebKitDOMElement *monospace_element;
+
+ selection_end = webkit_dom_node_contains (
+ block, WEBKIT_DOM_NODE (selection_end_marker));
+
+ if (selection_end)
+ break;
+
+ next_block = webkit_dom_node_get_next_sibling (block);
+
+ /* Find the monospaced element and move all the nodes from it and
+ * finally remove it. */
+ monospace_element = webkit_dom_element_query_selector (
+ WEBKIT_DOM_ELEMENT (block), "font[face=monospace]", NULL);
+ if (!monospace_element)
+ break;
+
+ parent = webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (monospace_element));
+ while ((child = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (monospace_element)))) {
+ webkit_dom_node_insert_before (
+ parent, child, WEBKIT_DOM_NODE (monospace_element), NULL);
+ }
+
+ remove_node (WEBKIT_DOM_NODE (monospace_element));
+
+ block = next_block;
+ }
+
+ /* End block */
+ node = WEBKIT_DOM_NODE (selection_end_marker);
+ monospace = webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (selection_end_marker));
+ while (monospace && !is_monospace_element (WEBKIT_DOM_ELEMENT (monospace)))
+ monospace = webkit_dom_node_get_parent_node (monospace);
+
+ /* No monospaced element was found as a parent of selection end node. */
+ if (!monospace)
+ return;
+
+ clone = WEBKIT_DOM_NODE (monospace);
+ node = webkit_dom_node_get_first_child (clone);
+ /* Move all the nodes that are supposed to lose the monospaced formatting
+ * out of the monospaced element. */
+ while (node) {
+ WebKitDOMNode *next_sibling;
+
+ next_sibling = webkit_dom_node_get_next_sibling (node);
+ if (webkit_dom_node_get_first_child (node)) {
+ if (webkit_dom_node_contains (node, WEBKIT_DOM_NODE (selection_end_marker))) {
+ node = webkit_dom_node_get_first_child (node);
+ continue;
+ } else
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (clone),
+ node,
+ clone,
+ NULL);
+ } else if (webkit_dom_node_is_same_node (node, WEBKIT_DOM_NODE (selection_end_marker))) {
+ selection_end = TRUE;
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (clone),
+ node,
+ clone,
+ NULL);
+ break;
+ } else {
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (clone),
+ node,
+ clone,
+ NULL);
+ }
+
+ node = next_sibling;
+ }
+
+ if (!webkit_dom_node_get_first_child (clone))
+ remove_node (clone);
+ out:
+ e_editor_dom_selection_restore (editor_page);
+}
+
+/*
+ * e_html_editor_selection_set_monospaced:
+ * @selection: an #EEditorSelection
+ * @monospaced: @TRUE to enable monospaced, @FALSE to disable
+ *
+ * Toggles monospaced formatting of current selection or letter at current cursor
+ * position, depending on whether @monospaced is @TRUE or @FALSE.
+ */
+void
+e_editor_dom_selection_set_monospace (EEditorPage *editor_page,
+ gboolean value)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMRange *range = NULL;
+ EEditorHistoryEvent *ev = NULL;
+ EEditorUndoRedoManager *manager;
+ guint font_size = 0;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ if ((e_editor_dom_selection_is_monospace (editor_page) ? 1 : 0) == (value ? 1 : 0))
+ return;
+
+ document = e_editor_page_get_document (editor_page);
+ range = e_editor_dom_get_current_range (editor_page);
+ if (!range)
+ return;
+
+ manager = e_editor_page_get_undo_redo_manager (editor_page);
+ if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+ ev = g_new0 (EEditorHistoryEvent, 1);
+ ev->type = HISTORY_MONOSPACE;
+
+ e_editor_dom_selection_get_coordinates (editor_page,
+ &ev->before.start.x,
+ &ev->before.start.y,
+ &ev->before.end.x,
+ &ev->before.end.y);
+
+ ev->data.style.from = !value;
+ ev->data.style.to = value;
+ }
+
+ font_size = e_editor_page_get_font_size (editor_page);
+ if (font_size == 0)
+ font_size = E_CONTENT_EDITOR_FONT_SIZE_NORMAL;
+
+ if (value) {
+ WebKitDOMElement *monospace;
+
+ monospace = webkit_dom_document_create_element (
+ document, "font", NULL);
+ webkit_dom_element_set_attribute (
+ monospace, "face", "monospace", NULL);
+ if (font_size != 0) {
+ gchar *font_size_str;
+
+ font_size_str = g_strdup_printf ("%d", font_size);
+ webkit_dom_element_set_attribute (
+ monospace, "size", font_size_str, NULL);
+ g_free (font_size_str);
+ }
+
+ if (!webkit_dom_range_get_collapsed (range, NULL))
+ monospace_selection (editor_page, monospace);
+ else {
+ /* https://bugs.webkit.org/show_bug.cgi?id=15256 */
+ webkit_dom_element_set_inner_html (
+ monospace,
+ UNICODE_ZERO_WIDTH_SPACE,
+ NULL);
+ webkit_dom_range_insert_node (
+ range, WEBKIT_DOM_NODE (monospace), NULL);
+
+ e_editor_dom_move_caret_into_element (editor_page, monospace, FALSE);
+ }
+ } else {
+ gboolean is_bold = FALSE, is_italic = FALSE;
+ gboolean is_underline = FALSE, is_strikethrough = FALSE;
+ guint font_size = 0;
+ WebKitDOMElement *tt_element;
+ WebKitDOMNode *node;
+
+ node = webkit_dom_range_get_end_container (range, NULL);
+ if (WEBKIT_DOM_IS_ELEMENT (node) &&
+ is_monospace_element (WEBKIT_DOM_ELEMENT (node))) {
+ tt_element = WEBKIT_DOM_ELEMENT (node);
+ } else {
+ tt_element = dom_node_find_parent_element (node, "FONT");
+
+ if (!is_monospace_element (tt_element)) {
+ g_clear_object (&range);
+ g_free (ev);
+ return;
+ }
+ }
+
+ /* Save current formatting */
+ is_bold = e_editor_page_get_bold (editor_page);
+ is_italic = e_editor_page_get_italic (editor_page);
+ is_underline = e_editor_page_get_underline (editor_page);
+ is_strikethrough = e_editor_page_get_strikethrough (editor_page);
+
+ if (!e_editor_dom_selection_is_collapsed (editor_page))
+ unmonospace_selection (editor_page);
+ else {
+ e_editor_dom_selection_save (editor_page);
+ set_font_style (document, "", FALSE);
+ e_editor_dom_selection_restore (editor_page);
+ }
+
+ /* Re-set formatting */
+ if (is_bold)
+ e_editor_dom_selection_set_bold (editor_page, TRUE);
+ if (is_italic)
+ e_editor_dom_selection_set_italic (editor_page, TRUE);
+ if (is_underline)
+ e_editor_dom_selection_set_underline (editor_page, TRUE);
+ if (is_strikethrough)
+ e_editor_dom_selection_set_strikethrough (editor_page, TRUE);
+
+ if (font_size)
+ e_editor_dom_selection_set_font_size (editor_page, font_size);
+ }
+
+ if (ev) {
+ e_editor_dom_selection_get_coordinates (editor_page,
+ &ev->after.start.x,
+ &ev->after.start.y,
+ &ev->after.end.x,
+ &ev->after.end.y);
+ e_editor_undo_redo_manager_insert_history_event (manager, ev);
+ }
+
+ e_editor_dom_force_spell_check_for_current_paragraph (editor_page);
+
+ g_clear_object (&range);
+}
+
+static gboolean
+is_bold_element (WebKitDOMElement *element)
+{
+ if (!element || !WEBKIT_DOM_IS_ELEMENT (element))
+ return FALSE;
+
+ if (element_has_tag (element, "b"))
+ return TRUE;
+
+ /* Headings are bold by default */
+ return WEBKIT_DOM_IS_HTML_HEADING_ELEMENT (element);
+}
+
+/*
+ * e_html_editor_selection_is_bold:
+ * @selection: an #EEditorSelection
+ *
+ * Returns whether current selection or letter at current cursor position
+ * is bold.
+ *
+ * Returns @TRUE when selection is bold, @FALSE otherwise.
+ */
+gboolean
+e_editor_dom_selection_is_bold (EEditorPage *editor_page)
+{
+ gboolean is_bold;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+ is_bold = e_editor_page_get_bold (editor_page);
+
+ is_bold = dom_selection_is_font_format (
+ editor_page, (IsRightFormatNodeFunc) is_bold_element, &is_bold);
+
+ return is_bold;
+}
+
+/*
+ * e_html_editor_selection_set_bold:
+ * @selection: an #EEditorSelection
+ * @bold: @TRUE to enable bold, @FALSE to disable
+ *
+ * Toggles bold formatting of current selection or letter at current cursor
+ * position, depending on whether @bold is @TRUE or @FALSE.
+ */
+void
+e_editor_dom_selection_set_bold (EEditorPage *editor_page,
+ gboolean bold)
+{
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ if (e_editor_dom_selection_is_bold (editor_page) == bold)
+ return;
+
+ selection_set_font_style (
+ editor_page, E_CONTENT_EDITOR_COMMAND_BOLD, bold);
+
+ e_editor_dom_force_spell_check_for_current_paragraph (editor_page);
+}
+
+static gboolean
+is_italic_element (WebKitDOMElement *element)
+{
+ if (!element || !WEBKIT_DOM_IS_ELEMENT (element))
+ return FALSE;
+
+ return element_has_tag (element, "i") || element_has_tag (element, "address");
+}
+
+/*
+ * e_html_editor_selection_is_italic:
+ * @selection: an #EEditorSelection
+ *
+ * Returns whether current selection or letter at current cursor position
+ * is italic.
+ *
+ * Returns @TRUE when selection is italic, @FALSE otherwise.
+ */
+gboolean
+e_editor_dom_selection_is_italic (EEditorPage *editor_page)
+{
+ gboolean is_italic;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+ is_italic = e_editor_page_get_italic (editor_page);
+ is_italic = dom_selection_is_font_format (
+ editor_page, (IsRightFormatNodeFunc) is_italic_element, &is_italic);
+
+ return is_italic;
+}
+
+/*
+ * e_html_editor_selection_set_italic:
+ * @selection: an #EEditorSelection
+ * @italic: @TRUE to enable italic, @FALSE to disable
+ *
+ * Toggles italic formatting of current selection or letter at current cursor
+ * position, depending on whether @italic is @TRUE or @FALSE.
+ */
+void
+e_editor_dom_selection_set_italic (EEditorPage *editor_page,
+ gboolean italic)
+{
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ if (e_editor_dom_selection_is_italic (editor_page) == italic)
+ return;
+
+ selection_set_font_style (
+ editor_page, E_CONTENT_EDITOR_COMMAND_ITALIC, italic);
+}
+
+/*
+ * e_html_editor_selection_is_indented:
+ * @selection: an #EEditorSelection
+ *
+ * Returns whether current paragraph is indented. This does not include
+ * citations. To check, whether paragraph is a citation, use
+ * e_html_editor_selection_is_citation().
+ *
+ * Returns: @TRUE when current paragraph is indented, @FALSE otherwise.
+ */
+gboolean
+e_editor_dom_selection_is_indented (EEditorPage *editor_page)
+{
+ WebKitDOMElement *element;
+ WebKitDOMRange *range = NULL;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+ range = e_editor_dom_get_current_range (editor_page);
+ if (!range)
+ return FALSE;
+
+ if (webkit_dom_range_get_collapsed (range, NULL)) {
+ element = get_element_for_inspection (range);
+ g_clear_object (&range);
+ return element_has_class (element, "-x-evo-indented");
+ } else {
+ WebKitDOMNode *node;
+ gboolean ret_val;
+
+ node = webkit_dom_range_get_end_container (range, NULL);
+ /* No selection or whole body selected */
+ if (WEBKIT_DOM_IS_HTML_BODY_ELEMENT (node))
+ goto out;
+
+ element = WEBKIT_DOM_ELEMENT (get_parent_indented_block (node));
+ ret_val = element_has_class (element, "-x-evo-indented");
+ if (!ret_val)
+ goto out;
+
+ node = webkit_dom_range_get_start_container (range, NULL);
+ /* No selection or whole body selected */
+ if (WEBKIT_DOM_IS_HTML_BODY_ELEMENT (node))
+ goto out;
+
+ element = WEBKIT_DOM_ELEMENT (get_parent_indented_block (node));
+ ret_val = element_has_class (element, "-x-evo-indented");
+
+ g_clear_object (&range);
+
+ return ret_val;
+ }
+
+ out:
+ g_clear_object (&range);
+
+ return FALSE;
+}
+
+/*
+ * e_html_editor_selection_is_citation:
+ * @selection: an #EEditorSelection
+ *
+ * Returns whether current paragraph is a citation.
+ *
+ * Returns: @TRUE when current paragraph is a citation, @FALSE otherwise.
+ */
+gboolean
+e_editor_dom_selection_is_citation (EEditorPage *editor_page)
+{
+ WebKitDOMNode *node;
+ WebKitDOMRange *range = NULL;
+ gboolean ret_val;
+ gchar *value, *text_content;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+ range = e_editor_dom_get_current_range (editor_page);
+ if (!range)
+ return FALSE;
+
+ node = webkit_dom_range_get_common_ancestor_container (range, NULL);
+ g_clear_object (&range);
+
+ if (WEBKIT_DOM_IS_TEXT (node))
+ return get_has_style (editor_page, "citation");
+
+ text_content = webkit_dom_node_get_text_content (node);
+ if (g_strcmp0 (text_content, "") == 0) {
+ g_free (text_content);
+ return FALSE;
+ }
+ g_free (text_content);
+
+ value = webkit_dom_element_get_attribute (WEBKIT_DOM_ELEMENT (node), "type");
+ /* citation == <blockquote type='cite'> */
+ if (value && strstr (value, "cite"))
+ ret_val = TRUE;
+ else
+ ret_val = get_has_style (editor_page, "citation");
+
+ g_free (value);
+ return ret_val;
+}
+
+static gchar *
+get_font_property (EEditorPage *editor_page,
+ const gchar *font_property)
+{
+ WebKitDOMRange *range = NULL;
+ WebKitDOMNode *node;
+ WebKitDOMElement *element;
+ gchar *value;
+
+ range = e_editor_dom_get_current_range (editor_page);
+ if (!range)
+ return NULL;
+
+ node = webkit_dom_range_get_common_ancestor_container (range, NULL);
+ g_clear_object (&range);
+ element = dom_node_find_parent_element (node, "FONT");
+ while (element && !WEBKIT_DOM_IS_HTML_BODY_ELEMENT (element) &&
+ !webkit_dom_element_has_attribute (element, font_property)) {
+ element = dom_node_find_parent_element (
+ webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element)), "FONT");
+ }
+
+ if (!element)
+ return NULL;
+
+ g_object_get (G_OBJECT (element), font_property, &value, NULL);
+
+ return value;
+}
+
+/*
+ * e_editor_dom_selection_get_font_size:
+ * @selection: an #EEditorSelection
+ *
+ * Returns point size of current selection or of letter at current cursor position.
+ */
+guint
+e_editor_dom_selection_get_font_size (EEditorPage *editor_page)
+{
+ gchar *size;
+ guint size_int;
+ gboolean increment;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), 0);
+
+ size = get_font_property (editor_page, "size");
+ if (!(size && *size)) {
+ g_free (size);
+ return E_CONTENT_EDITOR_FONT_SIZE_NORMAL;
+ }
+
+ /* We don't support increments, but when going through a content that
+ * was not written in Evolution we can find it. In this case just report
+ * the normal size. */
+ /* FIXME: go through all parent and get the right value. */
+ increment = size[0] == '+' || size[0] == '-';
+ size_int = atoi (size);
+ g_free (size);
+
+ if (increment || size_int == 0)
+ return E_CONTENT_EDITOR_FONT_SIZE_NORMAL;
+
+ return size_int;
+}
+
+/*
+ * e_html_editor_selection_set_font_size:
+ * @selection: an #EEditorSelection
+ * @font_size: point size to apply
+ *
+ * Sets font size of current selection or of letter at current cursor position
+ * to @font_size.
+ */
+void
+e_editor_dom_selection_set_font_size (EEditorPage *editor_page,
+ EContentEditorFontSize font_size)
+{
+ WebKitDOMDocument *document;
+ EEditorUndoRedoManager *manager;
+ EEditorHistoryEvent *ev = NULL;
+ gchar *size_str;
+ guint current_font_size;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+ current_font_size = e_editor_dom_selection_get_font_size (editor_page);
+ if (current_font_size == font_size)
+ return;
+
+ e_editor_dom_selection_save (editor_page);
+
+ manager = e_editor_page_get_undo_redo_manager (editor_page);
+ if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+ ev = g_new0 (EEditorHistoryEvent, 1);
+ ev->type = HISTORY_FONT_SIZE;
+
+ e_editor_dom_selection_get_coordinates (editor_page,
+ &ev->before.start.x,
+ &ev->before.start.y,
+ &ev->before.end.x,
+ &ev->before.end.y);
+
+ ev->data.style.from = current_font_size;
+ ev->data.style.to = font_size;
+ }
+
+ size_str = g_strdup_printf ("%d", font_size);
+
+ if (e_editor_dom_selection_is_collapsed (editor_page)) {
+ WebKitDOMElement *font;
+
+ font = set_font_style (document, "font", font_size != 3);
+ if (font)
+ webkit_dom_element_set_attribute (font, "size", size_str, NULL);
+ e_editor_dom_selection_restore (editor_page);
+ goto exit;
+ }
+
+ e_editor_dom_selection_restore (editor_page);
+
+ e_editor_dom_exec_command (editor_page, E_CONTENT_EDITOR_COMMAND_FONT_SIZE, size_str);
+
+ /* Text in <font size="3"></font> (size 3 is our default size) is a little
+ * bit smaller than font outsize it. So move it outside of it. */
+ if (font_size == E_CONTENT_EDITOR_FONT_SIZE_NORMAL) {
+ WebKitDOMElement *element;
+
+ element = webkit_dom_document_query_selector (document, "font[size=\"3\"]", NULL);
+ if (element) {
+ WebKitDOMNode *child;
+
+ while ((child = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (element))))
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element)),
+ child,
+ WEBKIT_DOM_NODE (element),
+ NULL);
+
+ remove_node (WEBKIT_DOM_NODE (element));
+ }
+ }
+
+ exit:
+ g_free (size_str);
+
+ if (ev) {
+ e_editor_dom_selection_get_coordinates (editor_page,
+ &ev->after.start.x,
+ &ev->after.start.y,
+ &ev->after.end.x,
+ &ev->after.end.y);
+
+ e_editor_undo_redo_manager_insert_history_event (manager, ev);
+ }
+}
+
+/*
+ * e_html_editor_selection_set_font_name:
+ * @selection: an #EEditorSelection
+ * @font_name: a font name to apply
+ *
+ * Sets font name of current selection or of letter at current cursor position
+ * to @font_name.
+ */
+void
+e_editor_dom_selection_set_font_name (EEditorPage *editor_page,
+ const gchar *font_name)
+{
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ e_editor_dom_exec_command (editor_page, E_CONTENT_EDITOR_COMMAND_FONT_NAME, font_name);
+}
+
+/*
+ * e_html_editor_selection_get_font_name:
+ * @selection: an #EEditorSelection
+ *
+ * Returns name of font used in current selection or at letter at current cursor
+ * position.
+ *
+ * Returns: A string with font name. [transfer-none]
+ */
+gchar *
+e_editor_dom_selection_get_font_name (EEditorPage *editor_page)
+{
+ WebKitDOMNode *node;
+ WebKitDOMRange *range = NULL;
+ WebKitDOMCSSStyleDeclaration *css = NULL;
+ gchar *value;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+ range = e_editor_dom_get_current_range (editor_page);
+ node = webkit_dom_range_get_common_ancestor_container (range, NULL);
+ g_clear_object (&range);
+
+ css = webkit_dom_element_get_style (WEBKIT_DOM_ELEMENT (node));
+ value = webkit_dom_css_style_declaration_get_property_value (css, "fontFamily");
+ g_clear_object (&css);
+
+ return value;
+}
+
+/*
+ * e_html_editor_selection_set_font_color:
+ * @selection: an #EEditorSelection
+ * @rgba: a #GdkRGBA
+ *
+ * Sets font color of current selection or letter at current cursor position to
+ * color defined in @rgba.
+ */
+void
+e_editor_dom_selection_set_font_color (EEditorPage *editor_page,
+ const gchar *color)
+{
+ EEditorUndoRedoManager *manager;
+ EEditorHistoryEvent *ev = NULL;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ manager = e_editor_page_get_undo_redo_manager (editor_page);
+ if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+ ev = g_new0 (EEditorHistoryEvent, 1);
+ ev->type = HISTORY_FONT_COLOR;
+
+ e_editor_dom_selection_get_coordinates (editor_page,
+ &ev->before.start.x,
+ &ev->before.start.y,
+ &ev->before.end.x,
+ &ev->before.end.y);
+
+ ev->data.string.from = g_strdup (e_editor_page_get_font_color (editor_page));
+ ev->data.string.to = g_strdup (color);
+ }
+
+ e_editor_dom_exec_command (editor_page, E_CONTENT_EDITOR_COMMAND_FORE_COLOR, color);
+
+ if (ev) {
+ ev->after.start.x = ev->before.start.x;
+ ev->after.start.y = ev->before.start.y;
+ ev->after.end.x = ev->before.end.x;
+ ev->after.end.y = ev->before.end.y;
+
+ e_editor_undo_redo_manager_insert_history_event (manager, ev);
+ }
+}
+
+/*
+ * e_html_editor_selection_get_font_color:
+ * @selection: an #EEditorSelection
+ * @rgba: a #GdkRGBA object to be set to current font color
+ *
+ * Sets @rgba to contain color of current text selection or letter at current
+ * cursor position.
+ */
+gchar *
+e_editor_dom_selection_get_font_color (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ gchar *color;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+ document = e_editor_page_get_document (editor_page);
+ color = get_font_property (editor_page, "color");
+ if (!(color && *color)) {
+ WebKitDOMHTMLElement *body;
+
+ body = webkit_dom_document_get_body (document);
+ g_free (color);
+ color = webkit_dom_html_body_element_get_text (WEBKIT_DOM_HTML_BODY_ELEMENT (body));
+ if (!(color && *color)) {
+ g_free (color);
+ return g_strdup ("#000000");
+ }
+ }
+
+ return color;
+}
+
+/*
+ * e_html_editor_selection_get_block_format:
+ * @selection: an #EEditorSelection
+ *
+ * Returns block format of current paragraph.
+ *
+ * Returns: #EContentEditorBlockFormat
+ */
+EContentEditorBlockFormat
+e_editor_dom_selection_get_block_format (EEditorPage *editor_page)
+{
+ WebKitDOMNode *node;
+ WebKitDOMRange *range = NULL;
+ WebKitDOMElement *element;
+ EContentEditorBlockFormat result;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), E_CONTENT_EDITOR_BLOCK_FORMAT_NONE);
+
+ range = e_editor_dom_get_current_range (editor_page);
+ if (!range)
+ return E_CONTENT_EDITOR_BLOCK_FORMAT_PARAGRAPH;
+
+ node = webkit_dom_range_get_start_container (range, NULL);
+
+ if ((element = dom_node_find_parent_element (node, "UL"))) {
+ WebKitDOMElement *tmp_element;
+
+ tmp_element = dom_node_find_parent_element (node, "OL");
+ if (tmp_element) {
+ if (webkit_dom_node_contains (WEBKIT_DOM_NODE (tmp_element), WEBKIT_DOM_NODE
(element)))
+ result = dom_get_list_format_from_node (WEBKIT_DOM_NODE (element));
+ else
+ result = dom_get_list_format_from_node (WEBKIT_DOM_NODE (tmp_element));
+ } else
+ result = E_CONTENT_EDITOR_BLOCK_FORMAT_UNORDERED_LIST;
+ } else if ((element = dom_node_find_parent_element (node, "OL")) != NULL) {
+ WebKitDOMElement *tmp_element;
+
+ tmp_element = dom_node_find_parent_element (node, "UL");
+ if (tmp_element) {
+ if (webkit_dom_node_contains (WEBKIT_DOM_NODE (element), WEBKIT_DOM_NODE
(tmp_element)))
+ result = dom_get_list_format_from_node (WEBKIT_DOM_NODE (element));
+ else
+ result = dom_get_list_format_from_node (WEBKIT_DOM_NODE (tmp_element));
+ } else
+ result = dom_get_list_format_from_node (WEBKIT_DOM_NODE (element));
+ } else if (dom_node_find_parent_element (node, "PRE")) {
+ result = E_CONTENT_EDITOR_BLOCK_FORMAT_PRE;
+ } else if (dom_node_find_parent_element (node, "ADDRESS")) {
+ result = E_CONTENT_EDITOR_BLOCK_FORMAT_ADDRESS;
+ } else if (dom_node_find_parent_element (node, "H1")) {
+ result = E_CONTENT_EDITOR_BLOCK_FORMAT_H1;
+ } else if (dom_node_find_parent_element (node, "H2")) {
+ result = E_CONTENT_EDITOR_BLOCK_FORMAT_H2;
+ } else if (dom_node_find_parent_element (node, "H3")) {
+ result = E_CONTENT_EDITOR_BLOCK_FORMAT_H3;
+ } else if (dom_node_find_parent_element (node, "H4")) {
+ result = E_CONTENT_EDITOR_BLOCK_FORMAT_H4;
+ } else if (dom_node_find_parent_element (node, "H5")) {
+ result = E_CONTENT_EDITOR_BLOCK_FORMAT_H5;
+ } else if (dom_node_find_parent_element (node, "H6")) {
+ result = E_CONTENT_EDITOR_BLOCK_FORMAT_H6;
+ } else if ((element = dom_node_find_parent_element (node, "BLOCKQUOTE")) != NULL) {
+ result = E_CONTENT_EDITOR_BLOCK_FORMAT_PARAGRAPH;
+ } else if (dom_node_find_parent_element (node, "P")) {
+ result = E_CONTENT_EDITOR_BLOCK_FORMAT_PARAGRAPH;
+ } else {
+ result = E_CONTENT_EDITOR_BLOCK_FORMAT_PARAGRAPH;
+ }
+
+ g_clear_object (&range);
+
+ return result;
+}
+
+static void
+change_leading_space_to_nbsp (WebKitDOMNode *block)
+{
+ WebKitDOMNode *child;
+
+ if (!WEBKIT_DOM_IS_HTML_PRE_ELEMENT (block))
+ return;
+
+ if ((child = webkit_dom_node_get_first_child (block)) &&
+ WEBKIT_DOM_IS_CHARACTER_DATA (child)) {
+ gchar *data;
+
+ data = webkit_dom_character_data_substring_data (
+ WEBKIT_DOM_CHARACTER_DATA (child), 0, 1, NULL);
+
+ if (data && *data == ' ')
+ webkit_dom_character_data_replace_data (
+ WEBKIT_DOM_CHARACTER_DATA (child), 0, 1, UNICODE_NBSP, NULL);
+ g_free (data);
+ }
+}
+
+static void
+change_trailing_space_in_block_to_nbsp (WebKitDOMNode *block)
+{
+ WebKitDOMNode *child;
+
+ if ((child = webkit_dom_node_get_last_child (block)) &&
+ WEBKIT_DOM_IS_CHARACTER_DATA (child)) {
+ gchar *tmp;
+ gulong length;
+
+ length = webkit_dom_character_data_get_length (
+ WEBKIT_DOM_CHARACTER_DATA (child));
+
+ tmp = webkit_dom_character_data_substring_data (
+ WEBKIT_DOM_CHARACTER_DATA (child), length - 1, 1, NULL);
+ if (tmp && *tmp == ' ') {
+ webkit_dom_character_data_replace_data (
+ WEBKIT_DOM_CHARACTER_DATA (child),
+ length - 1,
+ 1,
+ UNICODE_NBSP,
+ NULL);
+ }
+ g_free (tmp);
+ }
+}
+
+static void
+change_space_before_selection_to_nbsp (WebKitDOMNode *node)
+{
+ WebKitDOMNode *prev_sibling;
+
+ if ((prev_sibling = webkit_dom_node_get_previous_sibling (node))) {
+ if (WEBKIT_DOM_IS_CHARACTER_DATA (prev_sibling)) {
+ gchar *tmp;
+ gulong length;
+
+ length = webkit_dom_character_data_get_length (
+ WEBKIT_DOM_CHARACTER_DATA (prev_sibling));
+
+ tmp = webkit_dom_character_data_substring_data (
+ WEBKIT_DOM_CHARACTER_DATA (prev_sibling), length - 1, 1, NULL);
+ if (tmp && *tmp == ' ') {
+ webkit_dom_character_data_replace_data (
+ WEBKIT_DOM_CHARACTER_DATA (prev_sibling),
+ length - 1,
+ 1,
+ UNICODE_NBSP,
+ NULL);
+ }
+ g_free (tmp);
+ }
+ }
+}
+
+static gboolean
+process_block_to_block (EEditorPage *editor_page,
+ EContentEditorBlockFormat format,
+ const gchar *value,
+ WebKitDOMNode *block,
+ WebKitDOMNode *end_block,
+ WebKitDOMNode *blockquote,
+ gboolean html_mode)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMNode *next_block;
+ gboolean after_selection_end = FALSE;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+ document = e_editor_page_get_document (editor_page);
+
+ while (!after_selection_end && block) {
+ gboolean quoted = FALSE;
+ gboolean empty = FALSE;
+ gchar *content;
+ gint citation_level = 0;
+ WebKitDOMNode *child;
+ WebKitDOMElement *element;
+
+ if (e_editor_dom_node_is_citation_node (block)) {
+ gboolean finished;
+
+ next_block = webkit_dom_node_get_next_sibling (block);
+ finished = process_block_to_block (
+ editor_page,
+ format,
+ value,
+ webkit_dom_node_get_first_child (block),
+ end_block,
+ blockquote,
+ html_mode);
+
+ if (finished)
+ return TRUE;
+
+ block = next_block;
+
+ continue;
+ }
+
+ if (webkit_dom_element_query_selector (
+ WEBKIT_DOM_ELEMENT (block), "span.-x-evo-quoted", NULL)) {
+ quoted = TRUE;
+ e_editor_dom_remove_quoting_from_element (WEBKIT_DOM_ELEMENT (block));
+ }
+
+ if (!html_mode)
+ e_editor_dom_remove_wrapping_from_element (WEBKIT_DOM_ELEMENT (block));
+
+ after_selection_end = webkit_dom_node_is_same_node (block, end_block);
+
+ next_block = webkit_dom_node_get_next_sibling (block);
+
+ if (node_is_list (block)) {
+ WebKitDOMNode *item;
+
+ item = webkit_dom_node_get_first_child (block);
+ while (item && !WEBKIT_DOM_IS_HTML_LI_ELEMENT (item))
+ item = webkit_dom_node_get_first_child (item);
+
+ if (item && do_format_change_list_to_block (editor_page, format, item, value))
+ return TRUE;
+
+ block = next_block;
+
+ continue;
+ }
+
+ if (format == E_CONTENT_EDITOR_BLOCK_FORMAT_PARAGRAPH)
+ element = e_editor_dom_get_paragraph_element (editor_page, -1, 0);
+ else
+ element = webkit_dom_document_create_element (
+ document, value, NULL);
+
+ content = webkit_dom_node_get_text_content (block);
+
+ empty = !*content || (g_strcmp0 (content, UNICODE_ZERO_WIDTH_SPACE) == 0);
+ g_free (content);
+
+ change_leading_space_to_nbsp (block);
+ change_trailing_space_in_block_to_nbsp (block);
+
+ while ((child = webkit_dom_node_get_first_child (block))) {
+ if (WEBKIT_DOM_IS_HTML_BR_ELEMENT (child))
+ empty = FALSE;
+
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (element), child, NULL);
+ }
+
+ if (empty) {
+ WebKitDOMElement *br;
+
+ br = webkit_dom_document_create_element (
+ document, "BR", NULL);
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (element), WEBKIT_DOM_NODE (br), NULL);
+ }
+
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (block),
+ WEBKIT_DOM_NODE (element),
+ block,
+ NULL);
+
+ remove_node (block);
+
+ if (!next_block && !after_selection_end) {
+ citation_level = selection_get_citation_level (WEBKIT_DOM_NODE (element));
+
+ if (citation_level > 0) {
+ next_block = webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element));
+ next_block = webkit_dom_node_get_next_sibling (next_block);
+ }
+ }
+
+ block = next_block;
+
+ if (!html_mode && format == E_CONTENT_EDITOR_BLOCK_FORMAT_PARAGRAPH) {
+ citation_level = selection_get_citation_level (WEBKIT_DOM_NODE (element));
+
+ if (citation_level > 0) {
+ gint quote, word_wrap_length;
+
+ word_wrap_length =
+ e_editor_page_get_word_wrap_length (editor_page);
+ quote = citation_level ? citation_level * 2 : 0;
+
+ element = e_editor_dom_wrap_paragraph_length (
+ editor_page, element, word_wrap_length - quote);
+
+ }
+ }
+
+ if (!html_mode && quoted) {
+ if (citation_level > 0)
+ e_editor_dom_quote_plain_text_element_after_wrapping (
+ editor_page, element, citation_level);
+ else
+ e_editor_dom_quote_plain_text_element (editor_page, element);
+ }
+ }
+
+ return after_selection_end;
+}
+
+static void
+format_change_block_to_block (EEditorPage *editor_page,
+ EContentEditorBlockFormat format,
+ const gchar *value)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *selection_start_marker, *selection_end_marker;
+ WebKitDOMNode *block, *end_block, *blockquote = NULL;
+ gboolean html_mode = FALSE;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+ selection_start_marker = webkit_dom_document_query_selector (
+ document, "span#-x-evo-selection-start-marker", NULL);
+ selection_end_marker = webkit_dom_document_query_selector (
+ document, "span#-x-evo-selection-end-marker", NULL);
+
+ /* If the selection was not saved, move it into the first child of body */
+ if (!selection_start_marker || !selection_end_marker) {
+ WebKitDOMHTMLElement *body;
+ WebKitDOMNode *child;
+
+ body = webkit_dom_document_get_body (document);
+ child = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (body));
+
+ dom_add_selection_markers_into_element_start (
+ document,
+ WEBKIT_DOM_ELEMENT (child),
+ &selection_start_marker,
+ &selection_end_marker);
+ }
+
+ block = e_editor_dom_get_parent_block_node_from_child (
+ WEBKIT_DOM_NODE (selection_start_marker));
+
+ html_mode = e_editor_page_get_html_mode (editor_page);
+
+ end_block = e_editor_dom_get_parent_block_node_from_child (
+ WEBKIT_DOM_NODE (selection_end_marker));
+
+ /* Process all blocks that are in the selection one by one */
+ process_block_to_block (
+ editor_page, format, value, block, end_block, blockquote, html_mode);
+}
+
+static void
+format_change_block_to_list (EEditorPage *editor_page,
+ EContentEditorBlockFormat format)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *selection_start_marker, *selection_end_marker, *item, *list;
+ WebKitDOMNode *block, *next_block;
+ gboolean after_selection_end = FALSE, in_quote = FALSE;
+ gboolean html_mode = e_editor_page_get_html_mode (editor_page);
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+ selection_start_marker = webkit_dom_document_query_selector (
+ document, "span#-x-evo-selection-start-marker", NULL);
+ selection_end_marker = webkit_dom_document_query_selector (
+ document, "span#-x-evo-selection-end-marker", NULL);
+
+ /* If the selection was not saved, move it into the first child of body */
+ if (!selection_start_marker || !selection_end_marker) {
+ WebKitDOMHTMLElement *body;
+ WebKitDOMNode *child;
+
+ body = webkit_dom_document_get_body (document);
+ child = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (body));
+
+ dom_add_selection_markers_into_element_start (
+ document,
+ WEBKIT_DOM_ELEMENT (child),
+ &selection_start_marker,
+ &selection_end_marker);
+ }
+
+ block = e_editor_dom_get_parent_block_node_from_child (
+ WEBKIT_DOM_NODE (selection_start_marker));
+
+ list = create_list_element (editor_page, format, 0, html_mode);
+
+ if (webkit_dom_element_query_selector (
+ WEBKIT_DOM_ELEMENT (block), "span.-x-evo-quoted", NULL)) {
+ WebKitDOMElement *element;
+ WebKitDOMDOMWindow *dom_window = NULL;
+ WebKitDOMDOMSelection *dom_selection = NULL;
+ WebKitDOMRange *range = NULL;
+
+ in_quote = TRUE;
+
+ dom_window = webkit_dom_document_get_default_view (document);
+ dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+ range = webkit_dom_document_create_range (document);
+
+ webkit_dom_range_select_node (range, block, NULL);
+ webkit_dom_range_collapse (range, TRUE, NULL);
+ webkit_dom_dom_selection_remove_all_ranges (dom_selection);
+ webkit_dom_dom_selection_add_range (dom_selection, range);
+
+ g_clear_object (&range);
+ g_clear_object (&dom_selection);
+ g_clear_object (&dom_window);
+
+ e_editor_dom_remove_input_event_listener_from_body (editor_page);
+ e_editor_page_block_selection_changed (editor_page);
+
+ e_editor_dom_exec_command (
+ editor_page, E_CONTENT_EDITOR_COMMAND_INSERT_NEW_LINE_IN_QUOTED_CONTENT, NULL);
+
+ e_editor_dom_register_input_event_listener_on_body (editor_page);
+ e_editor_page_unblock_selection_changed (editor_page);
+
+ element = webkit_dom_document_query_selector (
+ document, "body>br", NULL);
+
+ webkit_dom_node_replace_child (
+ webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element)),
+ WEBKIT_DOM_NODE (list),
+ WEBKIT_DOM_NODE (element),
+ NULL);
+
+ block = e_editor_dom_get_parent_block_node_from_child (
+ WEBKIT_DOM_NODE (selection_start_marker));
+ } else
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (block),
+ WEBKIT_DOM_NODE (list),
+ block,
+ NULL);
+
+ /* Process all blocks that are in the selection one by one */
+ while (block && !after_selection_end) {
+ gboolean empty = FALSE, block_is_list;
+ gchar *content;
+ WebKitDOMNode *child, *parent;
+
+ after_selection_end = webkit_dom_node_contains (
+ block, WEBKIT_DOM_NODE (selection_end_marker));
+
+ next_block = webkit_dom_node_get_next_sibling (
+ WEBKIT_DOM_NODE (block));
+
+ e_editor_dom_remove_wrapping_from_element (WEBKIT_DOM_ELEMENT (block));
+ e_editor_dom_remove_quoting_from_element (WEBKIT_DOM_ELEMENT (block));
+
+ item = webkit_dom_document_create_element (document, "LI", NULL);
+ content = webkit_dom_node_get_text_content (block);
+
+ empty = !*content || (g_strcmp0 (content, UNICODE_ZERO_WIDTH_SPACE) == 0);
+ g_free (content);
+
+ change_leading_space_to_nbsp (block);
+ change_trailing_space_in_block_to_nbsp (block);
+
+ block_is_list = node_is_list_or_item (block);
+
+ while ((child = webkit_dom_node_get_first_child (block))) {
+ if (WEBKIT_DOM_IS_HTML_BR_ELEMENT (child))
+ empty = FALSE;
+
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (block_is_list ? list : item), child, NULL);
+ }
+
+ if (!block_is_list) {
+ /* We have to use again the hidden space to move caret into newly inserted list */
+ if (empty) {
+ WebKitDOMElement *br;
+
+ br = webkit_dom_document_create_element (
+ document, "BR", NULL);
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (item), WEBKIT_DOM_NODE (br), NULL);
+ }
+
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (list), WEBKIT_DOM_NODE (item), NULL);
+ }
+
+ parent = webkit_dom_node_get_parent_node (block);
+ remove_node (block);
+
+ if (in_quote) {
+ /* Remove all parents if previously removed node was the
+ * only one with text content */
+ content = webkit_dom_node_get_text_content (parent);
+ while (parent && content && !*content) {
+ WebKitDOMNode *tmp = webkit_dom_node_get_parent_node (parent);
+
+ remove_node (parent);
+ parent = tmp;
+
+ g_free (content);
+ content = webkit_dom_node_get_text_content (parent);
+ }
+ g_free (content);
+ }
+
+ block = next_block;
+ }
+
+ merge_lists_if_possible (WEBKIT_DOM_NODE (list));
+}
+
+static WebKitDOMElement *
+do_format_change_list_to_list (WebKitDOMElement *list_to_process,
+ WebKitDOMElement *new_list_template,
+ EContentEditorBlockFormat to)
+{
+ EContentEditorBlockFormat current_format;
+
+ current_format = dom_get_list_format_from_node (
+ WEBKIT_DOM_NODE (list_to_process));
+ if (to == current_format) {
+ /* Same format, skip it. */
+ return list_to_process;
+ } else if (current_format >= E_CONTENT_EDITOR_BLOCK_FORMAT_ORDERED_LIST &&
+ to >= E_CONTENT_EDITOR_BLOCK_FORMAT_ORDERED_LIST) {
+ /* Changing from ordered list type to another ordered list type. */
+ set_ordered_list_type_to_element (list_to_process, to);
+ return list_to_process;
+ } else {
+ WebKitDOMNode *clone, *child;
+
+ /* Create new list from template. */
+ clone = webkit_dom_node_clone_node_with_error (
+ WEBKIT_DOM_NODE (new_list_template), FALSE, NULL);
+
+ /* Insert it before the list that we are processing. */
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (
+ WEBKIT_DOM_NODE (list_to_process)),
+ clone,
+ WEBKIT_DOM_NODE (list_to_process),
+ NULL);
+
+ /* Move all it children to the new one. */
+ while ((child = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (list_to_process))))
+ webkit_dom_node_append_child (clone, child, NULL);
+
+ remove_node (WEBKIT_DOM_NODE (list_to_process));
+
+ return WEBKIT_DOM_ELEMENT (clone);
+ }
+
+ return NULL;
+}
+
+static void
+format_change_list_from_list (EEditorPage *editor_page,
+ EContentEditorBlockFormat to,
+ gboolean html_mode)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *selection_start_marker, *selection_end_marker, *new_list;
+ WebKitDOMNode *source_list, *source_list_clone, *current_list, *item;
+ gboolean after_selection_end = FALSE;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+ selection_start_marker = webkit_dom_document_query_selector (
+ document, "span#-x-evo-selection-start-marker", NULL);
+ selection_end_marker = webkit_dom_document_query_selector (
+ document, "span#-x-evo-selection-end-marker", NULL);
+
+ if (!selection_start_marker || !selection_end_marker)
+ return;
+
+ /* Copy elements from previous block to list */
+ item = get_list_item_node_from_child (WEBKIT_DOM_NODE (selection_start_marker));
+ source_list = webkit_dom_node_get_parent_node (item);
+ current_list = source_list;
+ source_list_clone = webkit_dom_node_clone_node_with_error (source_list, FALSE, NULL);
+
+ new_list = create_list_element (editor_page, to, 0, html_mode);
+
+ if (element_has_class (WEBKIT_DOM_ELEMENT (source_list), "-x-evo-indented"))
+ element_add_class (WEBKIT_DOM_ELEMENT (new_list), "-x-evo-indented");
+
+ while (item) {
+ gboolean selection_end;
+ WebKitDOMNode *next_item = webkit_dom_node_get_next_sibling (item);
+
+ selection_end = webkit_dom_node_contains (
+ item, WEBKIT_DOM_NODE (selection_end_marker));
+
+ if (WEBKIT_DOM_IS_HTML_LI_ELEMENT (item)) {
+ /* Actual node is an item, just copy it. */
+ webkit_dom_node_append_child (
+ after_selection_end ?
+ source_list_clone : WEBKIT_DOM_NODE (new_list),
+ item,
+ NULL);
+ } else if (node_is_list (item) && !selection_end && !after_selection_end) {
+ /* Node is a list and it doesn't contain the selection end
+ * marker, we can process the whole list. */
+ gint ii;
+ WebKitDOMNodeList *list = NULL;
+ WebKitDOMElement *processed_list;
+
+ list = webkit_dom_element_query_selector_all (
+ WEBKIT_DOM_ELEMENT (item), "ol,ul", NULL);
+ ii = webkit_dom_node_list_get_length (list);
+ g_clear_object (&list);
+
+ /* Process every sublist separately. */
+ while (ii) {
+ WebKitDOMElement *list_to_process;
+
+ list_to_process = webkit_dom_element_query_selector (
+ WEBKIT_DOM_ELEMENT (item), "ol,ul", NULL);
+ if (list_to_process)
+ do_format_change_list_to_list (list_to_process, new_list, to);
+ ii--;
+ }
+
+ /* Process the current list. */
+ processed_list = do_format_change_list_to_list (
+ WEBKIT_DOM_ELEMENT (item), new_list, to);
+
+ webkit_dom_node_append_child (
+ after_selection_end ?
+ source_list_clone : WEBKIT_DOM_NODE (new_list),
+ WEBKIT_DOM_NODE (processed_list),
+ NULL);
+ } else if (node_is_list (item) && !after_selection_end) {
+ /* Node is a list and it contains the selection end marker,
+ * thus we have to process it until we find the marker. */
+ gint ii;
+ WebKitDOMNodeList *list = NULL;
+
+ list = webkit_dom_element_query_selector_all (
+ WEBKIT_DOM_ELEMENT (item), "ol,ul", NULL);
+ ii = webkit_dom_node_list_get_length (list);
+ g_clear_object (&list);
+
+ /* No nested lists - process the items. */
+ if (ii == 0) {
+ WebKitDOMNode *clone, *child;
+
+ clone = webkit_dom_node_clone_node_with_error (
+ WEBKIT_DOM_NODE (new_list), FALSE, NULL);
+
+ webkit_dom_node_append_child (
+ after_selection_end ?
+ source_list_clone : WEBKIT_DOM_NODE (new_list),
+ clone,
+ NULL);
+
+ while ((child = webkit_dom_node_get_first_child (item))) {
+ webkit_dom_node_append_child (clone, child, NULL);
+ if (webkit_dom_node_contains (child, WEBKIT_DOM_NODE
(selection_end_marker)))
+ break;
+ }
+
+ if (webkit_dom_node_get_first_child (item))
+ webkit_dom_node_append_child (
+ after_selection_end ?
+ source_list_clone : WEBKIT_DOM_NODE (new_list),
+ item,
+ NULL);
+ else
+ remove_node (item);
+ } else {
+ gboolean done = FALSE;
+ WebKitDOMNode *tmp_parent = WEBKIT_DOM_NODE (new_list);
+ WebKitDOMNode *tmp_item = WEBKIT_DOM_NODE (item);
+
+ while (!done) {
+ WebKitDOMNode *clone, *child;
+
+ clone = webkit_dom_node_clone_node_with_error (
+ WEBKIT_DOM_NODE (new_list), FALSE, NULL);
+
+ webkit_dom_node_append_child (
+ tmp_parent, clone, NULL);
+
+ while ((child = webkit_dom_node_get_first_child (tmp_item))) {
+ if (!webkit_dom_node_contains (child, WEBKIT_DOM_NODE
(selection_end_marker))) {
+ webkit_dom_node_append_child (clone, child, NULL);
+ } else if (WEBKIT_DOM_IS_HTML_LI_ELEMENT (child)) {
+ webkit_dom_node_append_child (clone, child, NULL);
+ done = TRUE;
+ break;
+ } else {
+ tmp_parent = clone;
+ tmp_item = child;
+ break;
+ }
+ }
+ }
+ }
+ } else {
+ webkit_dom_node_append_child (
+ after_selection_end ?
+ source_list_clone : WEBKIT_DOM_NODE (new_list),
+ item,
+ NULL);
+ }
+
+ if (selection_end) {
+ source_list_clone = webkit_dom_node_clone_node_with_error (current_list, FALSE, NULL);
+ remove_node_if_empty (current_list);
+ after_selection_end = TRUE;
+ }
+
+ if (!next_item) {
+ if (after_selection_end)
+ break;
+
+ current_list = webkit_dom_node_get_next_sibling (current_list);
+ if (!node_is_list_or_item (current_list))
+ break;
+ if (node_is_list (current_list)) {
+ next_item = webkit_dom_node_get_first_child (current_list);
+ if (!node_is_list_or_item (next_item))
+ break;
+ } else if (WEBKIT_DOM_IS_HTML_LI_ELEMENT (current_list)) {
+ next_item = current_list;
+ current_list = webkit_dom_node_get_parent_node (next_item);
+ }
+ }
+
+ item = next_item;
+ }
+
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (source_list),
+ WEBKIT_DOM_NODE (source_list_clone),
+ webkit_dom_node_get_next_sibling (source_list),
+ NULL);
+
+ if (webkit_dom_node_has_child_nodes (WEBKIT_DOM_NODE (new_list)))
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (source_list_clone),
+ WEBKIT_DOM_NODE (new_list),
+ source_list_clone,
+ NULL);
+
+ remove_node_if_empty (source_list);
+
+ remove_node_if_empty (source_list_clone);
+
+ merge_lists_if_possible (WEBKIT_DOM_NODE (new_list));
+}
+
+static void
+format_change_list_to_list (EEditorPage *editor_page,
+ EContentEditorBlockFormat format,
+ gboolean html_mode)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *selection_start_marker, *selection_end_marker;
+ WebKitDOMNode *prev_list, *current_list, *next_list;
+ EContentEditorBlockFormat prev = 0, next = 0;
+ gboolean done = FALSE, indented = FALSE;
+ gboolean selection_starts_in_first_child, selection_ends_in_last_child;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+ selection_start_marker = webkit_dom_document_query_selector (
+ document, "span#-x-evo-selection-start-marker", NULL);
+ selection_end_marker = webkit_dom_document_query_selector (
+ document, "span#-x-evo-selection-end-marker", NULL);
+
+ current_list = get_list_node_from_child (
+ WEBKIT_DOM_NODE (selection_start_marker));
+
+ prev_list = get_list_node_from_child (
+ WEBKIT_DOM_NODE (selection_start_marker));
+
+ next_list = get_list_node_from_child (
+ WEBKIT_DOM_NODE (selection_end_marker));
+
+ selection_starts_in_first_child =
+ webkit_dom_node_contains (
+ webkit_dom_node_get_first_child (current_list),
+ WEBKIT_DOM_NODE (selection_start_marker));
+
+ selection_ends_in_last_child =
+ webkit_dom_node_contains (
+ webkit_dom_node_get_last_child (current_list),
+ WEBKIT_DOM_NODE (selection_end_marker));
+
+ indented = element_has_class (WEBKIT_DOM_ELEMENT (current_list), "-x-evo-indented");
+
+ if (!prev_list || !next_list || indented) {
+ format_change_list_from_list (editor_page, format, html_mode);
+ return;
+ }
+
+ if (webkit_dom_node_is_same_node (prev_list, next_list)) {
+ prev_list = webkit_dom_node_get_previous_sibling (
+ webkit_dom_node_get_parent_node (
+ webkit_dom_node_get_parent_node (
+ WEBKIT_DOM_NODE (selection_start_marker))));
+ next_list = webkit_dom_node_get_next_sibling (
+ webkit_dom_node_get_parent_node (
+ webkit_dom_node_get_parent_node (
+ WEBKIT_DOM_NODE (selection_end_marker))));
+ if (!prev_list || !next_list) {
+ format_change_list_from_list (editor_page, format, html_mode);
+ return;
+ }
+ }
+
+ prev = dom_get_list_format_from_node (prev_list);
+ next = dom_get_list_format_from_node (next_list);
+
+ if (format != E_CONTENT_EDITOR_BLOCK_FORMAT_NONE) {
+ if (format == prev && prev != E_CONTENT_EDITOR_BLOCK_FORMAT_NONE) {
+ if (selection_starts_in_first_child && selection_ends_in_last_child) {
+ done = TRUE;
+ merge_list_into_list (current_list, prev_list, FALSE);
+ }
+ }
+ if (format == next && next != E_CONTENT_EDITOR_BLOCK_FORMAT_NONE) {
+ if (selection_starts_in_first_child && selection_ends_in_last_child) {
+ done = TRUE;
+ merge_list_into_list (next_list, prev_list, FALSE);
+ }
+ }
+ }
+
+ if (done)
+ return;
+
+ format_change_list_from_list (editor_page, format, html_mode);
+}
+
+/*
+ * e_html_editor_selection_set_block_format:
+ * @selection: an #EEditorSelection
+ * @format: an #EContentEditorBlockFormat value
+ *
+ * Changes block format of current paragraph to @format.
+ */
+void
+e_editor_dom_selection_set_block_format (EEditorPage *editor_page,
+ EContentEditorBlockFormat format)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMRange *range = NULL;
+ EContentEditorBlockFormat current_format;
+ EContentEditorAlignment current_alignment;
+ EEditorUndoRedoManager *manager;
+ EEditorHistoryEvent *ev = NULL;
+ const gchar *value;
+ gboolean from_list = FALSE, to_list = FALSE, html_mode = FALSE;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+ current_format = e_editor_dom_selection_get_block_format (editor_page);
+ if (current_format == format)
+ return;
+
+ switch (format) {
+ case E_CONTENT_EDITOR_BLOCK_FORMAT_H1:
+ value = "H1";
+ break;
+ case E_CONTENT_EDITOR_BLOCK_FORMAT_H2:
+ value = "H2";
+ break;
+ case E_CONTENT_EDITOR_BLOCK_FORMAT_H3:
+ value = "H3";
+ break;
+ case E_CONTENT_EDITOR_BLOCK_FORMAT_H4:
+ value = "H4";
+ break;
+ case E_CONTENT_EDITOR_BLOCK_FORMAT_H5:
+ value = "H5";
+ break;
+ case E_CONTENT_EDITOR_BLOCK_FORMAT_H6:
+ value = "H6";
+ break;
+ case E_CONTENT_EDITOR_BLOCK_FORMAT_PARAGRAPH:
+ value = "P";
+ break;
+ case E_CONTENT_EDITOR_BLOCK_FORMAT_PRE:
+ value = "PRE";
+ break;
+ case E_CONTENT_EDITOR_BLOCK_FORMAT_ADDRESS:
+ value = "ADDRESS";
+ break;
+ case E_CONTENT_EDITOR_BLOCK_FORMAT_ORDERED_LIST:
+ case E_CONTENT_EDITOR_BLOCK_FORMAT_ORDERED_LIST_ALPHA:
+ case E_CONTENT_EDITOR_BLOCK_FORMAT_ORDERED_LIST_ROMAN:
+ to_list = TRUE;
+ value = NULL;
+ break;
+ case E_CONTENT_EDITOR_BLOCK_FORMAT_UNORDERED_LIST:
+ to_list = TRUE;
+ value = NULL;
+ break;
+ case E_CONTENT_EDITOR_BLOCK_FORMAT_NONE:
+ default:
+ value = NULL;
+ break;
+ }
+
+ html_mode = e_editor_page_get_html_mode (editor_page);
+
+ from_list =
+ current_format >= E_CONTENT_EDITOR_BLOCK_FORMAT_UNORDERED_LIST;
+
+ range = e_editor_dom_get_current_range (editor_page);
+ if (!range)
+ return;
+
+ current_alignment = e_editor_page_get_alignment (editor_page);
+
+ e_editor_dom_selection_save (editor_page);
+
+ manager = e_editor_page_get_undo_redo_manager (editor_page);
+ if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+ ev = g_new0 (EEditorHistoryEvent, 1);
+ ev->type = HISTORY_BLOCK_FORMAT;
+
+ e_editor_dom_selection_get_coordinates (editor_page,
+ &ev->before.start.x,
+ &ev->before.start.y,
+ &ev->before.end.x,
+ &ev->before.end.y);
+
+ ev->data.style.from = current_format;
+ ev->data.style.to = format;
+ }
+
+ g_clear_object (&range);
+
+ if (current_format == E_CONTENT_EDITOR_BLOCK_FORMAT_PRE) {
+ WebKitDOMElement *selection_marker;
+
+ selection_marker = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-start-marker");
+ if (selection_marker)
+ change_space_before_selection_to_nbsp (WEBKIT_DOM_NODE (selection_marker));
+ selection_marker = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-end-marker");
+ if (selection_marker)
+ change_space_before_selection_to_nbsp (WEBKIT_DOM_NODE (selection_marker));
+ }
+
+ if (from_list && to_list)
+ format_change_list_to_list (editor_page, format, html_mode);
+
+ if (!from_list && !to_list)
+ format_change_block_to_block (editor_page, format, value);
+
+ if (from_list && !to_list)
+ format_change_list_to_block (editor_page, format, value);
+
+ if (!from_list && to_list)
+ format_change_block_to_list (editor_page, format);
+
+ e_editor_dom_selection_restore (editor_page);
+
+ e_editor_dom_force_spell_check_for_current_paragraph (editor_page);
+
+ /* When changing the format we need to re-set the alignment */
+ e_editor_dom_selection_set_alignment (editor_page, current_alignment);
+
+ e_editor_page_emit_content_changed (editor_page);
+
+ if (ev) {
+ e_editor_dom_selection_get_coordinates (editor_page,
+ &ev->after.start.x,
+ &ev->after.start.y,
+ &ev->after.end.x,
+ &ev->after.end.y);
+ e_editor_undo_redo_manager_insert_history_event (manager, ev);
+ }
+}
+
+/*
+ * e_html_editor_selection_get_background_color:
+ * @selection: an #EEditorSelection
+ *
+ * Returns background color of currently selected text or letter at current
+ * cursor position.
+ *
+ * Returns: A string with code of current background color.
+ */
+gchar *
+e_editor_dom_selection_get_background_color (EEditorPage *editor_page)
+{
+ WebKitDOMNode *ancestor;
+ WebKitDOMRange *range = NULL;
+ WebKitDOMCSSStyleDeclaration *css = NULL;
+ gchar *value;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+ range = e_editor_dom_get_current_range (editor_page);
+ ancestor = webkit_dom_range_get_common_ancestor_container (range, NULL);
+ css = webkit_dom_element_get_style (WEBKIT_DOM_ELEMENT (ancestor));
+/* FIXME WK2
+ g_free (selection->priv->background_color);
+ selection->priv->background_color =
+ webkit_dom_css_style_declaration_get_property_value (
+ css, "background-color");*/
+
+ value = webkit_dom_css_style_declaration_get_property_value (css, "background-color");
+
+ g_clear_object (&css);
+ g_clear_object (&range);
+
+ return value;
+}
+
+/*
+ * e_html_editor_selection_set_background_color:
+ * @selection: an #EEditorSelection
+ * @color: code of new background color to set
+ *
+ * Changes background color of current selection or letter at current cursor
+ * position to @color.
+ */
+void
+e_editor_dom_selection_set_background_color (EEditorPage *editor_page,
+ const gchar *color)
+{
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ e_editor_dom_exec_command (editor_page, E_CONTENT_EDITOR_COMMAND_BACKGROUND_COLOR, color);
+}
+
+/*
+ * e_html_editor_selection_get_alignment:
+ * @selection: #an EEditorSelection
+ *
+ * Returns alignment of current paragraph
+ *
+ * Returns: #EContentEditorAlignment
+ */
+EContentEditorAlignment
+e_editor_dom_selection_get_alignment (EEditorPage *editor_page)
+{
+ WebKitDOMCSSStyleDeclaration *style = NULL;
+ WebKitDOMElement *element;
+ WebKitDOMNode *node;
+ WebKitDOMRange *range = NULL;
+ EContentEditorAlignment alignment;
+ gchar *value;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), E_CONTENT_EDITOR_ALIGNMENT_LEFT);
+
+ range = e_editor_dom_get_current_range (editor_page);
+ if (!range) {
+ alignment = E_CONTENT_EDITOR_ALIGNMENT_LEFT;
+ goto out;
+ }
+
+ node = webkit_dom_range_get_start_container (range, NULL);
+ g_clear_object (&range);
+ if (!node) {
+ alignment = E_CONTENT_EDITOR_ALIGNMENT_LEFT;
+ goto out;
+ }
+
+ if (WEBKIT_DOM_IS_ELEMENT (node))
+ element = WEBKIT_DOM_ELEMENT (node);
+ else
+ element = webkit_dom_node_get_parent_element (node);
+
+ if (element_has_class (element, "-x-evo-align-right")) {
+ alignment = E_CONTENT_EDITOR_ALIGNMENT_RIGHT;
+ goto out;
+ } else if (element_has_class (element, "-x-evo-align-center")) {
+ alignment = E_CONTENT_EDITOR_ALIGNMENT_CENTER;
+ goto out;
+ }
+
+ style = webkit_dom_element_get_style (element);
+ value = webkit_dom_css_style_declaration_get_property_value (style, "text-align");
+
+ if (!value || !*value ||
+ (g_ascii_strncasecmp (value, "left", 4) == 0)) {
+ alignment = E_CONTENT_EDITOR_ALIGNMENT_LEFT;
+ } else if (g_ascii_strncasecmp (value, "center", 6) == 0) {
+ alignment = E_CONTENT_EDITOR_ALIGNMENT_CENTER;
+ } else if (g_ascii_strncasecmp (value, "right", 5) == 0) {
+ alignment = E_CONTENT_EDITOR_ALIGNMENT_RIGHT;
+ } else {
+ alignment = E_CONTENT_EDITOR_ALIGNMENT_LEFT;
+ }
+
+ g_clear_object (&style);
+ g_free (value);
+
+ out:
+ return alignment;
+}
+
+static void
+set_block_alignment (WebKitDOMElement *element,
+ const gchar *class)
+{
+ WebKitDOMElement *parent;
+
+ element_remove_class (element, "-x-evo-align-center");
+ element_remove_class (element, "-x-evo-align-right");
+ element_add_class (element, class);
+ parent = webkit_dom_node_get_parent_element (WEBKIT_DOM_NODE (element));
+ while (parent && !WEBKIT_DOM_IS_HTML_BODY_ELEMENT (parent)) {
+ element_remove_class (parent, "-x-evo-align-center");
+ element_remove_class (parent, "-x-evo-align-right");
+ parent = webkit_dom_node_get_parent_element (
+ WEBKIT_DOM_NODE (parent));
+ }
+}
+
+/*
+ * e_html_editor_selection_set_alignment:
+ * @selection: an #EEditorSelection
+ * @alignment: an #EContentEditorAlignment value to apply
+ *
+ * Sets alignment of current paragraph to give @alignment.
+ */
+void
+e_editor_dom_selection_set_alignment (EEditorPage *editor_page,
+ EContentEditorAlignment alignment)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *selection_start_marker, *selection_end_marker;
+ WebKitDOMNode *block;
+ EContentEditorAlignment current_alignment;
+ EEditorUndoRedoManager *manager;
+ EEditorHistoryEvent *ev = NULL;
+ gboolean after_selection_end = FALSE;
+ const gchar *class = "";
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+ current_alignment = e_editor_page_get_alignment (editor_page);
+
+ if (current_alignment == alignment)
+ return;
+
+ switch (alignment) {
+ case E_CONTENT_EDITOR_ALIGNMENT_CENTER:
+ class = "-x-evo-align-center";
+ break;
+
+ case E_CONTENT_EDITOR_ALIGNMENT_LEFT:
+ break;
+
+ case E_CONTENT_EDITOR_ALIGNMENT_RIGHT:
+ class = "-x-evo-align-right";
+ break;
+ }
+
+ e_editor_dom_selection_save (editor_page);
+
+ selection_start_marker = webkit_dom_document_query_selector (
+ document, "span#-x-evo-selection-start-marker", NULL);
+ selection_end_marker = webkit_dom_document_query_selector (
+ document, "span#-x-evo-selection-end-marker", NULL);
+
+ if (!selection_start_marker)
+ return;
+
+ manager = e_editor_page_get_undo_redo_manager (editor_page);
+ if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+ ev = g_new0 (EEditorHistoryEvent, 1);
+ ev->type = HISTORY_ALIGNMENT;
+
+ e_editor_dom_selection_get_coordinates (editor_page,
+ &ev->before.start.x,
+ &ev->before.start.y,
+ &ev->before.end.x,
+ &ev->before.end.y);
+ ev->data.style.from = current_alignment;
+ ev->data.style.to = alignment;
+ }
+
+ block = e_editor_dom_get_parent_block_node_from_child (
+ WEBKIT_DOM_NODE (selection_start_marker));
+
+ while (block && !after_selection_end) {
+ WebKitDOMNode *next_block;
+
+ next_block = webkit_dom_node_get_next_sibling (block);
+
+ after_selection_end = webkit_dom_node_contains (
+ block, WEBKIT_DOM_NODE (selection_end_marker));
+
+ if (element_has_class (WEBKIT_DOM_ELEMENT (block), "-x-evo-indented")) {
+ gint ii, length;
+ WebKitDOMNodeList *list = NULL;
+
+ list = webkit_dom_element_query_selector_all (
+ WEBKIT_DOM_ELEMENT (block),
+ ".-x-evo-indented > *:not(.-x-evo-indented):not(li)",
+ NULL);
+ length = webkit_dom_node_list_get_length (list);
+
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMNode *item = webkit_dom_node_list_item (list, ii);
+
+ set_block_alignment (WEBKIT_DOM_ELEMENT (item), class);
+
+ after_selection_end = webkit_dom_node_contains (
+ item, WEBKIT_DOM_NODE (selection_end_marker));
+ g_object_unref (item);
+ if (after_selection_end)
+ break;
+ }
+
+ g_clear_object (&list);
+ } else {
+ set_block_alignment (WEBKIT_DOM_ELEMENT (block), class);
+ }
+
+ block = next_block;
+ }
+
+ if (ev) {
+ e_editor_dom_selection_get_coordinates (editor_page,
+ &ev->after.start.x,
+ &ev->after.start.y,
+ &ev->after.end.x,
+ &ev->after.end.y);
+ e_editor_undo_redo_manager_insert_history_event (manager, ev);
+ }
+
+ e_editor_dom_selection_restore (editor_page);
+
+ e_editor_dom_force_spell_check_for_current_paragraph (editor_page);
+}
+
+/*
+ * e_html_editor_selection_replace:
+ * @selection: an #EEditorSelection
+ * @replacement: a string to replace current selection with
+ *
+ * Replaces currently selected text with @replacement.
+ */
+void
+e_editor_dom_selection_replace (EEditorPage *editor_page,
+ const gchar *replacement)
+{
+ EEditorHistoryEvent *ev = NULL;
+ EEditorUndoRedoManager *manager;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ manager = e_editor_page_get_undo_redo_manager (editor_page);
+
+ if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+ WebKitDOMRange *range = NULL;
+
+ ev = g_new0 (EEditorHistoryEvent, 1);
+ ev->type = HISTORY_REPLACE;
+
+ e_editor_dom_selection_get_coordinates (editor_page,
+ &ev->before.start.x,
+ &ev->before.start.y,
+ &ev->before.end.x,
+ &ev->before.end.y);
+
+ range = e_editor_dom_get_current_range (editor_page);
+
+ ev->data.string.from = webkit_dom_range_get_text (range);
+ ev->data.string.to = g_strdup (replacement);
+
+ g_clear_object (&range);
+ }
+
+ e_editor_dom_exec_command (editor_page, E_CONTENT_EDITOR_COMMAND_INSERT_TEXT, replacement);
+
+ if (ev) {
+ e_editor_dom_selection_get_coordinates (editor_page,
+ &ev->after.start.x,
+ &ev->after.start.y,
+ &ev->after.end.x,
+ &ev->after.end.y);
+
+ e_editor_undo_redo_manager_insert_history_event (manager, ev);
+ }
+
+ e_editor_dom_force_spell_check_for_current_paragraph (editor_page);
+
+ e_editor_page_emit_content_changed (editor_page);
+}
+
+/*
+ * e_html_editor_selection_replace_caret_word:
+ * @selection: an #EEditorSelection
+ * @replacement: a string to replace current caret word with
+ *
+ * Replaces current word under cursor with @replacement.
+ */
+void
+e_editor_dom_replace_caret_word (EEditorPage *editor_page,
+ const gchar *replacement)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMDOMWindow *dom_window = NULL;
+ WebKitDOMDOMSelection *dom_selection = NULL;
+ WebKitDOMDocumentFragment *fragment;
+ WebKitDOMNode *node;
+ WebKitDOMRange *range = NULL;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+ dom_window = webkit_dom_document_get_default_view (document);
+ dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+ g_clear_object (&dom_window);
+
+ e_editor_page_emit_content_changed (editor_page);
+ range = e_editor_dom_get_current_range (editor_page);
+ webkit_dom_range_expand (range, "word", NULL);
+ webkit_dom_dom_selection_add_range (dom_selection, range);
+
+ fragment = webkit_dom_range_extract_contents (range, NULL);
+
+ /* Get the text node to replace and leave other formatting nodes
+ * untouched (font color, boldness, ...). */
+ webkit_dom_node_normalize (WEBKIT_DOM_NODE (fragment));
+ node = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (fragment));
+ if (!WEBKIT_DOM_IS_TEXT (node)) {
+ while (node && WEBKIT_DOM_IS_ELEMENT (node))
+ node = webkit_dom_node_get_first_child (node);
+ }
+
+ if (node && WEBKIT_DOM_IS_TEXT (node)) {
+ WebKitDOMText *text;
+
+ /* Replace the word */
+ text = webkit_dom_document_create_text_node (document, replacement);
+ webkit_dom_node_replace_child (
+ webkit_dom_node_get_parent_node (node),
+ WEBKIT_DOM_NODE (text),
+ node,
+ NULL);
+
+ /* Insert the word on current location. */
+ webkit_dom_range_insert_node (range, WEBKIT_DOM_NODE (fragment), NULL);
+
+ webkit_dom_dom_selection_collapse_to_end (dom_selection, NULL);
+ }
+
+ e_editor_dom_force_spell_check_for_current_paragraph (editor_page);
+
+ g_clear_object (&range);
+ g_clear_object (&dom_selection);
+}
+
+/*
+ * e_html_editor_selection_get_caret_word:
+ * @selection: an #EEditorSelection
+ *
+ * Returns word under cursor.
+ *
+ * Returns: A newly allocated string with current caret word or @NULL when there
+ * is no text under cursor or when selection is active. [transfer-full].
+ */
+gchar *
+e_editor_dom_get_caret_word (EEditorPage *editor_page)
+{
+ gchar *word;
+ WebKitDOMRange *range = NULL, *range_clone = NULL;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+ range = e_editor_dom_get_current_range (editor_page);
+
+ /* Don't operate on the visible selection */
+ range_clone = webkit_dom_range_clone_range (range, NULL);
+ webkit_dom_range_expand (range_clone, "word", NULL);
+ word = webkit_dom_range_to_string (range_clone, NULL);
+
+ g_clear_object (&range);
+ g_clear_object (&range_clone);
+
+ return word;
+}
+
+/*
+ * e_html_editor_selection_get_list_alignment_from_node:
+ * @node: #an WebKitDOMNode
+ *
+ * Returns alignment of given list.
+ *
+ * Returns: #EContentEditorAlignment
+ */
+EContentEditorAlignment
+e_editor_dom_get_list_alignment_from_node (WebKitDOMNode *node)
+{
+ if (element_has_class (WEBKIT_DOM_ELEMENT (node), "-x-evo-align-center"))
+ return E_CONTENT_EDITOR_ALIGNMENT_CENTER;
+ if (element_has_class (WEBKIT_DOM_ELEMENT (node), "-x-evo-align-right"))
+ return E_CONTENT_EDITOR_ALIGNMENT_RIGHT;
+ else
+ return E_CONTENT_EDITOR_ALIGNMENT_LEFT;
+}
+
+WebKitDOMElement *
+e_editor_dom_prepare_paragraph (EEditorPage *editor_page,
+ gboolean with_selection)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *element, *paragraph;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+ document = e_editor_page_get_document (editor_page);
+ paragraph = e_editor_dom_get_paragraph_element (editor_page, -1, 0);
+
+ if (with_selection)
+ dom_add_selection_markers_into_element_start (
+ document, paragraph, NULL, NULL);
+
+ element = webkit_dom_document_create_element (document, "BR", NULL);
+
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (paragraph), WEBKIT_DOM_NODE (element), NULL);
+
+ return paragraph;
+}
+
+void
+e_editor_dom_selection_set_on_point (EEditorPage *editor_page,
+ guint x,
+ guint y)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMRange *range = NULL;
+ WebKitDOMDOMWindow *dom_window = NULL;
+ WebKitDOMDOMSelection *dom_selection = NULL;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+ dom_window = webkit_dom_document_get_default_view (document);
+ dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+
+ range = webkit_dom_document_caret_range_from_point (document, x, y);
+ webkit_dom_dom_selection_remove_all_ranges (dom_selection);
+ webkit_dom_dom_selection_add_range (dom_selection, range);
+
+ g_clear_object (&range);
+ g_clear_object (&dom_selection);
+ g_clear_object (&dom_window);
+}
+
+void
+e_editor_dom_selection_get_coordinates (EEditorPage *editor_page,
+ guint *start_x,
+ guint *start_y,
+ guint *end_x,
+ guint *end_y)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *element, *parent;
+ gboolean created_selection_markers = FALSE;
+ guint local_x = 0, local_y = 0;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+ g_return_if_fail (start_x != NULL);
+ g_return_if_fail (start_y != NULL);
+ g_return_if_fail (end_x != NULL);
+ g_return_if_fail (end_y != NULL);
+
+ document = e_editor_page_get_document (editor_page);
+ element = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-start-marker");
+ if (!element) {
+ created_selection_markers = TRUE;
+ e_editor_dom_selection_save (editor_page);
+ element = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-start-marker");
+ if (!element)
+ return;
+ }
+
+ parent = element;
+ while (parent && !WEBKIT_DOM_IS_HTML_BODY_ELEMENT (parent)) {
+ local_x += (guint) webkit_dom_element_get_offset_left (parent);
+ local_y += (guint) webkit_dom_element_get_offset_top (parent);
+ parent = webkit_dom_element_get_offset_parent (parent);
+ }
+
+ if (start_x)
+ *start_x = local_x;
+ if (start_y)
+ *start_y = local_y;
+
+ if (e_editor_dom_selection_is_collapsed (editor_page)) {
+ *end_x = local_x;
+ *end_y = local_y;
+
+ if (created_selection_markers)
+ e_editor_dom_selection_restore (editor_page);
+
+ goto workaroud;
+ }
+
+ element = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-end-marker");
+
+ local_x = 0;
+ local_y = 0;
+
+ parent = element;
+ while (parent && !WEBKIT_DOM_IS_HTML_BODY_ELEMENT (parent)) {
+ local_x += (guint) webkit_dom_element_get_offset_left (parent);
+ local_y += (guint) webkit_dom_element_get_offset_top (parent);
+ parent = webkit_dom_element_get_offset_parent (parent);
+ }
+
+ if (end_x)
+ *end_x = local_x;
+ if (end_y)
+ *end_y = local_y;
+
+ if (created_selection_markers)
+ e_editor_dom_selection_restore (editor_page);
+
+ workaroud:
+ /* Workaround for bug 749712 on the Evolution side. The cause of the bug
+ * is that WebKit is having problems determining the right line height
+ * for some fonts and font sizes (the right and wrong value differ by 1).
+ * To fix this we will add an extra one to the final top offset. This is
+ * safe to do even for fonts and font sizes that don't behave badly as we
+ * will still get the right element as we use fonts bigger than 1 pixel. */
+ *start_y += 1;
+ *end_y += 1;
+}
diff --git a/modules/webkit-editor/web-extension/e-editor-dom-functions.h
b/modules/webkit-editor/web-extension/e-editor-dom-functions.h
new file mode 100644
index 0000000..747dd11
--- /dev/null
+++ b/modules/webkit-editor/web-extension/e-editor-dom-functions.h
@@ -0,0 +1,378 @@
+/*
+ * Copyright (C) 2016 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library 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.
+ *
+ * This library 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 this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef E_EDITOR_DOM_FUNCTIONS_H
+#define E_EDITOR_DOM_FUNCTIONS_H
+
+#include <webkitdom/webkitdom.h>
+
+#define E_UTIL_INCLUDE_WITHOUT_WEBKIT
+#include <e-util/e-util.h>
+#undef E_UTIL_INCLUDE_WITHOUT_WEBKIT
+
+#include "e-editor-page.h"
+
+#define UNICODE_ZERO_WIDTH_SPACE "\xe2\x80\x8b"
+#define UNICODE_NBSP "\xc2\xa0"
+
+/* stephenhay from https://mathiasbynens.be/demo/url-regex */
+#define URL_PROTOCOLS "news|telnet|nntp|file|https?|s?ftp|webcal|localhost|ssh"
+#define URL_PATTERN_BASE "(?=((?:(?:(?:" URL_PROTOCOLS
")\\:\\/\\/)|(?:www\\.|ftp\\.))[^\\s\\/\\$\\.\\?#].[^\\s]*)"
+#define URL_PATTERN_NO_NBSP ")((?:(?! ).)*)"
+#define URL_PATTERN URL_PATTERN_BASE URL_PATTERN_NO_NBSP
+#define URL_PATTERN_SPACE URL_PATTERN_BASE "\\s$" URL_PATTERN_NO_NBSP
+/* Taken from camel-url-scanner.c */
+#define URL_INVALID_TRAILING_CHARS ",.:;?!-|}])\""
+
+/* http://www.w3.org/TR/html5/forms.html#valid-e-mail-address */
+#define E_MAIL_PATTERN \
+ "[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}"\
+ "[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*"
+
+#define E_MAIL_PATTERN_SPACE E_MAIL_PATTERN "\\s"
+
+#define QUOTE_SYMBOL ">"
+
+#define SPACES_PER_INDENTATION 3
+#define SPACES_PER_LIST_LEVEL 3
+#define SPACES_ORDERED_LIST_FIRST_LEVEL 6
+#define TAB_LENGTH 8
+#define MINIMAL_PARAGRAPH_WIDTH 5
+
+G_BEGIN_DECLS
+
+/* ******************** Tests ******************** */
+
+gboolean e_editor_dom_test_html_equal (WebKitDOMDocument *document,
+ const gchar *html1,
+ const gchar *html2);
+
+/* ******************** Actions ******************** */
+
+void e_editor_dom_delete_cell_contents
+ (EEditorPage *editor_page);
+void e_editor_dom_delete_column (EEditorPage *editor_page);
+void e_editor_dom_delete_row (EEditorPage *editor_page);
+void e_editor_dom_delete_table (EEditorPage *editor_page);
+void e_editor_dom_insert_column_after
+ (EEditorPage *editor_page);
+void e_editor_dom_insert_column_before
+ (EEditorPage *editor_page);
+void e_editor_dom_insert_row_above (EEditorPage *editor_page);
+void e_editor_dom_insert_row_below (EEditorPage *editor_page);
+void e_editor_dom_save_history_for_cut
+ (EEditorPage *editor_page);
+
+/* ******************** View ******************** */
+
+gboolean e_editor_dom_exec_command (EEditorPage *editor_page,
+ EContentEditorCommand command,
+ const gchar *value);
+void e_editor_dom_force_spell_check_for_current_paragraph
+ (EEditorPage *editor_page);
+void e_editor_dom_force_spell_check_in_viewport
+ (EEditorPage *editor_page);
+void e_editor_dom_force_spell_check (EEditorPage *editor_page);
+void e_editor_dom_turn_spell_check_off
+ (EEditorPage *editor_page);
+void e_editor_dom_embed_style_sheet (EEditorPage *editor_page,
+ const gchar *style_sheet_content);
+void e_editor_dom_remove_embedded_style_sheet
+ (EEditorPage *editor_page);
+void e_editor_dom_register_input_event_listener_on_body
+ (EEditorPage *editor_page);
+void e_editor_dom_remove_input_event_listener_from_body
+ (EEditorPage *editor_page);
+void e_editor_dom_quote_and_insert_text_into_selection
+ (EEditorPage *editor_page,
+ const gchar *text,
+ gboolean is_html);
+void e_editor_dom_check_magic_links (EEditorPage *editor_page,
+ gboolean include_space_by_user);
+void e_editor_dom_insert_smiley (EEditorPage *editor_page,
+ EEmoticon *emoticon);
+void e_editor_dom_insert_smiley_by_name
+ (EEditorPage *editor_page,
+ const gchar *name);
+void e_editor_dom_check_magic_smileys
+ (EEditorPage *editor_page);
+void e_editor_dom_set_monospace_font_family_on_body
+ (WebKitDOMElement *body,
+ gboolean html_mode);
+void e_editor_dom_convert_content (EEditorPage *editor_page,
+ const gchar *preferred_text);
+void e_editor_dom_convert_and_insert_html_into_selection
+ (EEditorPage *editor_page,
+ const gchar *html,
+ gboolean is_html);
+gboolean e_editor_dom_node_is_citation_node
+ (WebKitDOMNode *node);
+void e_editor_dom_quote_plain_text_element_after_wrapping
+ (EEditorPage *editor_page,
+ WebKitDOMElement *element,
+ gint quote_level);
+WebKitDOMNode * e_editor_dom_get_parent_block_node_from_child
+ (WebKitDOMNode *node);
+WebKitDOMElement *
+ e_editor_dom_insert_new_line_into_citation
+ (EEditorPage *editor_page,
+ const gchar *html_to_insert);
+WebKitDOMElement *
+ e_editor_dom_quote_plain_text_element
+ (EEditorPage *editor_page,
+ WebKitDOMElement *element);
+void e_editor_dom_convert_when_changing_composer_mode
+ (EEditorPage *editor_page);
+void e_editor_dom_process_content_after_load
+ (EEditorPage *editor_page);
+GVariant * e_editor_dom_get_inline_images_data
+ (EEditorPage *editor_page,
+ const gchar *uid_domain);
+void e_editor_dom_insert_html (EEditorPage *editor_page,
+ const gchar *html_text);
+void e_editor_dom_convert_element_from_html_to_plain_text
+ (EEditorPage *editor_page,
+ WebKitDOMElement *element);
+gchar * e_editor_dom_process_content_for_draft
+ (EEditorPage *editor_page,
+ gboolean only_inner_body);
+gchar * e_editor_dom_process_content_to_plain_text_for_exporting
+ (EEditorPage *editor_page);
+void e_editor_dom_restore_images (EEditorPage *editor_page,
+ GVariant *inline_images_to_restore);
+gchar * e_editor_dom_process_content_to_html_for_exporting
+ (EEditorPage *editor_page);
+gboolean e_editor_dom_check_if_conversion_needed
+ (EEditorPage *editor_page);
+void e_editor_dom_process_content_after_mode_change
+ (EEditorPage *editor_page);
+guint e_editor_dom_get_caret_offset (EEditorPage *editor_page);
+guint e_editor_dom_get_caret_position (EEditorPage *editor_page);
+void e_editor_dom_drag_and_drop_end (EEditorPage *editor_page);
+void e_editor_dom_set_link_color (EEditorPage *editor_page,
+ const gchar *color);
+void e_editor_dom_set_visited_link_color
+ (EEditorPage *editor_page,
+ const gchar *color);
+gboolean e_editor_dom_move_quoted_block_level_up
+ (EEditorPage *editor_page);
+gboolean e_editor_dom_delete_last_character_on_line_in_quoted_block
+ (EEditorPage *editor_page,
+ glong key_code,
+ gboolean control_key);
+gboolean e_editor_dom_fix_structure_after_delete_before_quoted_content
+ (EEditorPage *editor_page,
+ glong key_code,
+ gboolean control_key,
+ gboolean delete_key);
+void e_editor_dom_disable_quote_marks_select
+ (EEditorPage *editor_page);
+void e_editor_dom_remove_node_and_parents_if_empty
+ (WebKitDOMNode *node);
+gboolean e_editor_dom_return_pressed_in_empty_list_item
+ (EEditorPage *editor_page);
+void e_editor_dom_merge_siblings_if_necessary
+ (EEditorPage *editor_page,
+ WebKitDOMDocumentFragment *deleted_content);
+void e_editor_dom_body_key_up_event_process_return_key
+ (EEditorPage *editor_page);
+gboolean e_editor_dom_key_press_event_process_backspace_key
+ (EEditorPage *editor_page);
+gboolean e_editor_dom_key_press_event_process_delete_or_backspace_key
+ (EEditorPage *editor_page,
+ glong key_code,
+ gboolean control_key,
+ gboolean delete);
+void e_editor_dom_body_input_event_process
+ (EEditorPage *editor_page,
+ WebKitDOMEvent *event);
+void e_editor_dom_body_key_up_event_process_backspace_or_delete
+ (EEditorPage *editor_page,
+ gboolean delete);
+gboolean e_editor_dom_key_press_event_process_return_key
+ (EEditorPage *editor_page);
+WebKitDOMElement *
+ e_editor_dom_wrap_and_quote_element
+ (EEditorPage *editor_page,
+ WebKitDOMElement *element);
+gint e_editor_dom_get_citation_level (WebKitDOMNode *node,
+ gboolean set_plaintext_quoted);
+void e_editor_dom_save_history_for_drop
+ (EEditorPage *editor_page);
+void e_editor_dom_fix_file_uri_images
+ (EEditorPage *editor_page);
+
+/* ******************** Selection ******************** */
+
+void e_editor_dom_replace_base64_image_src
+ (EEditorPage *editor_page,
+ const gchar *selector,
+ const gchar *base64_content,
+ const gchar *filename,
+ const gchar *uri);
+WebKitDOMRange *
+ e_editor_dom_get_current_range (EEditorPage *editor_page);
+void e_editor_dom_move_caret_into_element
+ (EEditorPage *editor_page,
+ WebKitDOMElement *element,
+ gboolean to_start);
+void e_editor_dom_insert_base64_image
+ (EEditorPage *editor_page,
+ const gchar *base64_content,
+ const gchar *filename,
+ const gchar *uri);
+void e_editor_dom_insert_image (EEditorPage *editor_page,
+ const gchar *uri);
+void e_editor_dom_replace_image_src (EEditorPage *editor_page,
+ const gchar *selector,
+ const gchar *uri);
+void e_editor_dom_selection_unlink (EEditorPage *editor_page);
+void e_editor_dom_create_link (EEditorPage *editor_page,
+ const gchar *uri);
+void e_editor_dom_selection_indent (EEditorPage *editor_page);
+void e_editor_dom_selection_unindent (EEditorPage *editor_page);
+void e_editor_dom_selection_save (EEditorPage *editor_page);
+void e_editor_dom_selection_restore (EEditorPage *editor_page);
+gboolean e_editor_dom_selection_is_collapsed
+ (EEditorPage *editor_page);
+void e_editor_dom_scroll_to_caret (EEditorPage *editor_page);
+void e_editor_dom_remove_wrapping_from_element
+ (WebKitDOMElement *element);
+void e_editor_dom_remove_quoting_from_element
+ (WebKitDOMElement *element);
+void e_editor_dom_set_paragraph_style
+ (EEditorPage *editor_page,
+ WebKitDOMElement *element,
+ gint width,
+ gint offset,
+ const gchar *style_to_add);
+WebKitDOMElement *
+ e_editor_dom_get_paragraph_element
+ (EEditorPage *editor_page,
+ gint width,
+ gint offset);
+WebKitDOMElement *
+ e_editor_dom_put_node_into_paragraph
+ (EEditorPage *editor_page,
+ WebKitDOMNode *node,
+ gboolean with_input);
+void e_editor_dom_selection_wrap (EEditorPage *editor_page);
+WebKitDOMElement *
+ e_editor_dom_wrap_paragraph_length
+ (EEditorPage *editor_page,
+ WebKitDOMElement *paragraph,
+ gint length);
+WebKitDOMElement *
+ e_editor_dom_wrap_paragraph (EEditorPage *editor_page,
+ WebKitDOMElement *paragraph);
+void e_editor_dom_wrap_paragraphs_in_document
+ (EEditorPage *editor_page);
+gboolean e_editor_dom_selection_is_underline
+ (EEditorPage *editor_page);
+void e_editor_dom_selection_set_underline
+ (EEditorPage *editor_page,
+ gboolean underline);
+gboolean e_editor_dom_selection_is_subscript
+ (EEditorPage *editor_page);
+void e_editor_dom_selection_set_subscript
+ (EEditorPage *editor_page,
+ gboolean subscript);
+gboolean e_editor_dom_selection_is_superscript
+ (EEditorPage *editor_page);
+void e_editor_dom_selection_set_superscript
+ (EEditorPage *editor_page,
+ gboolean superscript);
+gboolean e_editor_dom_selection_is_strikethrough
+ (EEditorPage *editor_page);
+void e_editor_dom_selection_set_strikethrough
+ (EEditorPage *editor_page,
+ gboolean strikethrough);
+gboolean e_editor_dom_selection_is_monospace
+ (EEditorPage *editor_page);
+void e_editor_dom_selection_set_monospace
+ (EEditorPage *editor_page,
+ gboolean monospaced);
+gboolean e_editor_dom_selection_is_bold (EEditorPage *editor_page);
+void e_editor_dom_selection_set_bold (EEditorPage *editor_page,
+ gboolean bold);
+gboolean e_editor_dom_selection_is_italic
+ (EEditorPage *editor_page);
+void e_editor_dom_selection_set_italic
+ (EEditorPage *editor_page,
+ gboolean italic);
+gboolean e_editor_dom_selection_is_indented
+ (EEditorPage *editor_page);
+gboolean e_editor_dom_selection_is_citation
+ (EEditorPage *editor_page);
+guint e_editor_dom_selection_get_font_size
+ (EEditorPage *editor_page);
+void e_editor_dom_selection_set_font_size
+ (EEditorPage *editor_page,
+ guint font_size);
+gchar * e_editor_dom_selection_get_font_name
+ (EEditorPage *editor_page);
+void e_editor_dom_selection_set_font_name
+ (EEditorPage *editor_page,
+ const gchar *font_size);
+gchar * e_editor_dom_selection_get_font_color
+ (EEditorPage *editor_page);
+void e_editor_dom_selection_set_font_color
+ (EEditorPage *editor_page,
+ const gchar *font_color);
+gchar * e_editor_dom_selection_get_background_color
+ (EEditorPage *editor_page);
+void e_editor_dom_selection_set_background_color
+ (EEditorPage *editor_page,
+ const gchar *bg_color);
+EContentEditorBlockFormat
+ e_editor_dom_selection_get_block_format
+ (EEditorPage *editor_page);
+void e_editor_dom_selection_set_block_format
+ (EEditorPage *editor_page,
+ EContentEditorBlockFormat format);
+EContentEditorAlignment
+ e_editor_dom_selection_get_alignment
+ (EEditorPage *editor_page);
+void e_editor_dom_selection_set_alignment
+ (EEditorPage *editor_page,
+ EContentEditorAlignment alignment);
+void e_editor_dom_selection_replace (EEditorPage *editor_page,
+ const gchar *replacement);
+void e_editor_dom_replace_caret_word (EEditorPage *editor_page,
+ const gchar *replacement);
+gchar * e_editor_dom_get_caret_word (EEditorPage *editor_page);
+EContentEditorAlignment
+ e_editor_dom_get_list_alignment_from_node
+ (WebKitDOMNode *node);
+WebKitDOMElement *
+ e_editor_dom_prepare_paragraph (EEditorPage *editor_page,
+ gboolean with_selection);
+void e_editor_dom_selection_set_on_point
+ (EEditorPage *editor_page,
+ guint x,
+ guint y);
+void e_editor_dom_selection_get_coordinates
+ (EEditorPage *editor_page,
+ guint *start_x,
+ guint *start_y,
+ guint *end_x,
+ guint *end_y);
+gboolean e_editor_dom_is_selection_position_node
+ (WebKitDOMNode *node);
+
+G_END_DECLS
+
+#endif /* E_EDITOR_DOM_FUNCTIONS_H */
diff --git a/modules/webkit-editor/web-extension/e-editor-page.c
b/modules/webkit-editor/web-extension/e-editor-page.c
new file mode 100644
index 0000000..6d362e5
--- /dev/null
+++ b/modules/webkit-editor/web-extension/e-editor-page.c
@@ -0,0 +1,940 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2016 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library 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.
+ *
+ * This library 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 this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <webkit2/webkit-web-extension.h>
+
+#include "web-extensions/e-dom-utils.h"
+
+#include "e-editor-dom-functions.h"
+#include "e-editor-web-extension.h"
+#include "e-editor-undo-redo-manager.h"
+
+#include "e-editor-page.h"
+
+struct _EEditorPagePrivate {
+ WebKitWebPage *web_page; /* not referenced */
+ EEditorWebExtension *web_extension; /* not referenced */
+
+ EEditorUndoRedoManager *undo_redo_manager;
+ ESpellChecker *spell_checker;
+
+ guint spell_check_on_scroll_event_source_id;
+
+ EContentEditorAlignment alignment;
+ EContentEditorBlockFormat block_format;
+ guint32 style_flags; /* bit-OR of EContentEditorStyleFlags */
+ gchar *background_color;
+ gchar *font_color;
+ gchar *font_name;
+ gint font_size;
+
+ guint selection_changed_blocked;
+ gboolean selection_changed;
+
+ gboolean force_image_load;
+ gboolean html_mode;
+ gboolean return_key_pressed;
+ gboolean space_key_pressed;
+ gboolean smiley_written;
+ gint word_wrap_length;
+
+ gboolean convert_in_situ;
+ gboolean body_input_event_removed;
+ gboolean dont_save_history_in_body_input;
+ gboolean composition_in_progress;
+ gboolean pasting_content_from_itself;
+ gboolean renew_history_after_coordinates;
+
+ GHashTable *inline_images;
+
+ WebKitDOMNode *node_under_mouse_click;
+
+ GSettings *mail_settings;
+};
+
+G_DEFINE_TYPE (EEditorPage, e_editor_page, G_TYPE_OBJECT)
+
+
+static void
+web_page_document_loaded_cb (WebKitWebPage *web_page,
+ EEditorPage *editor_page)
+{
+ g_return_if_fail (WEBKIT_IS_WEB_PAGE (web_page));
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ editor_page->priv->body_input_event_removed = TRUE;
+
+ e_editor_undo_redo_manager_clean_history (editor_page->priv->undo_redo_manager);
+ e_editor_dom_process_content_after_load (editor_page);
+}
+
+static gboolean
+web_page_context_menu_cb (WebKitWebPage *web_page,
+ WebKitContextMenu *context_menu,
+ WebKitWebHitTestResult *hit_test_result,
+ EEditorPage *editor_page)
+{
+ WebKitDOMNode *node;
+ EContentEditorNodeFlags flags = 0;
+ GVariant *variant;
+
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+ node = webkit_web_hit_test_result_get_node (hit_test_result);
+ editor_page->priv->node_under_mouse_click = node;
+
+ if (WEBKIT_DOM_IS_HTML_HR_ELEMENT (node))
+ flags |= E_CONTENT_EDITOR_NODE_IS_H_RULE;
+
+ if (WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (node) ||
+ (dom_node_find_parent_element (node, "A") != NULL))
+ flags |= E_CONTENT_EDITOR_NODE_IS_ANCHOR;
+
+ if (WEBKIT_DOM_IS_HTML_IMAGE_ELEMENT (node) ||
+ (dom_node_find_parent_element (node, "IMG") != NULL))
+ flags |= E_CONTENT_EDITOR_NODE_IS_IMAGE;
+
+ if (WEBKIT_DOM_IS_HTML_TABLE_CELL_ELEMENT (node) ||
+ (dom_node_find_parent_element (node, "TD") != NULL) ||
+ (dom_node_find_parent_element (node, "TH") != NULL))
+ flags |= E_CONTENT_EDITOR_NODE_IS_TABLE_CELL;
+
+ if (flags & E_CONTENT_EDITOR_NODE_IS_TABLE_CELL &&
+ (WEBKIT_DOM_IS_HTML_TABLE_ELEMENT (node) ||
+ dom_node_find_parent_element (node, "TABLE") != NULL))
+ flags |= E_CONTENT_EDITOR_NODE_IS_TABLE;
+
+ if (flags == 0)
+ flags |= E_CONTENT_EDITOR_NODE_IS_TEXT;
+
+ variant = g_variant_new_int32 (flags);
+ webkit_context_menu_set_user_data (context_menu, variant);
+
+ return FALSE;
+}
+
+static void
+e_editor_page_setup (EEditorPage *editor_page,
+ WebKitWebPage *web_page,
+ struct _EEditorWebExtension *web_extension)
+{
+ WebKitWebEditor *web_editor;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ editor_page->priv->web_page = web_page;
+ editor_page->priv->web_extension = web_extension;
+ editor_page->priv->undo_redo_manager = e_editor_undo_redo_manager_new (editor_page);
+
+ g_signal_connect_swapped (
+ editor_page->priv->undo_redo_manager, "notify::can-undo",
+ G_CALLBACK (e_editor_page_emit_undo_redo_state_changed), editor_page);
+
+ g_signal_connect_swapped (
+ editor_page->priv->undo_redo_manager, "notify::can-redo",
+ G_CALLBACK (e_editor_page_emit_undo_redo_state_changed), editor_page);
+
+ web_editor = webkit_web_page_get_editor (web_page);
+
+ g_signal_connect_swapped (
+ web_editor, "selection-changed",
+ G_CALLBACK (e_editor_page_emit_selection_changed), editor_page);
+
+ g_signal_connect (
+ web_page, "document-loaded",
+ G_CALLBACK (web_page_document_loaded_cb), editor_page);
+
+ g_signal_connect (
+ web_page, "context-menu",
+ G_CALLBACK (web_page_context_menu_cb), editor_page);
+}
+
+static void
+e_editor_page_dispose (GObject *object)
+{
+ EEditorPage *editor_page = E_EDITOR_PAGE (object);
+
+ if (editor_page->priv->spell_check_on_scroll_event_source_id > 0) {
+ g_source_remove (editor_page->priv->spell_check_on_scroll_event_source_id);
+ editor_page->priv->spell_check_on_scroll_event_source_id = 0;
+ }
+
+ if (editor_page->priv->background_color != NULL) {
+ g_free (editor_page->priv->background_color);
+ editor_page->priv->background_color = NULL;
+ }
+
+ if (editor_page->priv->font_color != NULL) {
+ g_free (editor_page->priv->font_color);
+ editor_page->priv->font_color = NULL;
+ }
+
+ if (editor_page->priv->font_name != NULL) {
+ g_free (editor_page->priv->font_name);
+ editor_page->priv->font_name = NULL;
+ }
+
+ if (editor_page->priv->mail_settings != NULL) {
+ g_signal_handlers_disconnect_by_data (editor_page->priv->mail_settings, object);
+ g_object_unref (editor_page->priv->mail_settings);
+ editor_page->priv->mail_settings = NULL;
+ }
+
+ g_clear_object (&editor_page->priv->undo_redo_manager);
+ g_clear_object (&editor_page->priv->spell_checker);
+
+ g_hash_table_remove_all (editor_page->priv->inline_images);
+
+ /* Chain up to parent's method. */
+ G_OBJECT_CLASS (e_editor_page_parent_class)->dispose (object);
+}
+
+static void
+e_editor_page_finalize (GObject *object)
+{
+ EEditorPage *editor_page = E_EDITOR_PAGE (object);
+
+ g_hash_table_destroy (editor_page->priv->inline_images);
+
+ /* Chain up to parent's method. */
+ G_OBJECT_CLASS (e_editor_page_parent_class)->finalize (object);
+}
+
+static void
+e_editor_page_class_init (EEditorPageClass *class)
+{
+ GObjectClass *object_class;
+
+ g_type_class_add_private (class, sizeof (EEditorPagePrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->dispose = e_editor_page_dispose;
+ object_class->finalize = e_editor_page_finalize;
+}
+
+static void
+e_editor_page_init (EEditorPage *editor_page)
+{
+ editor_page->priv = G_TYPE_INSTANCE_GET_PRIVATE (editor_page, E_TYPE_EDITOR_PAGE, EEditorPagePrivate);
+ editor_page->priv->style_flags = 0;
+ editor_page->priv->selection_changed_blocked = 0;
+ editor_page->priv->background_color = g_strdup ("");
+ editor_page->priv->font_color = g_strdup ("");
+ editor_page->priv->font_name = g_strdup ("");
+ editor_page->priv->font_size = E_CONTENT_EDITOR_FONT_SIZE_NORMAL;
+ editor_page->priv->alignment = E_CONTENT_EDITOR_ALIGNMENT_LEFT;
+ editor_page->priv->block_format = E_CONTENT_EDITOR_BLOCK_FORMAT_PARAGRAPH;
+ editor_page->priv->force_image_load = FALSE;
+ editor_page->priv->html_mode = TRUE;
+ editor_page->priv->return_key_pressed = FALSE;
+ editor_page->priv->space_key_pressed = FALSE;
+ editor_page->priv->smiley_written = FALSE;
+ editor_page->priv->convert_in_situ = FALSE;
+ editor_page->priv->body_input_event_removed = TRUE;
+ editor_page->priv->dont_save_history_in_body_input = FALSE;
+ editor_page->priv->pasting_content_from_itself = FALSE;
+ editor_page->priv->composition_in_progress = FALSE;
+ editor_page->priv->renew_history_after_coordinates = TRUE;
+ editor_page->priv->spell_check_on_scroll_event_source_id = 0;
+ editor_page->priv->mail_settings = e_util_ref_settings ("org.gnome.evolution.mail");
+ editor_page->priv->word_wrap_length = g_settings_get_int (editor_page->priv->mail_settings,
"composer-word-wrap-length");
+ editor_page->priv->inline_images = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+ editor_page->priv->spell_checker = e_spell_checker_new ();
+}
+
+EEditorPage *
+e_editor_page_new (WebKitWebPage *web_page,
+ struct _EEditorWebExtension *web_extension)
+{
+ EEditorPage *editor_page;
+
+ g_return_val_if_fail (WEBKIT_IS_WEB_PAGE (web_page), NULL);
+ g_return_val_if_fail (E_IS_EDITOR_WEB_EXTENSION (web_extension), NULL);
+
+ editor_page = g_object_new (E_TYPE_EDITOR_PAGE, NULL);
+ e_editor_page_setup (editor_page, web_page, web_extension);
+
+ return editor_page;
+}
+
+WebKitWebPage *
+e_editor_page_get_web_page (EEditorPage *editor_page)
+{
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+ return editor_page->priv->web_page;
+}
+
+struct _EEditorWebExtension *
+e_editor_page_get_web_extension (EEditorPage *editor_page)
+{
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+ return editor_page->priv->web_extension;
+}
+
+guint64
+e_editor_page_get_page_id (EEditorPage *editor_page)
+{
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), 0);
+
+ if (!editor_page->priv->web_page)
+ return 0;
+
+ return webkit_web_page_get_id (editor_page->priv->web_page);
+}
+
+WebKitDOMDocument *
+e_editor_page_get_document (EEditorPage *editor_page)
+{
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+ if (!editor_page->priv->web_page)
+ return NULL;
+
+ return webkit_web_page_get_dom_document (editor_page->priv->web_page);
+}
+
+struct _EEditorUndoRedoManager *
+e_editor_page_get_undo_redo_manager (EEditorPage *editor_page)
+{
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+ return editor_page->priv->undo_redo_manager;
+}
+
+void
+e_editor_page_block_selection_changed (EEditorPage *editor_page)
+{
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ editor_page->priv->selection_changed_blocked++;
+}
+
+void
+e_editor_page_unblock_selection_changed (EEditorPage *editor_page)
+{
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+ g_return_if_fail (editor_page->priv->selection_changed_blocked > 0);
+
+ editor_page->priv->selection_changed_blocked--;
+
+ if (!editor_page->priv->selection_changed_blocked &&
+ editor_page->priv->selection_changed) {
+ editor_page->priv->selection_changed = FALSE;
+ e_editor_page_emit_selection_changed (editor_page);
+ }
+}
+
+gboolean
+e_editor_page_get_html_mode (EEditorPage *editor_page)
+{
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+ return editor_page->priv->html_mode;
+}
+
+void
+e_editor_page_set_html_mode (EEditorPage *editor_page,
+ gboolean value)
+{
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ editor_page->priv->html_mode = value;
+}
+
+gboolean
+e_editor_page_get_force_image_load (EEditorPage *editor_page)
+{
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+ return editor_page->priv->force_image_load;
+}
+
+void
+e_editor_page_set_force_image_load (EEditorPage *editor_page,
+ gboolean value)
+{
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ editor_page->priv->force_image_load = value;
+}
+
+gint
+e_editor_page_get_word_wrap_length (EEditorPage *editor_page)
+{
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), 0);
+
+ return editor_page->priv->word_wrap_length;
+}
+
+static gboolean
+e_editor_page_check_style_flag (EEditorPage *editor_page,
+ EContentEditorStyleFlags flag)
+{
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+ return (editor_page->priv->style_flags & flag) != 0;
+}
+
+static gboolean
+e_editor_page_set_style_flag (EEditorPage *editor_page,
+ EContentEditorStyleFlags flag,
+ gboolean value)
+{
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+ if ((((editor_page->priv->style_flags & flag) != 0) ? 1 : 0) == (value ? 1 : 0))
+ return FALSE;
+
+ editor_page->priv->style_flags = (editor_page->priv->style_flags & ~flag) | (value ? flag : 0);
+
+ return TRUE;
+}
+
+gboolean
+e_editor_page_get_bold (EEditorPage *editor_page)
+{
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+ return e_editor_page_check_style_flag (editor_page, E_CONTENT_EDITOR_STYLE_IS_BOLD);
+}
+
+void
+e_editor_page_set_bold (EEditorPage *editor_page,
+ gboolean value)
+{
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ if (e_editor_page_set_style_flag (editor_page, E_CONTENT_EDITOR_STYLE_IS_BOLD, value))
+ e_editor_dom_selection_set_bold (editor_page, value);
+}
+
+gboolean
+e_editor_page_get_italic (EEditorPage *editor_page)
+{
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+ return e_editor_page_check_style_flag (editor_page, E_CONTENT_EDITOR_STYLE_IS_ITALIC);
+}
+
+void
+e_editor_page_set_italic (EEditorPage *editor_page,
+ gboolean value)
+{
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ if (e_editor_page_set_style_flag (editor_page, E_CONTENT_EDITOR_STYLE_IS_ITALIC, value))
+ e_editor_dom_selection_set_italic (editor_page, value);
+}
+
+gboolean
+e_editor_page_get_underline (EEditorPage *editor_page)
+{
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+ return e_editor_page_check_style_flag (editor_page, E_CONTENT_EDITOR_STYLE_IS_UNDERLINE);
+}
+
+void
+e_editor_page_set_underline (EEditorPage *editor_page,
+ gboolean value)
+{
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ if (e_editor_page_set_style_flag (editor_page, E_CONTENT_EDITOR_STYLE_IS_UNDERLINE, value))
+ e_editor_dom_selection_set_underline (editor_page, value);
+}
+
+gboolean
+e_editor_page_get_monospace (EEditorPage *editor_page)
+{
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+ return e_editor_page_check_style_flag (editor_page, E_CONTENT_EDITOR_STYLE_IS_MONOSPACE);
+}
+
+void
+e_editor_page_set_monospace (EEditorPage *editor_page,
+ gboolean value)
+{
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ if (e_editor_page_set_style_flag (editor_page, E_CONTENT_EDITOR_STYLE_IS_MONOSPACE, value))
+ e_editor_dom_selection_set_monospace (editor_page, value);
+}
+
+gboolean
+e_editor_page_get_strikethrough (EEditorPage *editor_page)
+{
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+ return e_editor_page_check_style_flag (editor_page, E_CONTENT_EDITOR_STYLE_IS_STRIKETHROUGH);
+}
+
+void
+e_editor_page_set_strikethrough (EEditorPage *editor_page,
+ gboolean value)
+{
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ if (e_editor_page_set_style_flag (editor_page, E_CONTENT_EDITOR_STYLE_IS_STRIKETHROUGH, value))
+ e_editor_dom_selection_set_strikethrough (editor_page, value);
+}
+
+guint
+e_editor_page_get_font_size (EEditorPage *editor_page)
+{
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), 0);
+
+ return editor_page->priv->font_size;
+}
+
+void
+e_editor_page_set_font_size (EEditorPage *editor_page,
+ guint value)
+{
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ if (editor_page->priv->font_size == value)
+ return;
+
+ editor_page->priv->font_size = value;
+}
+
+const gchar *
+e_editor_page_get_font_color (EEditorPage *editor_page)
+{
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+ return editor_page->priv->font_color;
+}
+
+EContentEditorAlignment
+e_editor_page_get_alignment (EEditorPage *editor_page)
+{
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), E_CONTENT_EDITOR_ALIGNMENT_LEFT);
+
+ return editor_page->priv->alignment;
+}
+
+void
+e_editor_page_set_alignment (EEditorPage *editor_page,
+ EContentEditorAlignment value)
+{
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ editor_page->priv->alignment = value;
+}
+
+gboolean
+e_editor_page_get_return_key_pressed (EEditorPage *editor_page)
+{
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+ return editor_page->priv->return_key_pressed;
+}
+
+void
+e_editor_page_set_return_key_pressed (EEditorPage *editor_page,
+ gboolean value)
+{
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ editor_page->priv->return_key_pressed = value;
+}
+
+gboolean
+e_editor_page_get_space_key_pressed (EEditorPage *editor_page)
+{
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+ return editor_page->priv->space_key_pressed;
+}
+
+void
+e_editor_page_set_space_key_pressed (EEditorPage *editor_page,
+ gboolean value)
+{
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ editor_page->priv->space_key_pressed = value;
+}
+
+gboolean
+e_editor_page_get_magic_links_enabled (EEditorPage *editor_page)
+{
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+ return g_settings_get_boolean (editor_page->priv->mail_settings, "composer-magic-links");
+}
+
+gboolean
+e_editor_page_get_magic_smileys_enabled (EEditorPage *editor_page)
+{
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+ return g_settings_get_boolean (editor_page->priv->mail_settings, "composer-magic-smileys");
+}
+
+gboolean
+e_editor_page_get_unicode_smileys_enabled (EEditorPage *editor_page)
+{
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+ return g_settings_get_boolean (editor_page->priv->mail_settings, "composer-unicode-smileys");
+}
+
+EImageLoadingPolicy
+e_editor_page_get_image_loading_policy (EEditorPage *editor_page)
+{
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), E_IMAGE_LOADING_POLICY_NEVER);
+
+ return g_settings_get_enum (editor_page->priv->mail_settings, "image-loading-policy");
+}
+
+gboolean
+e_editor_page_get_inline_spelling_enabled (EEditorPage *editor_page)
+{
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+ return g_settings_get_boolean (editor_page->priv->mail_settings, "composer-inline-spelling");
+}
+
+gboolean
+e_editor_page_check_word_spelling (EEditorPage *editor_page,
+ const gchar *word,
+ const gchar * const *languages)
+{
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), TRUE);
+
+ if (!word || !languages || !*languages)
+ return TRUE;
+
+ e_spell_checker_set_active_languages (editor_page->priv->spell_checker, languages);
+
+ return e_spell_checker_check_word (editor_page->priv->spell_checker, word, -1);
+}
+
+gboolean
+e_editor_page_get_body_input_event_removed (EEditorPage *editor_page)
+{
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+ return editor_page->priv->body_input_event_removed;
+}
+
+void
+e_editor_page_set_body_input_event_removed (EEditorPage *editor_page,
+ gboolean value)
+{
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ editor_page->priv->body_input_event_removed = value;
+}
+
+gboolean
+e_editor_page_get_convert_in_situ (EEditorPage *editor_page)
+{
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+ return editor_page->priv->convert_in_situ;
+}
+
+void
+e_editor_page_set_convert_in_situ (EEditorPage *editor_page,
+ gboolean value)
+{
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ editor_page->priv->convert_in_situ = value;
+}
+
+GHashTable *
+e_editor_page_get_inline_images (EEditorPage *editor_page)
+{
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+ return editor_page->priv->inline_images;
+}
+
+void
+e_editor_page_add_new_inline_image_into_list (EEditorPage *editor_page,
+ const gchar *cid_src,
+ const gchar *src)
+{
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ g_hash_table_insert (editor_page->priv->inline_images, g_strdup (cid_src), g_strdup (src));
+}
+
+gboolean
+e_editor_page_get_is_smiley_written (EEditorPage *editor_page)
+{
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+ return editor_page->priv->smiley_written;
+}
+
+void
+e_editor_page_set_is_smiley_written (EEditorPage *editor_page,
+ gboolean value)
+{
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ editor_page->priv->smiley_written = value;
+}
+
+gboolean
+e_editor_page_get_dont_save_history_in_body_input (EEditorPage *editor_page)
+{
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+ return editor_page->priv->dont_save_history_in_body_input;
+}
+
+void
+e_editor_page_set_dont_save_history_in_body_input (EEditorPage *editor_page,
+ gboolean value)
+{
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ editor_page->priv->dont_save_history_in_body_input = value;
+}
+
+gboolean
+e_editor_page_is_pasting_content_from_itself (EEditorPage *editor_page)
+{
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+ return editor_page->priv->pasting_content_from_itself;
+}
+
+void
+e_editor_page_set_pasting_content_from_itself (EEditorPage *editor_page,
+ gboolean value)
+{
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ editor_page->priv->pasting_content_from_itself = value;
+}
+
+gboolean
+e_editor_page_get_renew_history_after_coordinates (EEditorPage *editor_page)
+{
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+ return editor_page->priv->renew_history_after_coordinates;
+}
+
+void
+e_editor_page_set_renew_history_after_coordinates (EEditorPage *editor_page,
+ gboolean renew_history_after_coordinates)
+{
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ editor_page->priv->renew_history_after_coordinates = renew_history_after_coordinates;
+}
+
+gboolean
+e_editor_page_is_composition_in_progress (EEditorPage *editor_page)
+{
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+ return editor_page->priv->composition_in_progress;
+}
+
+void
+e_editor_page_set_composition_in_progress (EEditorPage *editor_page,
+ gboolean value)
+{
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ editor_page->priv->composition_in_progress = value;
+}
+
+guint
+e_editor_page_get_spell_check_on_scroll_event_source_id (EEditorPage *editor_page)
+{
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), 0);
+
+ return editor_page->priv->spell_check_on_scroll_event_source_id;
+}
+
+void
+e_editor_page_set_spell_check_on_scroll_event_source_id (EEditorPage *editor_page,
+ guint value)
+{
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ editor_page->priv->spell_check_on_scroll_event_source_id = value;
+}
+
+WebKitDOMNode *
+e_editor_page_get_node_under_mouse_click (EEditorPage *editor_page)
+{
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+ return editor_page->priv->node_under_mouse_click;
+}
+
+void
+e_editor_page_emit_selection_changed (EEditorPage *editor_page)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMRange *range = NULL;
+ GDBusConnection *connection;
+ GError *error = NULL;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ if (!editor_page->priv->web_extension ||
+ editor_page->priv->selection_changed_blocked) {
+ editor_page->priv->selection_changed = TRUE;
+ return;
+ }
+
+ document = e_editor_page_get_document (editor_page);
+ if (!document)
+ return;
+
+ connection = e_editor_web_extension_get_connection (editor_page->priv->web_extension);
+ if (!connection)
+ return;
+
+ range = e_editor_dom_get_current_range (editor_page);
+ if (!range)
+ return;
+
+ g_clear_object (&range);
+
+ editor_page->priv->alignment = e_editor_dom_selection_get_alignment (editor_page);
+ editor_page->priv->block_format = e_editor_dom_selection_get_block_format (editor_page);
+
+ if (editor_page->priv->html_mode) {
+ guint32 style_flags = E_CONTENT_EDITOR_STYLE_NONE;
+
+ #define set_flag_if(tst, flg) G_STMT_START { \
+ if (tst (editor_page)) \
+ style_flags |= flg; \
+ } G_STMT_END
+
+ set_flag_if (e_editor_dom_selection_is_bold, E_CONTENT_EDITOR_STYLE_IS_BOLD);
+ set_flag_if (e_editor_dom_selection_is_italic, E_CONTENT_EDITOR_STYLE_IS_ITALIC);
+ set_flag_if (e_editor_dom_selection_is_underline, E_CONTENT_EDITOR_STYLE_IS_UNDERLINE);
+ set_flag_if (e_editor_dom_selection_is_strikethrough,
E_CONTENT_EDITOR_STYLE_IS_STRIKETHROUGH);
+ set_flag_if (e_editor_dom_selection_is_monospace, E_CONTENT_EDITOR_STYLE_IS_MONOSPACE);
+ set_flag_if (e_editor_dom_selection_is_subscript, E_CONTENT_EDITOR_STYLE_IS_SUBSCRIPT);
+ set_flag_if (e_editor_dom_selection_is_superscript, E_CONTENT_EDITOR_STYLE_IS_SUPERSCRIPT);
+
+ #undef set_flag_if
+
+ editor_page->priv->style_flags = style_flags;
+ editor_page->priv->font_size = e_editor_dom_selection_get_font_size (editor_page);
+ g_free (editor_page->priv->font_color);
+ editor_page->priv->font_color = e_editor_dom_selection_get_font_color (editor_page);
+ }
+
+ g_dbus_connection_emit_signal (
+ connection,
+ NULL,
+ E_WEBKIT_EDITOR_WEB_EXTENSION_OBJECT_PATH,
+ E_WEBKIT_EDITOR_WEB_EXTENSION_INTERFACE,
+ "SelectionChanged",
+ g_variant_new ("(tiibiis)",
+ e_editor_page_get_page_id (editor_page),
+ (gint32) editor_page->priv->alignment,
+ (gint32) editor_page->priv->block_format,
+ e_editor_dom_selection_is_indented (editor_page),
+ editor_page->priv->style_flags,
+ (gint32) editor_page->priv->font_size,
+ editor_page->priv->font_color ? editor_page->priv->font_color : ""),
+ &error);
+
+ if (error) {
+ g_warning ("%s: Failed to emit signal: %s", G_STRFUNC, error->message);
+ g_error_free (error);
+ }
+}
+
+void
+e_editor_page_emit_content_changed (EEditorPage *editor_page)
+{
+ GDBusConnection *connection;
+ GError *error = NULL;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ if (!editor_page->priv->web_extension)
+ return;
+
+ connection = e_editor_web_extension_get_connection (editor_page->priv->web_extension);
+ if (!connection)
+ return;
+
+ g_dbus_connection_emit_signal (
+ connection,
+ NULL,
+ E_WEBKIT_EDITOR_WEB_EXTENSION_OBJECT_PATH,
+ E_WEBKIT_EDITOR_WEB_EXTENSION_INTERFACE,
+ "ContentChanged",
+ g_variant_new ("(t)", e_editor_page_get_page_id (editor_page)),
+ &error);
+
+ if (error) {
+ g_warning ("%s: Failed to emit signal: %s", G_STRFUNC, error->message);
+ g_error_free (error);
+ }
+}
+
+void
+e_editor_page_emit_undo_redo_state_changed (EEditorPage *editor_page)
+{
+ GDBusConnection *connection;
+ GError *error = NULL;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ if (!editor_page->priv->web_extension)
+ return;
+
+ connection = e_editor_web_extension_get_connection (editor_page->priv->web_extension);
+ if (!connection)
+ return;
+
+ g_dbus_connection_emit_signal (
+ connection,
+ NULL,
+ E_WEBKIT_EDITOR_WEB_EXTENSION_OBJECT_PATH,
+ E_WEBKIT_EDITOR_WEB_EXTENSION_INTERFACE,
+ "UndoRedoStateChanged",
+ g_variant_new ("(tbb)",
+ e_editor_page_get_page_id (editor_page),
+ e_editor_undo_redo_manager_can_undo (editor_page->priv->undo_redo_manager),
+ e_editor_undo_redo_manager_can_redo (editor_page->priv->undo_redo_manager)),
+ &error);
+
+ if (error) {
+ g_warning ("%s: Failed to emit signal: %s", G_STRFUNC, error->message);
+ g_error_free (error);
+ }
+}
diff --git a/modules/webkit-editor/web-extension/e-editor-page.h
b/modules/webkit-editor/web-extension/e-editor-page.h
new file mode 100644
index 0000000..160b9ae
--- /dev/null
+++ b/modules/webkit-editor/web-extension/e-editor-page.h
@@ -0,0 +1,197 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2016 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library 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.
+ *
+ * This library 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 this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef E_EDITOR_PAGE_H
+#define E_EDITOR_PAGE_H
+
+#include <glib-object.h>
+#include <webkit2/webkit-web-extension.h>
+
+#define E_UTIL_INCLUDE_WITHOUT_WEBKIT
+#include <e-util/e-util.h>
+#undef E_UTIL_INCLUDE_WITHOUT_WEBKIT
+
+/* Standard GObject macros */
+#define E_TYPE_EDITOR_PAGE \
+ (e_editor_page_get_type ())
+#define E_EDITOR_PAGE(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_EDITOR_PAGE, EEditorPage))
+#define E_EDITOR_PAGE_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_EDITOR_PAGE, EEditorPageClass))
+#define E_IS_EDITOR_PAGE(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_EDITOR_PAGE))
+#define E_IS_EDITOR_PAGE_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_EDITOR_PAGE))
+#define E_EDITOR_PAGE_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_EDITOR_PAGE, EEditorPageClass))
+
+G_BEGIN_DECLS
+
+struct _EEditorWebExtension;
+struct _EEditorUndoRedoManager;
+
+typedef struct _EEditorPage EEditorPage;
+typedef struct _EEditorPageClass EEditorPageClass;
+typedef struct _EEditorPagePrivate EEditorPagePrivate;
+
+struct _EEditorPage {
+ GObject parent;
+ EEditorPagePrivate *priv;
+};
+
+struct _EEditorPageClass {
+ GObjectClass parent_class;
+};
+
+GType e_editor_page_get_type (void) G_GNUC_CONST;
+EEditorPage * e_editor_page_new (WebKitWebPage *web_page,
+ struct _EEditorWebExtension *web_extension);
+WebKitWebPage * e_editor_page_get_web_page (EEditorPage *editor_page);
+struct _EEditorWebExtension *
+ e_editor_page_get_web_extension (EEditorPage *editor_page);
+guint64 e_editor_page_get_page_id (EEditorPage *editor_page);
+WebKitDOMDocument *
+ e_editor_page_get_document (EEditorPage *editor_page);
+struct _EEditorUndoRedoManager *
+ e_editor_page_get_undo_redo_manager
+ (EEditorPage *editor_page);
+
+void e_editor_page_block_selection_changed
+ (EEditorPage *editor_page);
+void e_editor_page_unblock_selection_changed
+ (EEditorPage *editor_page);
+gboolean e_editor_page_get_html_mode (EEditorPage *editor_page);
+void e_editor_page_set_html_mode (EEditorPage *editor_page,
+ gboolean value);
+gboolean e_editor_page_get_force_image_load
+ (EEditorPage *editor_page);
+void e_editor_page_set_force_image_load
+ (EEditorPage *editor_page,
+ gboolean value);
+gboolean e_editor_page_get_bold (EEditorPage *editor_page);
+void e_editor_page_set_bold (EEditorPage *editor_page,
+ gboolean value);
+gboolean e_editor_page_get_italic (EEditorPage *editor_page);
+void e_editor_page_set_italic (EEditorPage *editor_page,
+ gboolean value);
+gboolean e_editor_page_get_underline (EEditorPage *editor_page);
+void e_editor_page_set_underline (EEditorPage *editor_page,
+ gboolean value);
+gboolean e_editor_page_get_monospace (EEditorPage *editor_page);
+void e_editor_page_set_monospace (EEditorPage *editor_page,
+ gboolean value);
+gboolean e_editor_page_get_strikethrough (EEditorPage *editor_page);
+void e_editor_page_set_strikethrough (EEditorPage *editor_page,
+ gboolean value);
+guint e_editor_page_get_font_size (EEditorPage *editor_page);
+void e_editor_page_set_font_size (EEditorPage *editor_page,
+ guint value);
+const gchar * e_editor_page_get_font_color (EEditorPage *editor_page);
+EContentEditorAlignment
+ e_editor_page_get_alignment (EEditorPage *editor_page);
+void e_editor_page_set_alignment (EEditorPage *editor_page,
+ EContentEditorAlignment value);
+gint e_editor_page_get_word_wrap_length
+ (EEditorPage *editor_page);
+gboolean e_editor_page_get_return_key_pressed
+ (EEditorPage *editor_page);
+void e_editor_page_set_return_key_pressed
+ (EEditorPage *editor_page,
+ gboolean value);
+gboolean e_editor_page_get_space_key_pressed
+ (EEditorPage *editor_page);
+void e_editor_page_set_space_key_pressed
+ (EEditorPage *editor_page,
+ gboolean value);
+gboolean e_editor_page_get_magic_links_enabled
+ (EEditorPage *editor_page);
+gboolean e_editor_page_get_magic_smileys_enabled
+ (EEditorPage *editor_page);
+gboolean e_editor_page_get_unicode_smileys_enabled
+ (EEditorPage *editor_page);
+EImageLoadingPolicy
+ e_editor_page_get_image_loading_policy
+ (EEditorPage *editor_page);
+gboolean e_editor_page_get_inline_spelling_enabled
+ (EEditorPage *editor_page);
+gboolean e_editor_page_check_word_spelling
+ (EEditorPage *editor_page,
+ const gchar *word,
+ const gchar * const *languages);
+gboolean e_editor_page_get_body_input_event_removed
+ (EEditorPage *editor_page);
+void e_editor_page_set_body_input_event_removed
+ (EEditorPage *editor_page,
+ gboolean value);
+gboolean e_editor_page_get_convert_in_situ
+ (EEditorPage *editor_page);
+void e_editor_page_set_convert_in_situ
+ (EEditorPage *editor_page,
+ gboolean value);
+GHashTable * e_editor_page_get_inline_images
+ (EEditorPage *editor_page);
+void e_editor_page_add_new_inline_image_into_list
+ (EEditorPage *editor_page,
+ const gchar *cid_src,
+ const gchar *src);
+gboolean e_editor_page_get_is_smiley_written
+ (EEditorPage *editor_page);
+void e_editor_page_set_is_smiley_written
+ (EEditorPage *editor_page,
+ gboolean value);
+gboolean e_editor_page_get_dont_save_history_in_body_input
+ (EEditorPage *editor_page);
+void e_editor_page_set_dont_save_history_in_body_input
+ (EEditorPage *editor_page,
+ gboolean value);
+gboolean e_editor_page_is_pasting_content_from_itself
+ (EEditorPage *editor_page);
+void e_editor_page_set_pasting_content_from_itself
+ (EEditorPage *editor_page,
+ gboolean value);
+gboolean e_editor_page_get_renew_history_after_coordinates
+ (EEditorPage *editor_page);
+void e_editor_page_set_renew_history_after_coordinates
+ (EEditorPage *editor_page,
+ gboolean renew_history_after_coordinates);
+gboolean e_editor_page_is_composition_in_progress
+ (EEditorPage *editor_page);
+void e_editor_page_set_composition_in_progress
+ (EEditorPage *editor_page,
+ gboolean value);
+guint e_editor_page_get_spell_check_on_scroll_event_source_id
+ (EEditorPage *editor_page);
+void e_editor_page_set_spell_check_on_scroll_event_source_id
+ (EEditorPage *editor_page,
+ guint value);
+WebKitDOMNode * e_editor_page_get_node_under_mouse_click
+ (EEditorPage *editor_page);
+
+void e_editor_page_emit_selection_changed
+ (EEditorPage *editor_page);
+void e_editor_page_emit_content_changed
+ (EEditorPage *editor_page);
+void e_editor_page_emit_undo_redo_state_changed
+ (EEditorPage *editor_page);
+G_END_DECLS
+
+#endif /* E_EDITOR_PAGE_H */
diff --git a/modules/webkit-editor/web-extension/e-editor-undo-redo-manager.c
b/modules/webkit-editor/web-extension/e-editor-undo-redo-manager.c
new file mode 100644
index 0000000..2f36941
--- /dev/null
+++ b/modules/webkit-editor/web-extension/e-editor-undo-redo-manager.c
@@ -0,0 +1,2831 @@
+/*
+ * e-editor-undo-redo-manager.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/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define WEBKIT_DOM_USE_UNSTABLE_API
+#include <webkitdom/WebKitDOMDocumentFragmentUnstable.h>
+#include <webkitdom/WebKitDOMRangeUnstable.h>
+#include <webkitdom/WebKitDOMDOMSelection.h>
+#include <webkitdom/WebKitDOMDOMWindowUnstable.h>
+#include <webkitdom/WebKitDOMHTMLElementUnstable.h>
+#include <webkitdom/WebKitDOMDocumentUnstable.h>
+#undef WEBKIT_DOM_USE_UNSTABLE_API
+
+#include "web-extensions/e-dom-utils.h"
+
+#include "e-editor-page.h"
+#include "e-editor-dom-functions.h"
+#include "e-editor-undo-redo-manager.h"
+
+#define E_EDITOR_UNDO_REDO_MANAGER_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_EDITOR_UNDO_REDO_MANAGER, EEditorUndoRedoManagerPrivate))
+
+struct _EEditorUndoRedoManagerPrivate {
+ GWeakRef editor_page;
+
+ gboolean operation_in_progress;
+
+ GList *history;
+ guint history_size;
+};
+
+enum {
+ PROP_0,
+ PROP_CAN_REDO,
+ PROP_CAN_UNDO,
+ PROP_EDITOR_PAGE
+};
+
+#define HISTORY_SIZE_LIMIT 30
+
+#define d(x)
+
+G_DEFINE_TYPE (EEditorUndoRedoManager, e_editor_undo_redo_manager, G_TYPE_OBJECT)
+
+EEditorUndoRedoManager *
+e_editor_undo_redo_manager_new (EEditorPage *editor_page)
+{
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+ return g_object_new (E_TYPE_EDITOR_UNDO_REDO_MANAGER,
+ "editor-page", editor_page,
+ NULL);
+}
+
+static EEditorPage *
+editor_undo_redo_manager_ref_editor_page (EEditorUndoRedoManager *manager)
+{
+ g_return_val_if_fail (E_IS_EDITOR_UNDO_REDO_MANAGER (manager), NULL);
+
+ return g_weak_ref_get (&manager->priv->editor_page);
+}
+
+static WebKitDOMRange *
+get_range_for_point (WebKitDOMDocument *document,
+ EEditorSelectionPoint point)
+{
+ glong scroll_left, scroll_top;
+ WebKitDOMHTMLElement *body;
+ WebKitDOMRange *range = NULL;
+
+ body = webkit_dom_document_get_body (document);
+ scroll_left = webkit_dom_element_get_scroll_left (WEBKIT_DOM_ELEMENT (body));
+ scroll_top = webkit_dom_element_get_scroll_top (WEBKIT_DOM_ELEMENT (body));
+
+ range = webkit_dom_document_caret_range_from_point (
+ document, point.x - scroll_left, point.y - scroll_top);
+
+ /* The point is outside the viewport, scroll to it. */
+ if (!range) {
+ WebKitDOMDOMWindow *dom_window = NULL;
+
+ dom_window = webkit_dom_document_get_default_view (document);
+ webkit_dom_dom_window_scroll_to (dom_window, point.x, point.y);
+
+ scroll_left = webkit_dom_element_get_scroll_left (WEBKIT_DOM_ELEMENT (body));
+ scroll_top = webkit_dom_element_get_scroll_top (WEBKIT_DOM_ELEMENT (body));
+ range = webkit_dom_document_caret_range_from_point (
+ document, point.x - scroll_left, point.y - scroll_top);
+ g_clear_object (&dom_window);
+ }
+
+ return range;
+}
+
+static void
+restore_selection_to_history_event_state (EEditorPage *editor_page,
+ EEditorSelection selection_state)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMDOMWindow *dom_window = NULL;
+ WebKitDOMDOMSelection *dom_selection = NULL;
+ WebKitDOMElement *element, *tmp;
+ WebKitDOMRange *range = NULL;
+ gboolean was_collapsed = FALSE;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ document = e_editor_page_get_document (editor_page);
+ dom_window = webkit_dom_document_get_default_view (document);
+ dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+ g_clear_object (&dom_window);
+
+ /* Restore the selection how it was before the event occured. */
+ range = get_range_for_point (document, selection_state.start);
+ webkit_dom_dom_selection_remove_all_ranges (dom_selection);
+ webkit_dom_dom_selection_add_range (dom_selection, range);
+ g_clear_object (&range);
+
+ was_collapsed = selection_state.start.x == selection_state.end.x;
+ was_collapsed = was_collapsed && selection_state.start.y == selection_state.end.y;
+ if (was_collapsed) {
+ g_clear_object (&dom_selection);
+ return;
+ }
+
+ e_editor_dom_selection_save (editor_page);
+
+ element = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-end-marker");
+
+ remove_node (WEBKIT_DOM_NODE (element));
+
+ element = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-start-marker");
+
+ webkit_dom_element_remove_attribute (element, "id");
+
+ range = get_range_for_point (document, selection_state.end);
+ webkit_dom_dom_selection_remove_all_ranges (dom_selection);
+ webkit_dom_dom_selection_add_range (dom_selection, range);
+ g_clear_object (&range);
+
+ e_editor_dom_selection_save (editor_page);
+
+ tmp = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-start-marker");
+
+ remove_node (WEBKIT_DOM_NODE (tmp));
+
+ webkit_dom_element_set_id (
+ element, "-x-evo-selection-start-marker");
+
+ e_editor_dom_selection_restore (editor_page);
+
+ g_clear_object (&dom_selection);
+}
+
+#if d(1)+0
+static void
+print_node_inner_html (WebKitDOMNode *node)
+{
+ gchar *inner_html;
+
+ if (!node) {
+ printf (" none\n");
+ return;
+ }
+
+ inner_html = dom_get_node_inner_html (node);
+
+ printf (" '%s'\n", inner_html);
+
+ g_free (inner_html);
+}
+
+static void
+print_history_event (EEditorHistoryEvent *event)
+{
+ if (event->type != HISTORY_START && event->type != HISTORY_AND) {
+ printf (" HISTORY EVENT: %d ; \n", event->type);
+ printf (" before: start_x: %u ; start_y: %u ; end_x: %u ; end_y: %u ;\n",
+ event->before.start.x, event->before.start.y, event->before.end.x,
event->before.end.y);
+ printf (" after: start_x: %u ; start_y: %u ; end_x: %u ; end_y: %u ;\n",
+ event->after.start.x, event->after.start.y, event->after.end.x, event->after.end.y);
+ }
+ switch (event->type) {
+ case HISTORY_DELETE:
+ case HISTORY_INPUT:
+ case HISTORY_REMOVE_LINK:
+ case HISTORY_SMILEY:
+ case HISTORY_IMAGE:
+ case HISTORY_CITATION_SPLIT:
+ print_node_inner_html (WEBKIT_DOM_NODE (event->data.fragment));
+ break;
+ case HISTORY_ALIGNMENT:
+ case HISTORY_BLOCK_FORMAT:
+ case HISTORY_BOLD:
+ case HISTORY_FONT_SIZE:
+ case HISTORY_INDENT:
+ case HISTORY_ITALIC:
+ case HISTORY_MONOSPACE:
+ case HISTORY_UNDERLINE:
+ case HISTORY_STRIKETHROUGH:
+ case HISTORY_WRAP:
+ printf (" from %d to %d ;\n", event->data.style.from, event->data.style.to);
+ break;
+ case HISTORY_PASTE:
+ case HISTORY_PASTE_AS_TEXT:
+ case HISTORY_PASTE_QUOTED:
+ case HISTORY_INSERT_HTML:
+ printf (" pasting: '%s' ; \n", event->data.string.to);
+ break;
+ case HISTORY_HRULE_DIALOG:
+ case HISTORY_IMAGE_DIALOG:
+ case HISTORY_LINK_DIALOG:
+ case HISTORY_CELL_DIALOG:
+ case HISTORY_TABLE_DIALOG:
+ case HISTORY_PAGE_DIALOG:
+ case HISTORY_UNQUOTE:
+ print_node_inner_html (event->data.dom.from);
+ print_node_inner_html (event->data.dom.to);
+ break;
+ case HISTORY_FONT_COLOR:
+ case HISTORY_REPLACE:
+ case HISTORY_REPLACE_ALL:
+ printf (" from '%s' to '%s';\n", event->data.string.from, event->data.string.to);
+ break;
+ case HISTORY_START:
+ printf (" HISTORY START\n");
+ break;
+ case HISTORY_AND:
+ printf (" HISTORY AND\n");
+ break;
+ default:
+ printf (" Unknown history type\n");
+ }
+}
+
+static void
+print_history (EEditorUndoRedoManager *manager)
+{
+ printf ("-------------------\nWHOLE HISTORY STACK\n");
+ if (manager->priv->history) {
+ g_list_foreach (
+ manager->priv->history, (GFunc) print_history_event, NULL);
+ }
+ printf ("-------------------\n");
+}
+
+static void
+print_undo_events (EEditorUndoRedoManager *manager)
+{
+ GList *item = manager->priv->history;
+
+ printf ("------------------\nUNDO HISTORY STACK\n");
+ if (!item || !item->next) {
+ printf ("------------------\n");
+ return;
+ }
+
+ print_history_event (item->data);
+ item = item->next;
+ while (item) {
+ print_history_event (item->data);
+ item = item->next;
+ }
+
+ printf ("------------------\n");
+}
+
+static void
+print_redo_events (EEditorUndoRedoManager *manager)
+{
+ GList *item = manager->priv->history;
+
+ printf ("------------------\nREDO HISTORY STACK\n");
+ if (!item || !item->prev) {
+ printf ("------------------\n");
+ return;
+ }
+
+ item = item->prev;
+ while (item) {
+ print_history_event (item->data);
+ item = item->prev;
+ }
+
+ printf ("------------------\n");
+}
+#endif
+
+static gboolean
+event_selection_was_collapsed (EEditorHistoryEvent *ev)
+{
+ return (ev->before.start.x == ev->before.end.x) && (ev->before.start.y == ev->before.end.y);
+}
+
+static WebKitDOMNode *
+split_node_into_two (WebKitDOMNode *item,
+ gint level)
+{
+ gint current_level = 1;
+ WebKitDOMDocument *document;
+ WebKitDOMDocumentFragment *fragment;
+ WebKitDOMNode *parent, *prev_parent = NULL, *tmp = NULL;
+
+ document = webkit_dom_node_get_owner_document (item);
+ fragment = webkit_dom_document_create_document_fragment (document);
+
+ tmp = item;
+ parent = webkit_dom_node_get_parent_node (item);
+ while (!WEBKIT_DOM_IS_HTML_BODY_ELEMENT (parent)) {
+ WebKitDOMNode *clone, *first_child, *insert_before = NULL, *sibling;
+
+ first_child = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (fragment));
+ clone = webkit_dom_node_clone_node_with_error (parent, FALSE, NULL);
+ webkit_dom_node_insert_before (
+ WEBKIT_DOM_NODE (fragment), clone, first_child, NULL);
+
+ if (first_child)
+ insert_before = webkit_dom_node_get_first_child (first_child);
+
+ while (first_child && (sibling = webkit_dom_node_get_next_sibling (first_child)))
+ webkit_dom_node_insert_before (first_child, sibling, insert_before, NULL);
+
+ while ((sibling = webkit_dom_node_get_next_sibling (tmp)))
+ webkit_dom_node_append_child (clone, sibling, NULL);
+
+ webkit_dom_node_insert_before (
+ clone, tmp, webkit_dom_node_get_first_child (clone), NULL);
+
+ prev_parent = parent;
+ tmp = webkit_dom_node_get_next_sibling (parent);
+ parent = webkit_dom_node_get_parent_node (parent);
+ if (WEBKIT_DOM_IS_HTML_BODY_ELEMENT (parent)) {
+ first_child = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (fragment));
+ insert_before = webkit_dom_node_get_first_child (first_child);
+ while (first_child && (sibling = webkit_dom_node_get_next_sibling (first_child))) {
+ webkit_dom_node_insert_before (
+ first_child, sibling, insert_before, NULL);
+ }
+ }
+
+ if (current_level >= level && level >= 0)
+ break;
+
+ current_level++;
+ }
+
+ if (prev_parent) {
+ tmp = webkit_dom_node_insert_before (
+ parent,
+ webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (fragment)),
+ webkit_dom_node_get_next_sibling (prev_parent),
+ NULL);
+ remove_node_if_empty (prev_parent);
+ }
+
+ return tmp;
+}
+
+static void
+undo_delete (EEditorPage *editor_page,
+ EEditorHistoryEvent *event)
+{
+ gboolean empty, single_block;
+ gchar *content;
+ WebKitDOMDocument *document;
+ WebKitDOMDOMWindow *dom_window = NULL;
+ WebKitDOMDOMSelection *dom_selection = NULL;
+ WebKitDOMRange *range = NULL;
+ WebKitDOMElement *element;
+ WebKitDOMNode *first_child, *fragment;
+
+ document = e_editor_page_get_document (editor_page);
+ dom_window = webkit_dom_document_get_default_view (document);
+ dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+ g_clear_object (&dom_window);
+
+ fragment = webkit_dom_node_clone_node_with_error (WEBKIT_DOM_NODE (event->data.fragment), TRUE, NULL);
+ first_child = webkit_dom_node_get_first_child (fragment);
+
+ content = webkit_dom_node_get_text_content (fragment);
+ empty = content && !*content;
+ g_free (content);
+
+ /* Tabulator */
+ single_block = event->type == HISTORY_INPUT;
+ single_block = single_block && event->before.start.x != 0 && event->before.end.y != 0;
+
+ if (!single_block) {
+ /* One block delete */
+ if ((single_block = WEBKIT_DOM_IS_ELEMENT (first_child)))
+ single_block = element_has_id (WEBKIT_DOM_ELEMENT (first_child),
"-x-evo-selection-start-marker");
+ else
+ single_block = WEBKIT_DOM_IS_TEXT (first_child);
+ }
+
+ /* Delete or BackSpace pressed in the beginning of a block or on its end. */
+ if (event->type == HISTORY_DELETE && !single_block &&
+ g_object_get_data (G_OBJECT (event->data.fragment), "history-concatenating-blocks")) {
+ WebKitDOMNode *node, *block;
+
+ range = get_range_for_point (document, event->after.start);
+ webkit_dom_dom_selection_remove_all_ranges (dom_selection);
+ webkit_dom_dom_selection_add_range (dom_selection, range);
+
+ node = webkit_dom_range_get_end_container (range, NULL);
+ block = e_editor_dom_get_parent_block_node_from_child (node);
+
+ if (webkit_dom_document_fragment_query_selector (event->data.fragment, ".-x-evo-quoted",
NULL)) {
+ while ((node = webkit_dom_node_get_first_child (fragment))) {
+ if (WEBKIT_DOM_IS_ELEMENT (node) &&
+ webkit_dom_element_query_selector (WEBKIT_DOM_ELEMENT (node),
".-x-evo-quoted", NULL))
+
+ if (e_editor_dom_get_citation_level (block, FALSE) > 0) {
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (block),
+ node,
+ block,
+ NULL);
+ } else {
+ WebKitDOMNode *next_block;
+
+ next_block = webkit_dom_node_get_next_sibling (block);
+ while (next_block && e_editor_dom_node_is_citation_node
(next_block))
+ next_block = webkit_dom_node_get_first_child
(next_block);
+
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (next_block),
+ node,
+ next_block,
+ NULL);
+ }
+ else {
+ if (e_editor_dom_get_citation_level (block, FALSE) > 0) {
+ WebKitDOMNode *next_node;
+
+ if ((next_node = split_node_into_two (block, -1)))
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (next_node),
+ node,
+ next_node,
+ NULL);
+ else
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (block),
+ node,
+ block,
+ NULL);
+ } else
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (block),
+ node,
+ block,
+ NULL);
+ }
+ }
+ } else {
+ while ((node = webkit_dom_node_get_first_child (fragment))) {
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (block),
+ node,
+ block,
+ NULL);
+ }
+ }
+
+ remove_node (block);
+
+ g_clear_object (&range);
+ g_clear_object (&dom_selection);
+
+ restore_selection_to_history_event_state (editor_page, event->before);
+
+ e_editor_dom_force_spell_check_in_viewport (editor_page);
+
+ return;
+ }
+
+ /* Redoing Return key press */
+ if (event->type == HISTORY_INPUT && (empty ||
+ g_object_get_data (G_OBJECT (event->data.fragment), "history-return-key"))) {
+ if (e_editor_dom_key_press_event_process_return_key (editor_page)) {
+ e_editor_dom_body_key_up_event_process_return_key (editor_page);
+ } else {
+ WebKitDOMElement *element;
+ WebKitDOMNode *next_sibling;
+
+ range = get_range_for_point (document, event->before.start);
+ webkit_dom_dom_selection_remove_all_ranges (dom_selection);
+ webkit_dom_dom_selection_add_range (dom_selection, range);
+ g_clear_object (&range);
+
+ e_editor_dom_selection_save (editor_page);
+
+ element = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-end-marker");
+
+ next_sibling = webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (element));
+ if (next_sibling && !(WEBKIT_DOM_IS_HTML_BR_ELEMENT (next_sibling))) {
+ split_node_into_two (WEBKIT_DOM_NODE (element), 1);
+ } else {
+ WebKitDOMNode *block;
+
+ block = e_editor_dom_get_parent_block_node_from_child (
+ WEBKIT_DOM_NODE (element));
+ dom_remove_selection_markers (document);
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (block),
+ fragment,
+ webkit_dom_node_get_next_sibling (block),
+ NULL);
+ }
+ e_editor_dom_selection_restore (editor_page);
+ }
+
+ e_editor_page_set_return_key_pressed (editor_page, TRUE);
+ e_editor_dom_check_magic_links (editor_page, FALSE);
+ e_editor_page_set_return_key_pressed (editor_page, FALSE);
+ e_editor_dom_force_spell_check_in_viewport (editor_page);
+
+ g_clear_object (&dom_selection);
+
+ return;
+ }
+
+ if (!single_block) {
+ if (WEBKIT_DOM_IS_ELEMENT (first_child) &&
+ !(WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (first_child) ||
+ WEBKIT_DOM_IS_HTML_PRE_ELEMENT (first_child) ||
+ WEBKIT_DOM_IS_HTML_PARAGRAPH_ELEMENT (first_child)))
+ single_block = TRUE;
+ }
+
+ /* Multi block delete */
+ if (WEBKIT_DOM_IS_ELEMENT (first_child) && !single_block) {
+ gboolean delete;
+ WebKitDOMElement *signature;
+ WebKitDOMNode *node, *current_block, *last_child;
+ WebKitDOMNode *next_block, *insert_before;
+
+ range = get_range_for_point (document, event->after.start);
+ webkit_dom_dom_selection_remove_all_ranges (dom_selection);
+ webkit_dom_dom_selection_add_range (dom_selection, range);
+ g_clear_object (&range);
+ e_editor_dom_selection_save (editor_page);
+
+ if ((element = webkit_dom_document_get_element_by_id (document,
"-x-evo-selection-end-marker"))) {
+ WebKitDOMNode *next_sibling;
+
+ if ((next_sibling = webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (element))) &&
+ WEBKIT_DOM_IS_CHARACTER_DATA (next_sibling) &&
+ webkit_dom_character_data_get_length (WEBKIT_DOM_CHARACTER_DATA (next_sibling))
== 1) {
+ gchar *data;
+
+ data = webkit_dom_character_data_get_data (WEBKIT_DOM_CHARACTER_DATA
(next_sibling));
+ if (data && *data == ' ') {
+ WebKitDOMElement *hidden_space;
+
+ hidden_space = webkit_dom_document_create_element (document, "span",
NULL);
+ webkit_dom_element_set_attribute (
+ hidden_space, "data-hidden-space", "", NULL);
+ remove_node (next_sibling);
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element)),
+ WEBKIT_DOM_NODE (hidden_space),
+ webkit_dom_node_get_previous_sibling (
+ WEBKIT_DOM_NODE (element)),
+ NULL);
+ }
+ g_free (data);
+ }
+ }
+
+ element = webkit_dom_document_get_element_by_id (document, "-x-evo-selection-start-marker");
+
+ /* Get the last block in deleted content. */
+ last_child = webkit_dom_node_get_last_child (fragment);
+ while (WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (last_child))
+ last_child = webkit_dom_node_get_last_child (last_child);
+
+ /* All the nodes that are in current block after the caret position
+ * belongs on the end of the deleted content. */
+ node = webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (element));
+
+ /* FIXME Ugly hack */
+ /* If the selection ended in signature, the structure will be broken
+ * thus we saved the whole signature into deleted fragment and we will
+ * restore the whole signature, but we need to remove the rest of the
+ * signature that's left after delete to avoid duplications. */
+ signature = webkit_dom_document_query_selector (document, ".-x-evo-signature-wrapper", NULL);
+ delete = signature && webkit_dom_node_contains (WEBKIT_DOM_NODE (signature), WEBKIT_DOM_NODE
(element));
+ if (!delete) {
+ WebKitDOMNode *tmp_node;
+
+ tmp_node = webkit_dom_node_get_last_child (fragment);
+ delete = tmp_node && WEBKIT_DOM_IS_ELEMENT (tmp_node) &&
+ element_has_class (WEBKIT_DOM_ELEMENT (tmp_node), "-x-evo-signature-wrapper");
+ }
+
+ current_block = e_editor_dom_get_parent_block_node_from_child (WEBKIT_DOM_NODE (element));
+
+ while (node) {
+ WebKitDOMNode *next_sibling, *parent_node;
+
+ next_sibling = webkit_dom_node_get_next_sibling (node);
+ parent_node = webkit_dom_node_get_parent_node (node);
+ /* Check if the whole element was deleted. If so replace it. */
+ if (!next_sibling && WEBKIT_DOM_IS_HTML_BR_ELEMENT (node) &&
+ !webkit_dom_node_get_previous_sibling (WEBKIT_DOM_NODE (element))) {
+ WebKitDOMNode *tmp_node;
+ WebKitDOMElement *tmp_element;
+
+ tmp_node = webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element));
+ webkit_dom_node_replace_child (
+ webkit_dom_node_get_parent_node (tmp_node),
+ fragment,
+ tmp_node,
+ NULL);
+
+ /* Remove empty blockquotes, if presented. */
+ tmp_element = webkit_dom_document_query_selector (
+ document, "blockquote[type=cite]:empty", NULL);
+ if (tmp_element)
+ remove_node (WEBKIT_DOM_NODE (tmp_element));
+
+ e_editor_dom_merge_siblings_if_necessary (editor_page, event->data.fragment);
+
+ tmp_node = webkit_dom_node_get_last_child (last_child);
+ if (tmp_node && WEBKIT_DOM_IS_ELEMENT (tmp_node) &&
+ element_has_class (WEBKIT_DOM_ELEMENT (tmp_node), "-x-evo-quoted")) {
+ webkit_dom_node_append_child (
+ last_child,
+ WEBKIT_DOM_NODE (
+ webkit_dom_document_create_element (
+ document, "br", NULL)),
+ NULL);
+ }
+
+ dom_remove_selection_markers (document);
+
+ restore_selection_to_history_event_state (editor_page, event->before);
+
+ e_editor_dom_force_spell_check_in_viewport (editor_page);
+
+ g_clear_object (&dom_selection);
+
+ return;
+ } else if (!next_sibling && !webkit_dom_node_is_same_node (parent_node,
current_block))
+ next_sibling = webkit_dom_node_get_next_sibling (parent_node);
+
+ if (delete)
+ remove_node (node);
+ else
+ webkit_dom_node_append_child (last_child, node, NULL);
+ node = next_sibling;
+ }
+
+ /* Get the first block in deleted content. */
+ while (WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (first_child))
+ first_child = webkit_dom_node_get_first_child (first_child);
+
+ /* All the nodes that are in the first block of the deleted content
+ * belongs to the current block right after the caret position. */
+ while ((node = webkit_dom_node_get_first_child (first_child)))
+ webkit_dom_node_append_child (current_block, node, NULL);
+
+ next_block = webkit_dom_node_get_next_sibling (current_block);
+ insert_before = next_block;
+
+ if (!insert_before) {
+ WebKitDOMNode *parent = NULL;
+
+ parent = current_block;
+ while ((parent = webkit_dom_node_get_parent_node (parent)) &&
+ !WEBKIT_DOM_IS_HTML_BODY_ELEMENT (parent)) {
+ insert_before = webkit_dom_node_get_next_sibling (parent);
+ if (insert_before)
+ break;
+ }
+ }
+
+ /* Split a BLOCKQUOTE if the deleted content started with BLOCKQUOTE */
+ if (insert_before &&
+ WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (
+ webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (fragment))) &&
+ e_editor_dom_get_citation_level (insert_before, FALSE > 0))
+ insert_before = split_node_into_two (insert_before, -1);
+
+ /* Remove the first block from deleted content as its content was already
+ * moved to the right place. */
+ remove_node (first_child);
+
+ /* Insert the deleted content. */
+ if (insert_before)
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (insert_before),
+ WEBKIT_DOM_NODE (fragment),
+ insert_before,
+ NULL);
+ else
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (
+ webkit_dom_document_get_body (document)),
+ WEBKIT_DOM_NODE (fragment),
+ NULL);
+
+ e_editor_dom_wrap_and_quote_element (editor_page, WEBKIT_DOM_ELEMENT (current_block));
+
+ if (WEBKIT_DOM_IS_ELEMENT (last_child))
+ e_editor_dom_wrap_and_quote_element (editor_page, WEBKIT_DOM_ELEMENT (last_child));
+
+ e_editor_dom_merge_siblings_if_necessary (editor_page, event->data.fragment);
+
+ /* If undoing drag and drop where the whole line was moved we need
+ * to correct the selection. */
+ if (g_object_get_data (G_OBJECT (event->data.fragment), "history-drag-and-drop") &&
+ (element = webkit_dom_document_get_element_by_id (document,
"-x-evo-selection-end-marker"))) {
+ WebKitDOMNode *prev_block;
+
+ prev_block = webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element));
+ if ((prev_block = webkit_dom_node_get_previous_sibling (prev_block)))
+ webkit_dom_node_append_child (
+ prev_block, WEBKIT_DOM_NODE (element), NULL);
+ }
+
+ e_editor_dom_selection_restore (editor_page);
+ e_editor_dom_force_spell_check_in_viewport (editor_page);
+ } else {
+ gboolean empty_text = FALSE, was_link = FALSE;
+ WebKitDOMNode *prev_sibling, *next_sibling, *nd;
+ WebKitDOMNode *parent;
+
+ element = webkit_dom_document_create_element (document, "span", NULL);
+
+ /* Create temporary node on the selection where the delete occured. */
+ if (webkit_dom_document_fragment_query_selector (event->data.fragment, ".Apple-tab-span",
NULL))
+ range = get_range_for_point (document, event->before.start);
+ else
+ range = get_range_for_point (document, event->after.start);
+
+ webkit_dom_range_surround_contents (range, WEBKIT_DOM_NODE (element), NULL);
+ webkit_dom_dom_selection_remove_all_ranges (dom_selection);
+ webkit_dom_dom_selection_add_range (dom_selection, range);
+ g_clear_object (&range);
+
+ nd = webkit_dom_node_get_previous_sibling (WEBKIT_DOM_NODE (element));
+ if (nd && WEBKIT_DOM_IS_TEXT (nd)) {
+ gchar *text = webkit_dom_character_data_get_data (WEBKIT_DOM_CHARACTER_DATA (nd));
+ glong length = webkit_dom_character_data_get_length (WEBKIT_DOM_CHARACTER_DATA (nd));
+
+ /* We have to preserve empty paragraphs with just UNICODE_ZERO_WIDTH_SPACE
+ * character as when we will remove it paragraph will collapse. */
+ if (length > 1) {
+ if (g_str_has_prefix (text, UNICODE_ZERO_WIDTH_SPACE))
+ webkit_dom_character_data_replace_data (
+ WEBKIT_DOM_CHARACTER_DATA (nd), 0, 1, "", NULL);
+ else if (g_str_has_suffix (text, UNICODE_ZERO_WIDTH_SPACE))
+ webkit_dom_character_data_replace_data (
+ WEBKIT_DOM_CHARACTER_DATA (nd), length - 1, 1, "", NULL);
+ } else if (length == 0)
+ empty_text = TRUE;
+
+ g_free (text);
+ }
+
+ parent = webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element));
+ if (!nd || empty_text) {
+ if (WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (parent))
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (parent),
+ WEBKIT_DOM_NODE (element),
+ parent,
+ NULL);
+ }
+
+ /* Insert the deleted content back to the body. */
+ if (WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (parent)) {
+ if (WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (first_child)) {
+ WebKitDOMNode *child;
+
+ while ((child = webkit_dom_node_get_first_child (first_child)))
+ webkit_dom_node_append_child (parent, child, NULL);
+
+ remove_node (first_child);
+
+ was_link = TRUE;
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (parent),
+ fragment,
+ webkit_dom_node_get_next_sibling (parent),
+ NULL);
+ } else {
+ if (g_object_get_data (G_OBJECT (event->data.fragment),
"history-removing-from-anchor") ||
+ !event_selection_was_collapsed (event)) {
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element)),
+ fragment,
+ WEBKIT_DOM_NODE (element),
+ NULL);
+ } else {
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (parent),
+ fragment,
+ webkit_dom_node_get_next_sibling (parent),
+ NULL);
+ }
+ }
+ } else {
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element)),
+ fragment,
+ WEBKIT_DOM_NODE (element),
+ NULL);
+ }
+
+ webkit_dom_node_normalize (parent);
+ prev_sibling = webkit_dom_node_get_previous_sibling (WEBKIT_DOM_NODE (element));
+ next_sibling = webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (element));
+ if (prev_sibling && next_sibling) {
+ WebKitDOMNode *clone_prev, *clone_next;
+
+ clone_prev = webkit_dom_node_clone_node_with_error (prev_sibling, FALSE, NULL);
+ clone_next = webkit_dom_node_clone_node_with_error (next_sibling, FALSE, NULL);
+
+ if (webkit_dom_node_is_equal_node (clone_prev, clone_next)) {
+ WebKitDOMNode *child;
+
+ while ((child = webkit_dom_node_get_first_child (next_sibling)))
+ webkit_dom_node_append_child (prev_sibling, child, NULL);
+
+ remove_node (next_sibling);
+ }
+ }
+
+ remove_node (WEBKIT_DOM_NODE (element));
+
+ if (event->type == HISTORY_DELETE && !e_editor_page_get_html_mode (editor_page)) {
+ WebKitDOMNode *current_block;
+
+ current_block = e_editor_dom_get_parent_block_node_from_child (parent);
+ if (e_editor_dom_get_citation_level (current_block, FALSE) > 0)
+ e_editor_dom_wrap_and_quote_element (editor_page, WEBKIT_DOM_ELEMENT
(current_block));
+ }
+
+ /* If the selection markers are presented restore the selection,
+ * otherwise the selection was not collapsed so select the deleted
+ * content as it was before the delete occurred. */
+ if (webkit_dom_document_fragment_query_selector (event->data.fragment,
"span#-x-evo-selection-start-marker", NULL))
+ e_editor_dom_selection_restore (editor_page);
+ else
+ restore_selection_to_history_event_state (editor_page, event->before);
+
+ if (event->type != HISTORY_INPUT) {
+ if (e_editor_page_get_magic_smileys_enabled (editor_page))
+ e_editor_dom_check_magic_smileys (editor_page);
+ if (!was_link && e_editor_page_get_magic_links_enabled (editor_page))
+ e_editor_dom_check_magic_links (editor_page, FALSE);
+ }
+ e_editor_dom_force_spell_check_for_current_paragraph (editor_page);
+ }
+
+ g_clear_object (&dom_selection);
+}
+
+static void
+redo_delete (EEditorPage *editor_page,
+ EEditorHistoryEvent *event)
+{
+ EEditorUndoRedoManager *manager;
+ WebKitDOMDocument *document;
+ WebKitDOMDocumentFragment *fragment = event->data.fragment;
+ WebKitDOMNode *node;
+ WebKitDOMHTMLElement *body;
+ gboolean delete_key, control_key, html_mode;
+ glong length = 1;
+ gint ii;
+
+ manager = e_editor_page_get_undo_redo_manager (editor_page);
+ document = e_editor_page_get_document (editor_page);
+ html_mode = e_editor_page_get_html_mode (editor_page);
+ restore_selection_to_history_event_state (editor_page, event->before);
+
+ delete_key = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (event->data.fragment),
"history-delete-key"));
+ control_key = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (event->data.fragment),
"history-control-key"));
+
+ body = webkit_dom_document_get_body (document);
+
+ if (!html_mode)
+ e_editor_dom_set_monospace_font_family_on_body (WEBKIT_DOM_ELEMENT (body), TRUE);
+
+ if (!delete_key && e_editor_dom_key_press_event_process_backspace_key (editor_page))
+ goto out;
+
+ if (e_editor_dom_key_press_event_process_delete_or_backspace_key (editor_page, ~0, 0, delete_key))
+ goto out;
+
+ if (control_key) {
+ gchar *text_content;
+
+ text_content = webkit_dom_node_get_text_content (WEBKIT_DOM_NODE (fragment));
+ length = g_utf8_strlen (text_content, -1);
+ control_key = length > 1;
+
+ g_free (text_content);
+ }
+
+ /* If concatenating two blocks with pressing Delete on the end
+ * of the previous one and the next node contain content that
+ * is wrapped on multiple lines, the last line will by separated
+ * by WebKit to the separate block. To avoid it let's remove
+ * all quoting and wrapping from the next paragraph. */
+ if (delete_key &&
+ GPOINTER_TO_INT (g_object_get_data (G_OBJECT (event->data.fragment),
"history-concatenating-blocks"))) {
+ WebKitDOMNode *current_block, *next_block, *node;
+ WebKitDOMRange *range = NULL;
+
+ range = e_editor_dom_get_current_range (editor_page);
+ node = webkit_dom_range_get_end_container (range, NULL);
+ g_clear_object (&range);
+ current_block = e_editor_dom_get_parent_block_node_from_child (node);
+ if (e_editor_dom_get_citation_level (current_block, FALSE) > 0 &&
+ (next_block = webkit_dom_node_get_next_sibling (current_block))) {
+ e_editor_dom_remove_wrapping_from_element (WEBKIT_DOM_ELEMENT (next_block));
+ e_editor_dom_remove_quoting_from_element (WEBKIT_DOM_ELEMENT (next_block));
+ }
+ }
+
+ for (ii = 0; ii < length; ii++) {
+ e_editor_dom_exec_command (editor_page,
+ delete_key ? E_CONTENT_EDITOR_COMMAND_FORWARD_DELETE :
+ E_CONTENT_EDITOR_COMMAND_DELETE,
+ NULL);
+ }
+
+ /* Really don't know why, but when the selection marker nodes were in
+ * anchors then we need to do an extra delete command otherwise we will
+ * end with two blocks split in half. */
+ node = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (fragment));
+ while ((node = webkit_dom_node_get_first_child (node))) {
+ if (WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (node)) {
+ e_editor_dom_exec_command (editor_page,
+ E_CONTENT_EDITOR_COMMAND_FORWARD_DELETE,
+ NULL);
+ break;
+ }
+ }
+
+ node = webkit_dom_node_get_last_child (WEBKIT_DOM_NODE (fragment));
+ while ((node = webkit_dom_node_get_last_child (node))) {
+ if (WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (node)) {
+ e_editor_dom_exec_command (editor_page,
+ E_CONTENT_EDITOR_COMMAND_FORWARD_DELETE,
+ NULL);
+ break;
+ }
+ }
+
+ out:
+ e_editor_page_set_dont_save_history_in_body_input (editor_page, TRUE);
+ e_editor_undo_redo_manager_set_operation_in_progress (manager, FALSE);
+ e_editor_dom_body_input_event_process (editor_page, NULL);
+ e_editor_page_set_dont_save_history_in_body_input (editor_page, FALSE);
+ e_editor_undo_redo_manager_set_operation_in_progress (manager, TRUE);
+ e_editor_page_set_renew_history_after_coordinates (editor_page, FALSE);
+ e_editor_dom_body_key_up_event_process_backspace_or_delete (editor_page, delete_key);
+ e_editor_page_set_renew_history_after_coordinates (editor_page, TRUE);
+ if (!html_mode)
+ e_editor_dom_set_monospace_font_family_on_body (WEBKIT_DOM_ELEMENT (body), FALSE);
+
+ restore_selection_to_history_event_state (editor_page, event->after);
+
+ e_editor_dom_force_spell_check_for_current_paragraph (editor_page);
+}
+
+typedef void (*SelectionStyleChangeFunc) (EEditorPage *editor_page, gint style);
+
+static void
+undo_redo_style_change (EEditorPage *editor_page,
+ EEditorHistoryEvent *event,
+ gboolean undo)
+{
+ SelectionStyleChangeFunc func;
+
+ switch (event->type) {
+ case HISTORY_ALIGNMENT:
+ func = (SelectionStyleChangeFunc) e_editor_dom_selection_set_alignment;
+ break;
+ case HISTORY_BOLD:
+ func = e_editor_dom_selection_set_bold;
+ break;
+ case HISTORY_BLOCK_FORMAT:
+ func = (SelectionStyleChangeFunc) e_editor_dom_selection_set_block_format;
+ break;
+ case HISTORY_FONT_SIZE:
+ func = (SelectionStyleChangeFunc) e_editor_dom_selection_set_font_size;
+ break;
+ case HISTORY_ITALIC:
+ func = e_editor_dom_selection_set_italic;
+ break;
+ case HISTORY_MONOSPACE:
+ func = e_editor_dom_selection_set_monospace;
+ break;
+ case HISTORY_STRIKETHROUGH:
+ func = e_editor_dom_selection_set_strikethrough;
+ break;
+ case HISTORY_UNDERLINE:
+ func = e_editor_dom_selection_set_underline;
+ break;
+ default:
+ return;
+ }
+
+ restore_selection_to_history_event_state (editor_page, undo ? event->after : event->before);
+
+ func (editor_page, undo ? event->data.style.from : event->data.style.to);
+
+ restore_selection_to_history_event_state (editor_page, undo ? event->before : event->after);
+}
+
+static void
+undo_redo_indent (EEditorPage *editor_page,
+ EEditorHistoryEvent *event,
+ gboolean undo)
+{
+ gboolean was_indent = FALSE;
+
+ if (undo)
+ restore_selection_to_history_event_state (editor_page, event->after);
+
+ was_indent = event->data.style.from && event->data.style.to;
+
+ if ((undo && was_indent) || (!undo && !was_indent))
+ e_editor_dom_selection_unindent (editor_page);
+ else
+ e_editor_dom_selection_indent (editor_page);
+
+ if (undo)
+ restore_selection_to_history_event_state (editor_page, event->before);
+}
+
+static void
+undo_redo_font_color (EEditorPage *editor_page,
+ EEditorHistoryEvent *event,
+ gboolean undo)
+{
+ if (undo)
+ restore_selection_to_history_event_state (editor_page, event->after);
+
+ e_editor_dom_exec_command (editor_page,
+ E_CONTENT_EDITOR_COMMAND_FORE_COLOR,
+ undo ? event->data.string.from : event->data.string.to);
+
+ if (undo)
+ restore_selection_to_history_event_state (editor_page, event->before);
+}
+
+static void
+undo_redo_wrap (EEditorPage *editor_page,
+ EEditorHistoryEvent *event,
+ gboolean undo)
+{
+ if (undo)
+ restore_selection_to_history_event_state (editor_page, event->after);
+
+ if (undo) {
+ WebKitDOMNode *node;
+ WebKitDOMElement *element;
+ WebKitDOMRange *range = NULL;
+
+ range = e_editor_dom_get_current_range (editor_page);
+ node = webkit_dom_range_get_common_ancestor_container (range, NULL);
+ g_clear_object (&range);
+ element = get_parent_block_element (WEBKIT_DOM_NODE (node));
+ webkit_dom_element_remove_attribute (element, "data-user-wrapped");
+ e_editor_dom_remove_wrapping_from_element (WEBKIT_DOM_ELEMENT (element));
+
+ e_editor_dom_force_spell_check_for_current_paragraph (editor_page);
+ } else
+ e_editor_dom_selection_wrap (editor_page);
+
+ if (undo)
+ restore_selection_to_history_event_state (editor_page, event->before);
+}
+
+static void
+undo_redo_page_dialog (EEditorPage *editor_page,
+ EEditorHistoryEvent *event,
+ gboolean undo)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMHTMLElement *body;
+ WebKitDOMNamedNodeMap *attributes = NULL, *attributes_history = NULL;
+ gint length, length_history, ii, jj;
+
+ document = e_editor_page_get_document (editor_page);
+ body = webkit_dom_document_get_body (document);
+
+ if (undo)
+ restore_selection_to_history_event_state (editor_page, event->after);
+
+ if (undo) {
+ attributes = webkit_dom_element_get_attributes (WEBKIT_DOM_ELEMENT (body));
+ attributes_history = webkit_dom_element_get_attributes (
+ WEBKIT_DOM_ELEMENT (event->data.dom.from));
+ } else {
+ attributes_history = webkit_dom_element_get_attributes (WEBKIT_DOM_ELEMENT (body));
+ attributes = webkit_dom_element_get_attributes (
+ WEBKIT_DOM_ELEMENT (event->data.dom.to));
+ }
+
+ length = webkit_dom_named_node_map_get_length (attributes);
+ length_history = webkit_dom_named_node_map_get_length (attributes_history);
+ for (ii = length - 1; ii >= 0; ii--) {
+ gchar *name;
+ WebKitDOMNode *attr;
+ gboolean replaced = FALSE;
+
+ attr = webkit_dom_named_node_map_item (attributes, ii);
+ name = webkit_dom_node_get_local_name (attr);
+
+ for (jj = length_history - 1; jj >= 0; jj--) {
+ gchar *name_history;
+ WebKitDOMNode *attr_history;
+
+ attr_history = webkit_dom_named_node_map_item (attributes_history, jj);
+ name_history = webkit_dom_node_get_local_name (attr_history);
+ if (g_strcmp0 (name, name_history) == 0) {
+ WebKitDOMNode *attr_clone;
+
+ attr_clone = webkit_dom_node_clone_node_with_error (
+ undo ? attr_history : attr, TRUE, NULL);
+ webkit_dom_element_set_attribute_node (
+ WEBKIT_DOM_ELEMENT (body),
+ WEBKIT_DOM_ATTR (attr_clone),
+ NULL);
+
+ /* Link color has to replaced in HEAD as well. */
+ if (g_strcmp0 (name, "link") == 0) {
+ gchar *value;
+
+ value = webkit_dom_node_get_node_value (attr_clone);
+ e_editor_dom_set_link_color (editor_page, value);
+ g_free (value);
+ } else if (g_strcmp0 (name, "vlink") == 0) {
+ gchar *value;
+
+ value = webkit_dom_node_get_node_value (attr_clone);
+ e_editor_dom_set_visited_link_color (editor_page, value);
+ g_free (value);
+ }
+ replaced = TRUE;
+ }
+ g_free (name_history);
+ g_clear_object (&attr_history);
+ if (replaced)
+ break;
+ }
+
+ if (!replaced) {
+ if (undo) {
+ webkit_dom_element_remove_attribute_node (
+ WEBKIT_DOM_ELEMENT (body),
+ WEBKIT_DOM_ATTR (attr),
+ NULL);
+ } else {
+ webkit_dom_element_set_attribute_node (
+ WEBKIT_DOM_ELEMENT (body),
+ WEBKIT_DOM_ATTR (
+ webkit_dom_node_clone_node_with_error (attr, TRUE, NULL)),
+ NULL);
+ }
+ }
+ g_free (name);
+ g_object_unref (attr);
+ }
+ g_clear_object (&attributes);
+ g_clear_object (&attributes_history);
+
+ if (undo)
+ restore_selection_to_history_event_state (editor_page, event->before);
+}
+
+static void
+undo_redo_hrule_dialog (EEditorPage *editor_page,
+ EEditorHistoryEvent *event,
+ gboolean undo)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *element;
+
+ document = e_editor_page_get_document (editor_page);
+
+ if (undo)
+ restore_selection_to_history_event_state (editor_page, event->after);
+
+ e_editor_dom_selection_save (editor_page);
+ element = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-start-marker");
+
+ if (undo) {
+ WebKitDOMNode *node;
+ WebKitDOMElement *parent;
+
+ parent = get_parent_block_element (WEBKIT_DOM_NODE (element));
+ if (event->data.dom.from)
+ node = webkit_dom_node_get_previous_sibling (WEBKIT_DOM_NODE (parent));
+ else
+ node = webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (parent));
+
+ if (node && WEBKIT_DOM_IS_HTML_HR_ELEMENT (node)) {
+ if (!event->data.dom.from)
+ remove_node (node);
+ else
+ webkit_dom_node_replace_child (
+ webkit_dom_node_get_parent_node (node),
+ webkit_dom_node_clone_node_with_error (event->data.dom.from, TRUE,
NULL),
+ node,
+ NULL);
+ }
+ } else {
+ WebKitDOMNode *node;
+ WebKitDOMElement *parent;
+
+ parent = get_parent_block_element (WEBKIT_DOM_NODE (element));
+
+ if (event->data.dom.from) {
+ node = webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (parent));
+
+ if (node && WEBKIT_DOM_IS_HTML_HR_ELEMENT (node))
+ webkit_dom_node_replace_child (
+ webkit_dom_node_get_parent_node (node),
+ webkit_dom_node_clone_node_with_error (event->data.dom.to, TRUE,
NULL),
+ node,
+ NULL);
+ } else {
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (parent)),
+ event->data.dom.to,
+ webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (parent)),
+ NULL);
+ }
+ }
+
+ if (undo) {
+ dom_remove_selection_markers (document);
+ restore_selection_to_history_event_state (editor_page, event->before);
+ } else
+ e_editor_dom_selection_restore (editor_page);
+}
+
+static void
+undo_redo_image_dialog (EEditorPage *editor_page,
+ EEditorHistoryEvent *event,
+ gboolean undo)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *element;
+ WebKitDOMNode *sibling, *image = NULL;
+
+ document = e_editor_page_get_document (editor_page);
+
+ if (undo)
+ restore_selection_to_history_event_state (editor_page, event->after);
+
+ e_editor_dom_selection_save (editor_page);
+ element = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-start-marker");
+ sibling = webkit_dom_node_get_previous_sibling (WEBKIT_DOM_NODE (element));
+ if (sibling && WEBKIT_DOM_IS_ELEMENT (sibling)) {
+ if (WEBKIT_DOM_IS_HTML_IMAGE_ELEMENT (sibling))
+ image = sibling;
+ else if (element_has_class (WEBKIT_DOM_ELEMENT (sibling), "-x-evo-resizable-wrapper"))
+ image = webkit_dom_node_get_first_child (sibling);
+ }
+
+ if (!image) {
+ element = WEBKIT_DOM_ELEMENT (webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (element)));
+ sibling = webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (element));
+ if (sibling && WEBKIT_DOM_IS_ELEMENT (sibling)) {
+ if (WEBKIT_DOM_IS_HTML_IMAGE_ELEMENT (sibling))
+ image = sibling;
+ else if (element_has_class (WEBKIT_DOM_ELEMENT (sibling), "-x-evo-resizable-wrapper"))
+ image = webkit_dom_node_get_first_child (sibling);
+ }
+ }
+
+ if (!image)
+ return;
+
+ webkit_dom_node_replace_child (
+ webkit_dom_node_get_parent_node (image),
+ webkit_dom_node_clone_node_with_error (undo ? event->data.dom.from : event->data.dom.to,
TRUE, NULL),
+ image,
+ NULL);
+
+ if (undo)
+ restore_selection_to_history_event_state (editor_page, event->before);
+ else
+ e_editor_dom_selection_restore (editor_page);
+}
+
+static void
+undo_redo_link_dialog (EEditorPage *editor_page,
+ EEditorHistoryEvent *event,
+ gboolean undo)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *anchor, *element;
+
+ document = e_editor_page_get_document (editor_page);
+
+ if (undo)
+ restore_selection_to_history_event_state (editor_page, event->after);
+ else
+ restore_selection_to_history_event_state (editor_page, event->before);
+
+ e_editor_dom_selection_save (editor_page);
+
+ element = webkit_dom_document_get_element_by_id (document, "-x-evo-selection-start-marker");
+ if (!element)
+ return;
+
+ anchor = dom_node_find_parent_element (WEBKIT_DOM_NODE (element), "A");
+ if (undo) {
+ if (anchor) {
+ if (!event->data.dom.from)
+ remove_node (WEBKIT_DOM_NODE (anchor));
+ else
+ webkit_dom_node_replace_child (
+ webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (anchor)),
+ webkit_dom_node_clone_node_with_error (event->data.dom.from, TRUE,
NULL),
+ WEBKIT_DOM_NODE (anchor),
+ NULL);
+ }
+ } else {
+ if (!event->data.dom.to) {
+ if (anchor)
+ remove_node (WEBKIT_DOM_NODE (anchor));
+ } else {
+ if (WEBKIT_DOM_IS_ELEMENT (event->data.dom.from) && anchor) {
+ webkit_dom_node_replace_child (
+ webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (anchor)),
+ webkit_dom_node_clone_node_with_error (event->data.dom.to, TRUE,
NULL),
+ WEBKIT_DOM_NODE (anchor),
+ NULL);
+ } else {
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element)),
+ webkit_dom_node_clone_node_with_error (event->data.dom.to, TRUE,
NULL),
+ WEBKIT_DOM_NODE (element),
+ NULL);
+
+ if (event->data.dom.from)
+ e_editor_dom_exec_command (editor_page,
+ E_CONTENT_EDITOR_COMMAND_DELETE, NULL);
+ }
+ }
+ }
+
+ if (undo)
+ restore_selection_to_history_event_state (editor_page, event->before);
+ else
+ e_editor_dom_selection_restore (editor_page);
+}
+
+static void
+undo_redo_table_dialog (EEditorPage *editor_page,
+ EEditorHistoryEvent *event,
+ gboolean undo)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *table, *element;
+
+ document = e_editor_page_get_document (editor_page);
+
+ if (undo)
+ restore_selection_to_history_event_state (editor_page, event->after);
+
+ e_editor_dom_selection_save (editor_page);
+ element = webkit_dom_document_get_element_by_id (document, "-x-evo-selection-start-marker");
+ if (!element)
+ return;
+
+ table = dom_node_find_parent_element (WEBKIT_DOM_NODE (element), "TABLE");
+
+ if (!table) {
+ if ((!event->data.dom.to && undo) || (!event->data.dom.from && !undo)) {
+ WebKitDOMElement *parent;
+
+ parent = get_parent_block_element (WEBKIT_DOM_NODE (element));
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (parent)),
+ webkit_dom_node_clone_node_with_error (undo ? event->data.dom.from :
event->data.dom.to, TRUE, NULL),
+ WEBKIT_DOM_NODE (parent),
+ NULL);
+ restore_selection_to_history_event_state (editor_page, event->before);
+ return;
+ } else
+ return;
+ }
+
+ if (undo) {
+ if (!event->data.dom.from)
+ remove_node (WEBKIT_DOM_NODE (table));
+ else
+ webkit_dom_node_replace_child (
+ webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (table)),
+ webkit_dom_node_clone_node_with_error (event->data.dom.from, TRUE, NULL),
+ WEBKIT_DOM_NODE (table),
+ NULL);
+ } else {
+ if (!event->data.dom.to)
+ remove_node (WEBKIT_DOM_NODE (table));
+ else
+ webkit_dom_node_replace_child (
+ webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (table)),
+ webkit_dom_node_clone_node_with_error (event->data.dom.to, TRUE, NULL),
+ WEBKIT_DOM_NODE (table),
+ NULL);
+ }
+
+ if (undo)
+ restore_selection_to_history_event_state (editor_page, event->before);
+ else
+ e_editor_dom_selection_restore (editor_page);
+}
+
+static void
+undo_redo_table_input (EEditorPage *editor_page,
+ EEditorHistoryEvent *event,
+ gboolean undo)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMDOMWindow *dom_window = NULL;
+ WebKitDOMDOMSelection *dom_selection = NULL;
+ WebKitDOMElement *element;
+ WebKitDOMNode *node;
+ WebKitDOMRange *range = NULL;
+
+ document = e_editor_page_get_document (editor_page);
+
+ if (undo)
+ restore_selection_to_history_event_state (editor_page, event->after);
+
+ dom_window = webkit_dom_document_get_default_view (document);
+ dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+ g_clear_object (&dom_window);
+
+ if (!webkit_dom_dom_selection_get_range_count (dom_selection)) {
+ g_clear_object (&dom_selection);
+ return;
+ }
+ range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+ g_clear_object (&dom_selection);
+
+ /* Find if writing into table. */
+ node = webkit_dom_range_get_start_container (range, NULL);
+ if (WEBKIT_DOM_IS_HTML_TABLE_CELL_ELEMENT (node))
+ element = WEBKIT_DOM_ELEMENT (node);
+ else
+ element = get_parent_block_element (node);
+
+ g_clear_object (&range);
+
+ /* If writing to table we have to create different history event. */
+ if (!WEBKIT_DOM_IS_HTML_TABLE_CELL_ELEMENT (element))
+ return;
+
+ webkit_dom_node_replace_child (
+ webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element)),
+ webkit_dom_node_clone_node_with_error (undo ? event->data.dom.from : event->data.dom.to,
TRUE, NULL),
+ WEBKIT_DOM_NODE (element),
+ NULL);
+
+ e_editor_dom_selection_restore (editor_page);
+}
+
+static void
+undo_redo_paste (EEditorPage *editor_page,
+ EEditorHistoryEvent *event,
+ gboolean undo)
+{
+ WebKitDOMDocument *document;
+
+ document = e_editor_page_get_document (editor_page);
+
+ if (undo) {
+ if (event->type == HISTORY_PASTE_QUOTED) {
+ WebKitDOMElement *tmp;
+ WebKitDOMNode *parent;
+
+ restore_selection_to_history_event_state (editor_page, event->after);
+
+ e_editor_dom_selection_save (editor_page);
+ tmp = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-start-marker");
+ if (!tmp)
+ return;
+
+ parent = webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (tmp));
+ while (!WEBKIT_DOM_IS_HTML_BODY_ELEMENT (webkit_dom_node_get_parent_node (parent)))
+ parent = webkit_dom_node_get_parent_node (parent);
+
+ webkit_dom_node_replace_child (
+ webkit_dom_node_get_parent_node (parent),
+ WEBKIT_DOM_NODE (e_editor_dom_prepare_paragraph (editor_page, TRUE)),
+ parent,
+ NULL);
+
+ e_editor_dom_selection_restore (editor_page);
+ } else {
+ WebKitDOMDOMWindow *dom_window = NULL;
+ WebKitDOMDOMSelection *dom_selection = NULL;
+ WebKitDOMElement *element, *tmp;
+ WebKitDOMRange *range = NULL;
+
+ dom_window = webkit_dom_document_get_default_view (document);
+ dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+ g_clear_object (&dom_window);
+
+ /* Restore the selection how it was before the event occured. */
+ range = get_range_for_point (document, event->before.start);
+ webkit_dom_dom_selection_remove_all_ranges (dom_selection);
+ webkit_dom_dom_selection_add_range (dom_selection, range);
+ g_clear_object (&range);
+
+ e_editor_dom_selection_save (editor_page);
+
+ element = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-end-marker");
+
+ remove_node (WEBKIT_DOM_NODE (element));
+
+ element = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-start-marker");
+
+ webkit_dom_element_remove_attribute (element, "id");
+
+ range = get_range_for_point (document, event->after.start);
+ webkit_dom_dom_selection_remove_all_ranges (dom_selection);
+ webkit_dom_dom_selection_add_range (dom_selection, range);
+ g_clear_object (&range);
+ g_clear_object (&dom_selection);
+
+ e_editor_dom_selection_save (editor_page);
+
+ tmp = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-start-marker");
+
+ remove_node (WEBKIT_DOM_NODE (tmp));
+
+ webkit_dom_element_set_id (
+ element, "-x-evo-selection-start-marker");
+
+ e_editor_dom_selection_restore (editor_page);
+
+ e_editor_dom_exec_command (editor_page, E_CONTENT_EDITOR_COMMAND_DELETE, NULL);
+
+ e_editor_dom_force_spell_check_for_current_paragraph (editor_page);
+ }
+ } else {
+ restore_selection_to_history_event_state (editor_page, event->before);
+
+ if (event->type == HISTORY_PASTE)
+ e_editor_dom_convert_and_insert_html_into_selection (editor_page,
event->data.string.to, FALSE);
+ else if (event->type == HISTORY_PASTE_QUOTED)
+ e_editor_dom_quote_and_insert_text_into_selection (editor_page,
event->data.string.to, FALSE);
+ else if (event->type == HISTORY_INSERT_HTML)
+ e_editor_dom_insert_html (editor_page, event->data.string.to);
+ else
+ e_editor_dom_convert_and_insert_html_into_selection (editor_page,
event->data.string.to, FALSE);
+ /* e_editor_selection_insert_as_text (selection, event->data.string.to); */
+ }
+}
+
+static void
+undo_redo_image (EEditorPage *editor_page,
+ EEditorHistoryEvent *event,
+ gboolean undo)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMDOMWindow *dom_window = NULL;
+ WebKitDOMDOMSelection *dom_selection = NULL;
+ WebKitDOMRange *range = NULL;
+
+ document = e_editor_page_get_document (editor_page);
+ dom_window = webkit_dom_document_get_default_view (document);
+ dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+ g_clear_object (&dom_window);
+
+ if (undo) {
+ WebKitDOMElement *element;
+ WebKitDOMNode *node;
+
+ range = get_range_for_point (document, event->before.start);
+ webkit_dom_dom_selection_remove_all_ranges (dom_selection);
+ webkit_dom_dom_selection_add_range (dom_selection, range);
+ g_clear_object (&range);
+
+ e_editor_dom_selection_save (editor_page);
+ element = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-end-marker");
+
+ node = webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (element));
+
+ if (WEBKIT_DOM_IS_ELEMENT (node))
+ if (element_has_class (WEBKIT_DOM_ELEMENT (node), "-x-evo-resizable-wrapper") ||
+ element_has_class (WEBKIT_DOM_ELEMENT (node), "-x-evo-smiley-wrapper"))
+ remove_node (node);
+ e_editor_dom_selection_restore (editor_page);
+ } else {
+ WebKitDOMElement *element;
+
+ range = get_range_for_point (document, event->before.start);
+ /* Create temporary node on the selection where the delete occured. */
+ webkit_dom_dom_selection_remove_all_ranges (dom_selection);
+ webkit_dom_dom_selection_add_range (dom_selection, range);
+ g_clear_object (&range);
+
+ e_editor_dom_selection_save (editor_page);
+ element = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-start-marker");
+
+ /* Insert the deleted content back to the body. */
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element)),
+ webkit_dom_node_clone_node_with_error (WEBKIT_DOM_NODE (event->data.fragment), TRUE,
NULL),
+ WEBKIT_DOM_NODE (element),
+ NULL);
+
+ e_editor_dom_selection_restore (editor_page);
+ e_editor_dom_force_spell_check_for_current_paragraph (editor_page);
+ }
+
+ g_clear_object (&dom_selection);
+}
+
+static void
+undo_redo_replace (EEditorPage *editor_page,
+ EEditorHistoryEvent *event,
+ gboolean undo)
+{
+ WebKitDOMDocument *document;
+
+ document = e_editor_page_get_document (editor_page);
+
+ restore_selection_to_history_event_state (editor_page, undo ? event->after : event->before);
+
+ if (undo) {
+ WebKitDOMDOMWindow *dom_window = NULL;
+ WebKitDOMDOMSelection *dom_selection = NULL;
+
+ dom_window = webkit_dom_document_get_default_view (document);
+ dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+ g_clear_object (&dom_window);
+
+ webkit_dom_dom_selection_modify (dom_selection, "extend", "left", "word");
+ g_clear_object (&dom_selection);
+ }
+
+ e_editor_dom_exec_command (editor_page,
+ E_CONTENT_EDITOR_COMMAND_INSERT_TEXT,
+ undo ? event->data.string.from : event->data.string.to);
+
+ e_editor_dom_force_spell_check_for_current_paragraph (editor_page);
+
+ restore_selection_to_history_event_state (editor_page, undo ? event->before : event->after);
+}
+
+static void
+undo_redo_replace_all (EEditorUndoRedoManager *manager,
+ EEditorPage *editor_page,
+ EEditorHistoryEvent *event,
+ gboolean undo)
+{
+ WebKitDOMDocument *document;
+
+ document = e_editor_page_get_document (editor_page);
+
+ if (undo) {
+ if (event->type == HISTORY_REPLACE) {
+ undo_redo_replace (editor_page, event, undo);
+ return;
+ } else {
+ EEditorHistoryEvent *next_event;
+ GList *next_item;
+ WebKitDOMDOMWindow *dom_window = NULL;
+ WebKitDOMDOMSelection *dom_selection = NULL;
+
+ next_item = manager->priv->history->next;
+
+ while (next_item) {
+ next_event = next_item->data;
+
+ if (next_event->type != HISTORY_REPLACE)
+ break;
+
+ if (g_strcmp0 (next_event->data.string.from, event->data.string.from) != 0)
+ break;
+
+ if (g_strcmp0 (next_event->data.string.to, event->data.string.to) != 0)
+ break;
+
+ undo_redo_replace (editor_page, next_event, undo);
+
+ next_item = next_item->next;
+ }
+
+ manager->priv->history = next_item->prev;
+
+ dom_window = webkit_dom_document_get_default_view (document);
+ dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+ webkit_dom_dom_selection_collapse_to_end (dom_selection, NULL);
+ g_clear_object (&dom_window);
+ g_clear_object (&dom_selection);
+ }
+ } else {
+ /* Find if this history item is part of HISTORY_REPLACE_ALL. */
+ EEditorHistoryEvent *prev_event;
+ GList *prev_item;
+ gboolean replace_all = FALSE;
+
+ prev_item = manager->priv->history->prev;
+ while (prev_item) {
+ prev_event = prev_item->data;
+
+ if (prev_event->type == HISTORY_REPLACE)
+ prev_item = prev_item->prev;
+ else if (prev_event->type == HISTORY_REPLACE_ALL) {
+ replace_all = TRUE;
+ break;
+ } else
+ break;
+ }
+
+ if (!replace_all) {
+ undo_redo_replace (editor_page, event, undo);
+ return;
+ }
+
+ prev_item = manager->priv->history->prev;
+ while (prev_item) {
+ prev_event = prev_item->data;
+
+ if (prev_event->type == HISTORY_REPLACE) {
+ undo_redo_replace (editor_page, prev_event, undo);
+ prev_item = prev_item->prev;
+ } else
+ break;
+ }
+
+ manager->priv->history = prev_item->next;
+ }
+}
+
+static void
+undo_redo_remove_link (EEditorPage *editor_page,
+ EEditorHistoryEvent *event,
+ gboolean undo)
+{
+ WebKitDOMDocument *document;
+
+ document = e_editor_page_get_document (editor_page);
+
+ if (undo)
+ restore_selection_to_history_event_state (editor_page, event->after);
+
+ if (undo) {
+ WebKitDOMDOMWindow *dom_window = NULL;
+ WebKitDOMDOMSelection *dom_selection = NULL;
+ WebKitDOMElement *element;
+ WebKitDOMRange *range = NULL;
+
+ dom_window = webkit_dom_document_get_default_view (document);
+ dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+ /* Select the anchor. */
+ webkit_dom_dom_selection_modify (dom_selection, "move", "left", "word");
+ webkit_dom_dom_selection_modify (dom_selection, "extend", "right", "word");
+
+ range = e_editor_dom_get_current_range (editor_page);
+ element = webkit_dom_document_create_element (document, "SPAN", NULL);
+ webkit_dom_range_surround_contents (range, WEBKIT_DOM_NODE (element), NULL);
+ g_clear_object (&range);
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element)),
+ webkit_dom_node_clone_node_with_error (WEBKIT_DOM_NODE (event->data.fragment), TRUE,
NULL),
+ WEBKIT_DOM_NODE (element),
+ NULL);
+ remove_node (WEBKIT_DOM_NODE (element));
+ g_clear_object (&dom_window);
+ g_clear_object (&dom_selection);
+ } else
+ e_editor_dom_selection_unlink (editor_page);
+
+ if (undo)
+ restore_selection_to_history_event_state (editor_page, event->before);
+}
+
+static void
+undo_return_in_empty_list_item (EEditorPage *editor_page,
+ EEditorHistoryEvent *event)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *selection_start_marker;
+ WebKitDOMNode *parent;
+
+ document = e_editor_page_get_document (editor_page);
+ e_editor_dom_selection_save (editor_page);
+
+ selection_start_marker = webkit_dom_document_get_element_by_id (document,
"-x-evo-selection-start-marker");
+ parent = webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (selection_start_marker));
+
+ if (WEBKIT_DOM_IS_HTML_LI_ELEMENT (parent)) {
+ WebKitDOMNode *parent_list;
+
+ dom_remove_selection_markers (document);
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (parent),
+ webkit_dom_node_clone_node_with_error (WEBKIT_DOM_NODE (event->data.fragment), TRUE,
NULL),
+ webkit_dom_node_get_next_sibling (parent),
+ NULL);
+
+ parent_list = parent;
+ while (node_is_list_or_item (webkit_dom_node_get_parent_node (parent_list)))
+ parent_list = webkit_dom_node_get_parent_node (parent_list);
+
+ merge_lists_if_possible (parent_list);
+ }
+
+ e_editor_dom_selection_restore (editor_page);
+}
+
+static gboolean
+undo_return_press_after_h_rule (EEditorPage *editor_page,
+ EEditorHistoryEvent *event)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *selection_start_marker, *block;
+ WebKitDOMNode *node;
+
+ document = e_editor_page_get_document (editor_page);
+
+ e_editor_dom_selection_save (editor_page);
+
+ selection_start_marker = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-start-marker");
+
+ block = get_parent_block_element (WEBKIT_DOM_NODE (selection_start_marker));
+ node = webkit_dom_node_get_previous_sibling (WEBKIT_DOM_NODE( block));
+
+ if (!webkit_dom_node_get_previous_sibling (WEBKIT_DOM_NODE (selection_start_marker)) &&
+ WEBKIT_DOM_IS_HTML_HR_ELEMENT (node)) {
+
+ remove_node_if_empty (WEBKIT_DOM_NODE (block));
+ restore_selection_to_history_event_state (editor_page, event->before);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+undo_input (EEditorUndoRedoManager *manager,
+ EEditorPage *editor_page,
+ EEditorHistoryEvent *event)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMDOMWindow *dom_window = NULL;
+ WebKitDOMDOMSelection *dom_selection = NULL;
+ WebKitDOMNode *node, *tmp_node;
+ gboolean remove_anchor;
+
+ document = e_editor_page_get_document (editor_page);
+ dom_window = webkit_dom_document_get_default_view (document);
+ dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+
+ restore_selection_to_history_event_state (editor_page, event->after);
+
+ /* Undoing Return press after the HR element */
+ if (e_editor_page_get_html_mode (editor_page) &&
+ g_object_get_data (G_OBJECT (event->data.fragment), "history-return-key")) {
+ if (undo_return_press_after_h_rule (editor_page, event)) {
+ g_clear_object (&dom_window);
+ g_clear_object (&dom_selection);
+ return;
+ }
+ }
+
+ webkit_dom_dom_selection_modify (dom_selection, "extend", "left", "character");
+ if (e_editor_dom_selection_is_citation (editor_page)) {
+ /* Post processing of quoted text in body_input_event_cb needs to be called. */
+ manager->priv->operation_in_progress = FALSE;
+ e_editor_page_set_dont_save_history_in_body_input (editor_page, TRUE);
+ }
+
+ /* If we are undoing the text that was appended to the link we have to
+ * remove the link and make just the plain text from it. */
+ node = webkit_dom_dom_selection_get_anchor_node (dom_selection);
+ node = webkit_dom_node_get_parent_node (node);
+ remove_anchor = WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (node);
+ if (remove_anchor) {
+ gchar *text_content;
+
+ text_content = webkit_dom_node_get_text_content (node);
+ /* Remove the anchor just in case we are undoing the input from
+ * the end of it. */
+ remove_anchor =
+ g_utf8_strlen (text_content, -1) ==
+ webkit_dom_dom_selection_get_anchor_offset (dom_selection);
+ g_free (text_content);
+ }
+
+ e_editor_dom_exec_command (editor_page, E_CONTENT_EDITOR_COMMAND_DELETE, NULL);
+
+ if (remove_anchor) {
+ WebKitDOMNode *child;
+
+ /* Don't ask me why, but I got into the situation where the node
+ * that I received above was out of the document, and all the
+ * modifications to it were of course not propagated to it. Let's
+ * get that node again. */
+ node = webkit_dom_dom_selection_get_anchor_node (dom_selection);
+ node = webkit_dom_node_get_parent_node (node);
+ while ((child = webkit_dom_node_get_first_child (node)))
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (node), child, node, NULL);
+
+ remove_node (node);
+ }
+
+ tmp_node = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (event->data.fragment));
+ if (WEBKIT_DOM_IS_HTML_LI_ELEMENT (tmp_node) &&
+ WEBKIT_DOM_IS_HTML_BR_ELEMENT (webkit_dom_node_get_last_child (tmp_node)))
+ undo_return_in_empty_list_item (editor_page, event);
+
+ g_clear_object (&dom_window);
+ g_clear_object (&dom_selection);
+}
+
+static void
+undo_redo_citation_split (EEditorPage *editor_page,
+ EEditorHistoryEvent *event,
+ gboolean undo)
+{
+ WebKitDOMDocument *document;
+ gboolean in_situ = FALSE;
+
+ document = e_editor_page_get_document (editor_page);
+
+ if (event->before.start.x == event->after.start.x &&
+ event->before.start.y == event->after.start.y &&
+ event->before.end.x == event->after.end.x &&
+ event->before.end.y == event->after.end.y)
+ in_situ = TRUE;
+
+ if (undo) {
+ WebKitDOMElement *selection_start, *parent;
+ WebKitDOMNode *citation_before, *citation_after, *child, *last_child, *tmp;
+
+ restore_selection_to_history_event_state (editor_page, event->after);
+
+ e_editor_dom_selection_save (editor_page);
+ selection_start = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-start-marker");
+ if (!selection_start)
+ return;
+
+ parent = get_parent_block_element (WEBKIT_DOM_NODE (selection_start));
+
+ citation_before = webkit_dom_node_get_previous_sibling (WEBKIT_DOM_NODE (parent));
+ if (!e_editor_dom_node_is_citation_node (citation_before)) {
+ e_editor_dom_selection_restore (editor_page);
+ return;
+ }
+
+ citation_after = webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (parent));
+ if (!e_editor_dom_node_is_citation_node (citation_after)) {
+ e_editor_dom_selection_restore (editor_page);
+ return;
+ }
+
+ /* Get first block in next citation. */
+ child = webkit_dom_node_get_first_child (citation_after);
+ while (child && e_editor_dom_node_is_citation_node (child))
+ child = webkit_dom_node_get_first_child (child);
+
+ /* Get last block in previous citation. */
+ last_child = webkit_dom_node_get_last_child (citation_before);
+ while (last_child && e_editor_dom_node_is_citation_node (last_child))
+ last_child = webkit_dom_node_get_last_child (last_child);
+
+ /* Before appending any content to the block, check that the
+ * last node is not BR, if it is, remove it. */
+ tmp = webkit_dom_node_get_last_child (last_child);
+ if (WEBKIT_DOM_IS_HTML_BR_ELEMENT (tmp))
+ remove_node (tmp);
+
+ if (in_situ && event->data.fragment) {
+ webkit_dom_node_append_child (
+ webkit_dom_node_get_parent_node (last_child),
+ webkit_dom_node_clone_node_with_error (
+ WEBKIT_DOM_NODE (event->data.fragment), TRUE, NULL),
+ NULL);
+ } else {
+ e_editor_dom_remove_quoting_from_element (WEBKIT_DOM_ELEMENT (child));
+ e_editor_dom_remove_wrapping_from_element (WEBKIT_DOM_ELEMENT (child));
+
+ e_editor_dom_remove_quoting_from_element (WEBKIT_DOM_ELEMENT (last_child));
+ e_editor_dom_remove_wrapping_from_element (WEBKIT_DOM_ELEMENT (last_child));
+
+ /* Copy the content of the first block to the last block to get
+ * to the state how the block looked like before it was split. */
+ while ((tmp = webkit_dom_node_get_first_child (child)))
+ webkit_dom_node_append_child (last_child, tmp, NULL);
+
+ e_editor_dom_wrap_and_quote_element (editor_page, WEBKIT_DOM_ELEMENT (last_child));
+
+ remove_node (child);
+ }
+
+ /* Move all the block from next citation to the previous one. */
+ while ((child = webkit_dom_node_get_first_child (citation_after)))
+ webkit_dom_node_append_child (citation_before, child, NULL);
+
+ dom_remove_selection_markers (document);
+
+ remove_node (WEBKIT_DOM_NODE (parent));
+ remove_node (WEBKIT_DOM_NODE (citation_after));
+
+ /* If enter was pressed when some text was selected, restore it. */
+ if (event->data.fragment != NULL && !in_situ)
+ undo_delete (editor_page, event);
+
+ e_editor_dom_merge_siblings_if_necessary (editor_page, NULL);
+
+ restore_selection_to_history_event_state (editor_page, event->before);
+
+ e_editor_dom_force_spell_check_in_viewport (editor_page);
+ } else {
+ restore_selection_to_history_event_state (editor_page, event->before);
+
+ if (in_situ) {
+ WebKitDOMElement *selection_start_marker;
+ WebKitDOMNode *block;
+
+ e_editor_dom_selection_save (editor_page);
+
+ selection_start_marker = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-start-marker");
+
+ block = e_editor_dom_get_parent_block_node_from_child (
+ WEBKIT_DOM_NODE (selection_start_marker));
+ dom_remove_selection_markers (document);
+
+ /* Remove current block (and all of its parents if they
+ * are empty) as it will be replaced by a new block that
+ * will be in the body and not in the blockquote. */
+ e_editor_dom_remove_node_and_parents_if_empty (block);
+ }
+
+ e_editor_dom_insert_new_line_into_citation (editor_page, "");
+ }
+}
+
+static void
+undo_redo_unquote (EEditorPage *editor_page,
+ EEditorHistoryEvent *event,
+ gboolean undo)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *element;
+
+ document = e_editor_page_get_document (editor_page);
+
+ restore_selection_to_history_event_state (editor_page, undo ? event->after : event->before);
+
+ e_editor_dom_selection_save (editor_page);
+ element = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-start-marker");
+
+ if (undo) {
+ WebKitDOMNode *next_sibling, *prev_sibling;
+ WebKitDOMElement *block;
+
+ block = get_parent_block_element (WEBKIT_DOM_NODE (element));
+
+ next_sibling = webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (block));
+ prev_sibling = webkit_dom_node_get_previous_sibling (WEBKIT_DOM_NODE (block));
+
+ if (prev_sibling && e_editor_dom_node_is_citation_node (prev_sibling)) {
+ webkit_dom_node_append_child (
+ prev_sibling,
+ webkit_dom_node_clone_node_with_error (event->data.dom.from, TRUE, NULL),
+ NULL);
+
+ if (next_sibling && e_editor_dom_node_is_citation_node (next_sibling)) {
+ WebKitDOMNode *child;
+
+ while ((child = webkit_dom_node_get_first_child (next_sibling)))
+ webkit_dom_node_append_child (
+ prev_sibling, child, NULL);
+
+ remove_node (next_sibling);
+ }
+ } else if (next_sibling && e_editor_dom_node_is_citation_node (next_sibling)) {
+ webkit_dom_node_insert_before (
+ next_sibling,
+ webkit_dom_node_clone_node_with_error (event->data.dom.from, TRUE, NULL),
+ webkit_dom_node_get_first_child (next_sibling),
+ NULL);
+ }
+
+ remove_node (WEBKIT_DOM_NODE (block));
+ } else
+ e_editor_dom_move_quoted_block_level_up (editor_page);
+
+ if (undo)
+ e_editor_dom_selection_restore (editor_page);
+ else
+ restore_selection_to_history_event_state (editor_page, event->after);
+
+ e_editor_dom_force_spell_check_for_current_paragraph (editor_page);
+}
+
+gboolean
+e_editor_undo_redo_manager_is_operation_in_progress (EEditorUndoRedoManager *manager)
+{
+ g_return_val_if_fail (E_IS_EDITOR_UNDO_REDO_MANAGER (manager), FALSE);
+
+ return manager->priv->operation_in_progress;
+}
+
+void
+e_editor_undo_redo_manager_set_operation_in_progress (EEditorUndoRedoManager *manager,
+ gboolean value)
+{
+ g_return_if_fail (E_IS_EDITOR_UNDO_REDO_MANAGER (manager));
+
+ manager->priv->operation_in_progress = value;
+}
+
+static void
+free_history_event_content (EEditorHistoryEvent *event)
+{
+ switch (event->type) {
+ case HISTORY_INPUT:
+ case HISTORY_DELETE:
+ case HISTORY_CITATION_SPLIT:
+ case HISTORY_IMAGE:
+ case HISTORY_SMILEY:
+ case HISTORY_REMOVE_LINK:
+ if (event->data.fragment != NULL)
+ g_clear_object (&event->data.fragment);
+ break;
+ case HISTORY_FONT_COLOR:
+ case HISTORY_PASTE:
+ case HISTORY_PASTE_AS_TEXT:
+ case HISTORY_PASTE_QUOTED:
+ case HISTORY_INSERT_HTML:
+ case HISTORY_REPLACE:
+ case HISTORY_REPLACE_ALL:
+ if (event->data.string.from != NULL)
+ g_free (event->data.string.from);
+ if (event->data.string.to != NULL)
+ g_free (event->data.string.to);
+ break;
+ case HISTORY_HRULE_DIALOG:
+ case HISTORY_IMAGE_DIALOG:
+ case HISTORY_CELL_DIALOG:
+ case HISTORY_TABLE_DIALOG:
+ case HISTORY_TABLE_INPUT:
+ case HISTORY_PAGE_DIALOG:
+ case HISTORY_UNQUOTE:
+ case HISTORY_LINK_DIALOG:
+ if (event->data.dom.from != NULL)
+ g_clear_object (&event->data.dom.from);
+ if (event->data.dom.to != NULL)
+ g_clear_object (&event->data.dom.to);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+free_history_event (EEditorHistoryEvent *event)
+{
+ if (event == NULL)
+ return;
+
+ free_history_event_content (event);
+
+ g_free (event);
+}
+
+static void
+remove_history_event (EEditorUndoRedoManager *manager,
+ GList *item)
+{
+ free_history_event_content (item->data);
+
+ manager->priv->history = g_list_delete_link (manager->priv->history, item);
+ manager->priv->history_size--;
+}
+
+static void
+remove_forward_redo_history_events_if_needed (EEditorUndoRedoManager *manager)
+{
+ GList *history = manager->priv->history;
+ GList *item;
+
+ if (!history || !history->prev)
+ return;
+
+ item = history->prev;
+ while (item) {
+ GList *prev_item = item->prev;
+
+ remove_history_event (manager, item);
+ item = prev_item;
+ }
+}
+
+void
+e_editor_undo_redo_manager_insert_history_event (EEditorUndoRedoManager *manager,
+ EEditorHistoryEvent *event)
+{
+ g_return_if_fail (E_IS_EDITOR_UNDO_REDO_MANAGER (manager));
+
+ if (manager->priv->operation_in_progress)
+ return;
+
+ d (printf ("\nINSERTING EVENT:\n"));
+ d (print_history_event (event));
+
+ remove_forward_redo_history_events_if_needed (manager);
+
+ if (manager->priv->history_size >= HISTORY_SIZE_LIMIT) {
+ remove_history_event (manager, g_list_last (manager->priv->history)->prev);
+ /* FIXME WK2 - what if g_list_last (manager->priv->history) returns NULL? */
+ while (((EEditorHistoryEvent *) (g_list_last (manager->priv->history)->prev))->type ==
HISTORY_AND) {
+ remove_history_event (manager, g_list_last (manager->priv->history)->prev);
+ remove_history_event (manager, g_list_last (manager->priv->history)->prev);
+ }
+
+ }
+
+ manager->priv->history = g_list_prepend (manager->priv->history, event);
+ manager->priv->history_size++;
+
+ d (print_history (manager));
+
+ g_object_notify (G_OBJECT (manager), "can-undo");
+}
+
+EEditorHistoryEvent *
+e_editor_undo_redo_manager_get_current_history_event (EEditorUndoRedoManager *manager)
+{
+ g_return_val_if_fail (E_IS_EDITOR_UNDO_REDO_MANAGER (manager), NULL);
+
+ if (manager->priv->history)
+ return manager->priv->history->data;
+
+ return NULL;
+}
+
+void
+e_editor_undo_redo_manager_remove_current_history_event (EEditorUndoRedoManager *manager)
+{
+ g_return_if_fail (E_IS_EDITOR_UNDO_REDO_MANAGER (manager));
+
+ if (!manager->priv->history)
+ return;
+
+ remove_history_event (manager, manager->priv->history);
+}
+
+void
+e_editor_undo_redo_manager_insert_dash_history_event (EEditorUndoRedoManager *manager)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMDocumentFragment *fragment;
+ EEditorPage *editor_page;
+ EEditorHistoryEvent *event, *last;
+ GList *history;
+
+ g_return_if_fail (E_IS_EDITOR_UNDO_REDO_MANAGER (manager));
+
+ editor_page = editor_undo_redo_manager_ref_editor_page (manager);
+ g_return_if_fail (editor_page != NULL);
+
+ event = g_new0 (EEditorHistoryEvent, 1);
+ event->type = HISTORY_INPUT;
+
+ document = e_editor_page_get_document (editor_page);
+ fragment = webkit_dom_document_create_document_fragment (document);
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (fragment),
+ WEBKIT_DOM_NODE (
+ webkit_dom_document_create_text_node (document, "-")),
+ NULL);
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (fragment),
+ WEBKIT_DOM_NODE (
+ dom_create_selection_marker (document, TRUE)),
+ NULL);
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (fragment),
+ WEBKIT_DOM_NODE (
+ dom_create_selection_marker (document, FALSE)),
+ NULL);
+ event->data.fragment = fragment;
+
+ last = e_editor_undo_redo_manager_get_current_history_event (manager);
+ /* The dash event needs to have the same coordinates as the character
+ * that is right after it. */
+ event->after.start.x = last->after.start.x;
+ event->after.start.y = last->after.start.y;
+ event->after.end.x = last->after.end.x;
+ event->after.end.y = last->after.end.y;
+
+ history = manager->priv->history;
+ if (history) {
+ EEditorHistoryEvent *item;
+ WebKitDOMNode *first_child;
+
+ item = history->data;
+
+ if (item->type != HISTORY_INPUT) {
+ g_object_unref (editor_page);
+ return;
+ }
+
+ first_child = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (item->data.fragment));
+ if (WEBKIT_DOM_IS_TEXT (first_child)) {
+ guint diff;
+
+ diff = event->after.start.x - item->after.start.x;
+
+ /* We need to move the coordinate of the last
+ * event by one character. */
+ last->after.start.x += diff;
+ last->after.end.x += diff;
+
+ manager->priv->history = g_list_insert_before (
+ manager->priv->history, history, event);
+ }
+ }
+
+ g_object_unref (editor_page);
+}
+
+gboolean
+e_editor_undo_redo_manager_can_undo (EEditorUndoRedoManager *manager)
+{
+ g_return_val_if_fail (E_IS_EDITOR_UNDO_REDO_MANAGER (manager), FALSE);
+
+ if (manager->priv->history) {
+ EEditorHistoryEvent *event;
+
+ event = manager->priv->history->data;
+
+ return (event->type != HISTORY_START);
+ } else
+ return FALSE;
+}
+
+void
+e_editor_undo_redo_manager_undo (EEditorUndoRedoManager *manager)
+{
+ EEditorHistoryEvent *event;
+ EEditorPage *editor_page;
+ GList *history;
+
+ g_return_if_fail (E_IS_EDITOR_UNDO_REDO_MANAGER (manager));
+
+ if (!e_editor_undo_redo_manager_can_undo (manager))
+ return;
+
+ history = manager->priv->history;
+ event = history->data;
+
+ d (printf ("\nUNDOING EVENT:\n"));
+ d (print_history_event (event));
+
+ manager->priv->operation_in_progress = TRUE;
+
+ editor_page = editor_undo_redo_manager_ref_editor_page (manager);
+ g_return_if_fail (editor_page != NULL);
+
+ switch (event->type) {
+ case HISTORY_BOLD:
+ case HISTORY_ITALIC:
+ case HISTORY_STRIKETHROUGH:
+ case HISTORY_UNDERLINE:
+ case HISTORY_FONT_SIZE:
+ if (event_selection_was_collapsed (event)) {
+ if (history->next) {
+ manager->priv->history = history->next;
+ e_editor_undo_redo_manager_undo (manager);
+ }
+ manager->priv->operation_in_progress = FALSE;
+ g_object_unref (editor_page);
+ return;
+ }
+ case HISTORY_ALIGNMENT:
+ case HISTORY_BLOCK_FORMAT:
+ case HISTORY_MONOSPACE:
+ undo_redo_style_change (editor_page, event, TRUE);
+ break;
+ case HISTORY_DELETE:
+ undo_delete (editor_page, event);
+ break;
+ case HISTORY_INDENT:
+ undo_redo_indent (editor_page, event, TRUE);
+ break;
+ case HISTORY_INPUT:
+ undo_input (manager, editor_page, event);
+ break;
+ case HISTORY_REMOVE_LINK:
+ undo_redo_remove_link (editor_page, event, TRUE);
+ break;
+ case HISTORY_FONT_COLOR:
+ undo_redo_font_color (editor_page, event, TRUE);
+ break;
+ case HISTORY_CITATION_SPLIT:
+ undo_redo_citation_split (editor_page, event, TRUE);
+ break;
+ case HISTORY_PASTE:
+ case HISTORY_PASTE_AS_TEXT:
+ case HISTORY_PASTE_QUOTED:
+ case HISTORY_INSERT_HTML:
+ undo_redo_paste (editor_page, event, TRUE);
+ break;
+ case HISTORY_IMAGE:
+ case HISTORY_SMILEY:
+ undo_redo_image (editor_page, event, TRUE);
+ break;
+ case HISTORY_WRAP:
+ undo_redo_wrap (editor_page, event, TRUE);
+ break;
+ case HISTORY_IMAGE_DIALOG:
+ undo_redo_image_dialog (editor_page, event, TRUE);
+ break;
+ case HISTORY_LINK_DIALOG:
+ undo_redo_link_dialog (editor_page, event, TRUE);
+ break;
+ case HISTORY_TABLE_DIALOG:
+ undo_redo_table_dialog (editor_page, event, TRUE);
+ break;
+ case HISTORY_TABLE_INPUT:
+ undo_redo_table_input (editor_page, event, TRUE);
+ break;
+ case HISTORY_PAGE_DIALOG:
+ undo_redo_page_dialog (editor_page, event, TRUE);
+ break;
+ case HISTORY_HRULE_DIALOG:
+ undo_redo_hrule_dialog (editor_page, event, TRUE);
+ break;
+ case HISTORY_REPLACE:
+ case HISTORY_REPLACE_ALL:
+ undo_redo_replace_all (manager, editor_page, event, TRUE);
+ break;
+ case HISTORY_UNQUOTE:
+ undo_redo_unquote (editor_page, event, TRUE);
+ break;
+ case HISTORY_AND:
+ g_warning ("Unhandled HISTORY_AND event!");
+ break;
+ default:
+ g_object_unref (editor_page);
+ return;
+ }
+
+ /* FIXME WK2 - history->next can be NULL! */
+ event = history->next->data;
+ if (event->type == HISTORY_AND) {
+ manager->priv->history = history->next->next;
+ e_editor_undo_redo_manager_undo (manager);
+ g_object_unref (editor_page);
+ return;
+ }
+
+ if (history->next)
+ manager->priv->history = manager->priv->history->next;
+
+ d (print_undo_events (manager));
+/* FIXME WK2
+ html_editor_view_user_changed_contents_cb (view);*/
+
+ manager->priv->operation_in_progress = FALSE;
+
+ g_object_unref (editor_page);
+
+ g_object_notify (G_OBJECT (manager), "can-undo");
+ g_object_notify (G_OBJECT (manager), "can-redo");
+}
+
+gboolean
+e_editor_undo_redo_manager_can_redo (EEditorUndoRedoManager *manager)
+{
+ g_return_val_if_fail (E_IS_EDITOR_UNDO_REDO_MANAGER (manager), FALSE);
+
+ if (manager->priv->history && manager->priv->history->prev)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+void
+e_editor_undo_redo_manager_redo (EEditorUndoRedoManager *manager)
+{
+ EEditorPage *editor_page;
+ EEditorHistoryEvent *event;
+ GList *history;
+
+ if (!e_editor_undo_redo_manager_can_redo (manager))
+ return;
+
+ history = manager->priv->history;
+ event = history->prev->data;
+
+ d (printf ("\nREDOING EVENT:\n"));
+ d (print_history_event (event));
+
+ editor_page = editor_undo_redo_manager_ref_editor_page (manager);
+ g_return_if_fail (editor_page != NULL);
+
+ manager->priv->operation_in_progress = TRUE;
+
+ switch (event->type) {
+ case HISTORY_BOLD:
+ case HISTORY_MONOSPACE:
+ case HISTORY_STRIKETHROUGH:
+ case HISTORY_UNDERLINE:
+ case HISTORY_ALIGNMENT:
+ case HISTORY_BLOCK_FORMAT:
+ case HISTORY_FONT_SIZE:
+ case HISTORY_ITALIC:
+ undo_redo_style_change (editor_page, event, FALSE);
+ break;
+ case HISTORY_DELETE:
+ redo_delete (editor_page, event);
+ break;
+ case HISTORY_INDENT:
+ undo_redo_indent (editor_page, event, FALSE);
+ break;
+ case HISTORY_INPUT:
+ undo_delete (editor_page, event);
+ e_editor_dom_check_magic_smileys (editor_page);
+ {
+ gchar *text_content;
+ WebKitDOMNode *first_child;
+
+ first_child = webkit_dom_node_get_first_child (
+ WEBKIT_DOM_NODE (event->data.fragment));
+ text_content = webkit_dom_node_get_text_content (first_child);
+ /* Call magic links when the space was pressed. */
+ if (g_str_has_prefix (text_content, UNICODE_NBSP)) {
+ e_editor_page_set_space_key_pressed (editor_page, TRUE);
+ e_editor_dom_check_magic_links (editor_page, FALSE);
+ e_editor_page_set_space_key_pressed (editor_page, FALSE);
+ }
+ g_free (text_content);
+ }
+ break;
+ case HISTORY_REMOVE_LINK:
+ undo_redo_remove_link (editor_page, event, FALSE);
+ break;
+ case HISTORY_FONT_COLOR:
+ undo_redo_font_color (editor_page, event, FALSE);
+ break;
+ case HISTORY_CITATION_SPLIT:
+ undo_redo_citation_split (editor_page, event, FALSE);
+ break;
+ case HISTORY_PASTE:
+ case HISTORY_PASTE_AS_TEXT:
+ case HISTORY_PASTE_QUOTED:
+ case HISTORY_INSERT_HTML:
+ undo_redo_paste (editor_page, event, FALSE);
+ break;
+ case HISTORY_IMAGE:
+ case HISTORY_SMILEY:
+ undo_redo_image (editor_page, event, FALSE);
+ break;
+ case HISTORY_WRAP:
+ undo_redo_wrap (editor_page, event, FALSE);
+ break;
+ case HISTORY_IMAGE_DIALOG:
+ undo_redo_image_dialog (editor_page, event, FALSE);
+ break;
+ case HISTORY_LINK_DIALOG:
+ undo_redo_link_dialog (editor_page, event, FALSE);
+ break;
+ case HISTORY_TABLE_DIALOG:
+ undo_redo_table_dialog (editor_page, event, FALSE);
+ break;
+ case HISTORY_TABLE_INPUT:
+ undo_redo_table_input (editor_page, event, FALSE);
+ break;
+ case HISTORY_PAGE_DIALOG:
+ undo_redo_page_dialog (editor_page, event, FALSE);
+ break;
+ case HISTORY_HRULE_DIALOG:
+ undo_redo_hrule_dialog (editor_page, event, FALSE);
+ break;
+ case HISTORY_REPLACE:
+ case HISTORY_REPLACE_ALL:
+ undo_redo_replace_all (manager, editor_page, event, FALSE);
+ break;
+ case HISTORY_UNQUOTE:
+ undo_redo_unquote (editor_page, event, FALSE);
+ break;
+ case HISTORY_AND:
+ g_warning ("Unhandled HISTORY_AND event!");
+ break;
+ default:
+ g_object_unref (editor_page);
+ return;
+ }
+
+ /* FIXME WK2 - what if history->prev is NULL? */
+ if (history->prev->prev) {
+ event = history->prev->prev->data;
+ if (event->type == HISTORY_AND) {
+ manager->priv->history = manager->priv->history->prev->prev;
+ e_editor_undo_redo_manager_redo (manager);
+ g_object_unref (editor_page);
+ return;
+ }
+ }
+
+ manager->priv->history = manager->priv->history->prev;
+
+ d (print_redo_events (manager));
+/* FIXME WK2
+ html_editor_view_user_changed_contents_cb (view);*/
+
+ manager->priv->operation_in_progress = FALSE;
+
+ g_object_unref (editor_page);
+
+ g_object_notify (G_OBJECT (manager), "can-undo");
+ g_object_notify (G_OBJECT (manager), "can-redo");
+}
+
+void
+e_editor_undo_redo_manager_clean_history (EEditorUndoRedoManager *manager)
+{
+ EEditorPage *editor_page;
+ EEditorHistoryEvent *ev;
+
+ g_return_if_fail (E_IS_EDITOR_UNDO_REDO_MANAGER (manager));
+
+ if (manager->priv->history != NULL) {
+ g_list_free_full (manager->priv->history, (GDestroyNotify) free_history_event);
+ manager->priv->history = NULL;
+ }
+
+ manager->priv->history_size = 0;
+ editor_page = editor_undo_redo_manager_ref_editor_page (manager);
+ g_return_if_fail (editor_page != NULL);
+ e_editor_page_set_dont_save_history_in_body_input (editor_page, FALSE);
+ g_object_unref (editor_page);
+ manager->priv->operation_in_progress = FALSE;
+
+ ev = g_new0 (EEditorHistoryEvent, 1);
+ ev->type = HISTORY_START;
+ manager->priv->history = g_list_append (manager->priv->history, ev);
+
+ g_object_notify (G_OBJECT (manager), "can-undo");
+ g_object_notify (G_OBJECT (manager), "can-redo");
+}
+
+static void
+editor_undo_redo_manager_set_editor_page (EEditorUndoRedoManager *manager,
+ EEditorPage *editor_page)
+{
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ g_weak_ref_set (&manager->priv->editor_page, editor_page);
+}
+
+static void
+editor_undo_redo_manager_dispose (GObject *object)
+{
+ EEditorUndoRedoManagerPrivate *priv;
+
+ priv = E_EDITOR_UNDO_REDO_MANAGER_GET_PRIVATE (object);
+
+ if (priv->history != NULL) {
+ g_list_free_full (priv->history, (GDestroyNotify) free_history_event);
+ priv->history = NULL;
+ }
+
+ g_weak_ref_set (&priv->editor_page, NULL);
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (e_editor_undo_redo_manager_parent_class)->dispose (object);
+}
+
+static void
+editor_undo_redo_manager_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_CAN_REDO:
+ g_value_set_boolean (
+ value, e_editor_undo_redo_manager_can_redo (
+ E_EDITOR_UNDO_REDO_MANAGER (object)));
+ return;
+
+ case PROP_CAN_UNDO:
+ g_value_set_boolean (
+ value, e_editor_undo_redo_manager_can_undo (
+ E_EDITOR_UNDO_REDO_MANAGER (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+editor_undo_redo_manager_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_EDITOR_PAGE:
+ editor_undo_redo_manager_set_editor_page (
+ E_EDITOR_UNDO_REDO_MANAGER (object),
+ g_value_get_object (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+e_editor_undo_redo_manager_class_init (EEditorUndoRedoManagerClass *class)
+{
+ GObjectClass *object_class;
+
+ g_type_class_add_private (class, sizeof (EEditorUndoRedoManagerPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->dispose = editor_undo_redo_manager_dispose;
+ object_class->get_property = editor_undo_redo_manager_get_property;
+ object_class->set_property = editor_undo_redo_manager_set_property;
+
+ /**
+ * EEditorUndoRedoManager:can-redo
+ *
+ * Determines whether it's possible to redo previous action. The action
+ * is usually disabled when there is no action to redo.
+ */
+ g_object_class_install_property (
+ object_class,
+ PROP_CAN_REDO,
+ g_param_spec_boolean (
+ "can-redo",
+ "Can Redo",
+ NULL,
+ FALSE,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * EEditorUndoRedoManager:can-undo
+ *
+ * Determines whether it's possible to undo last action. The action
+ * is usually disabled when there is no previous action to undo.
+ */
+ g_object_class_install_property (
+ object_class,
+ PROP_CAN_UNDO,
+ g_param_spec_boolean (
+ "can-undo",
+ "Can Undo",
+ NULL,
+ FALSE,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_EDITOR_PAGE,
+ g_param_spec_object (
+ "editor-page",
+ NULL,
+ NULL,
+ E_TYPE_EDITOR_PAGE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+}
+
+static void
+e_editor_undo_redo_manager_init (EEditorUndoRedoManager *manager)
+{
+ manager->priv = E_EDITOR_UNDO_REDO_MANAGER_GET_PRIVATE (manager);
+
+ manager->priv->operation_in_progress = FALSE;
+ manager->priv->history = NULL;
+ manager->priv->history_size = 0;
+}
diff --git a/modules/webkit-editor/web-extension/e-editor-undo-redo-manager.h
b/modules/webkit-editor/web-extension/e-editor-undo-redo-manager.h
new file mode 100644
index 0000000..60dabaf
--- /dev/null
+++ b/modules/webkit-editor/web-extension/e-editor-undo-redo-manager.h
@@ -0,0 +1,175 @@
+/*
+ * e-editor-undo-redo-manager.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/>
+ *
+ */
+
+#ifndef E_EDITOR_UNDO_REDO_MANAGER_H
+#define E_EDITOR_UNDO_REDO_MANAGER_H
+
+#include <glib-object.h>
+#include <webkitdom/webkitdom.h>
+
+#define E_TYPE_EDITOR_UNDO_REDO_MANAGER \
+ (e_editor_undo_redo_manager_get_type ())
+#define E_EDITOR_UNDO_REDO_MANAGER(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_EDITOR_UNDO_REDO_MANAGER, EEditorUndoRedoManager))
+#define E_EDITOR_UNDO_REDO_MANAGER_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_EDITOR_UNDO_REDO_MANAGER, EEditorUndoRedoManagerClass))
+#define E_IS_EDITOR_UNDO_REDO_MANAGER(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_EDITOR_UNDO_REDO_MANAGER))
+#define E_IS_EDITOR_UNDO_REDO_MANAGER_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_EDITOR_UNDO_REDO_MANAGER))
+#define E_EDITOR_UNDO_REDO_MANAGER_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_EDITOR_UNDO_REDO_MANAGER, EEditorUndoRedoManagerClass))
+
+G_BEGIN_DECLS
+
+struct _EEditorPage;
+
+enum EEditorHistoryEventType {
+ HISTORY_ALIGNMENT,
+ HISTORY_AND,
+ HISTORY_BLOCK_FORMAT,
+ HISTORY_BOLD,
+ HISTORY_CELL_DIALOG,
+ HISTORY_DELETE, /* BackSpace, Delete, with and without selection */
+ HISTORY_FONT_COLOR,
+ HISTORY_FONT_SIZE,
+ HISTORY_HRULE_DIALOG,
+ HISTORY_INDENT,
+ HISTORY_INPUT,
+ HISTORY_IMAGE,
+ HISTORY_IMAGE_DIALOG,
+ HISTORY_INSERT_HTML,
+ HISTORY_ITALIC,
+ HISTORY_LINK_DIALOG,
+ HISTORY_MONOSPACE,
+ HISTORY_PAGE_DIALOG,
+ HISTORY_PASTE,
+ HISTORY_PASTE_AS_TEXT,
+ HISTORY_PASTE_QUOTED,
+ HISTORY_REMOVE_LINK,
+ HISTORY_REPLACE,
+ HISTORY_REPLACE_ALL,
+ HISTORY_CITATION_SPLIT,
+ HISTORY_SMILEY,
+ HISTORY_START, /* Start of history */
+ HISTORY_STRIKETHROUGH,
+ HISTORY_TABLE_DIALOG,
+ HISTORY_TABLE_INPUT,
+ HISTORY_UNDERLINE,
+ HISTORY_WRAP,
+ HISTORY_UNQUOTE
+};
+
+typedef struct {
+ gint from; /* From what format we are changing. */
+ gint to; /* To what format we are changing. */
+} EEditorStyleChange;
+
+/* This is used for e-html-editor-*-dialogs */
+typedef struct {
+ WebKitDOMNode *from; /* From what node we are changing. */
+ WebKitDOMNode *to; /* To what node we are changing. */
+} EEditorDOMChange;
+
+typedef struct {
+ gchar *from; /* From what format we are changing. */
+ gchar *to; /* To what format we are changing. */
+} EEditorStringChange;
+
+typedef struct {
+ guint x;
+ guint y;
+} EEditorSelectionPoint;
+
+typedef struct {
+ EEditorSelectionPoint start;
+ EEditorSelectionPoint end;
+} EEditorSelection;
+
+typedef struct {
+ enum EEditorHistoryEventType type;
+ EEditorSelection before;
+ EEditorSelection after;
+ union {
+ WebKitDOMDocumentFragment *fragment;
+ EEditorStyleChange style;
+ EEditorStringChange string;
+ EEditorDOMChange dom;
+ } data;
+} EEditorHistoryEvent;
+
+typedef struct _EEditorUndoRedoManager EEditorUndoRedoManager;
+typedef struct _EEditorUndoRedoManagerClass EEditorUndoRedoManagerClass;
+typedef struct _EEditorUndoRedoManagerPrivate EEditorUndoRedoManagerPrivate;
+
+struct _EEditorUndoRedoManager {
+ GObject parent;
+ EEditorUndoRedoManagerPrivate *priv;
+};
+
+struct _EEditorUndoRedoManagerClass
+{
+ GObjectClass parent_class;
+};
+
+GType e_editor_undo_redo_manager_get_type
+ (void) G_GNUC_CONST;
+
+EEditorUndoRedoManager *
+ e_editor_undo_redo_manager_new (struct _EEditorPage *editor_page);
+gboolean e_editor_undo_redo_manager_is_operation_in_progress
+ (EEditorUndoRedoManager *manager);
+
+void e_editor_undo_redo_manager_set_operation_in_progress
+ (EEditorUndoRedoManager *manager,
+ gboolean value);
+
+void e_editor_undo_redo_manager_insert_history_event
+ (EEditorUndoRedoManager *manager,
+ EEditorHistoryEvent *event);
+
+EEditorHistoryEvent *
+ e_editor_undo_redo_manager_get_current_history_event
+ (EEditorUndoRedoManager *manager);
+void e_editor_undo_redo_manager_remove_current_history_event
+ (EEditorUndoRedoManager *manager);
+
+void e_editor_undo_redo_manager_insert_dash_history_event
+ (EEditorUndoRedoManager *manager);
+
+gboolean e_editor_undo_redo_manager_can_undo
+ (EEditorUndoRedoManager *manager);
+
+void e_editor_undo_redo_manager_undo (EEditorUndoRedoManager *manager);
+
+gboolean e_editor_undo_redo_manager_can_redo
+ (EEditorUndoRedoManager *manager);
+
+void e_editor_undo_redo_manager_redo (EEditorUndoRedoManager *manager);
+
+void e_editor_undo_redo_manager_clean_history
+ (EEditorUndoRedoManager *manager);
+
+G_END_DECLS
+
+#endif /* E_EDITOR_UNDO_REDO_MANAGER_H */
diff --git a/modules/webkit-editor/web-extension/e-editor-web-extension-main.c
b/modules/webkit-editor/web-extension/e-editor-web-extension-main.c
new file mode 100644
index 0000000..244bc4c
--- /dev/null
+++ b/modules/webkit-editor/web-extension/e-editor-web-extension-main.c
@@ -0,0 +1,57 @@
+/*
+ * e-html-editor-web-extension-main.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/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <camel/camel.h>
+
+#include "e-editor-web-extension.h"
+
+static void
+bus_acquired_cb (GDBusConnection *connection,
+ const gchar *name,
+ EEditorWebExtension *extension)
+{
+ e_editor_web_extension_dbus_register (extension, connection);
+}
+
+/* Forward declaration */
+G_MODULE_EXPORT void webkit_web_extension_initialize (WebKitWebExtension *wk_extension);
+
+G_MODULE_EXPORT void
+webkit_web_extension_initialize (WebKitWebExtension *wk_extension)
+{
+ EEditorWebExtension *extension;
+
+ camel_debug_init ();
+
+ extension = e_editor_web_extension_get_default ();
+ e_editor_web_extension_initialize (extension, wk_extension);
+
+ g_bus_own_name (
+ G_BUS_TYPE_SESSION,
+ E_WEBKIT_EDITOR_WEB_EXTENSION_SERVICE_NAME,
+ G_BUS_NAME_OWNER_FLAGS_NONE,
+ (GBusAcquiredCallback) bus_acquired_cb,
+ NULL, /* GBusNameAcquiredCallback */
+ NULL, /* GBusNameLostCallback */
+ g_object_ref (extension),
+ (GDestroyNotify) g_object_unref);
+}
diff --git a/modules/webkit-editor/web-extension/e-editor-web-extension-names.h
b/modules/webkit-editor/web-extension/e-editor-web-extension-names.h
new file mode 100644
index 0000000..d1b5f02
--- /dev/null
+++ b/modules/webkit-editor/web-extension/e-editor-web-extension-names.h
@@ -0,0 +1,26 @@
+/*
+ * e-editor-web-extension-names.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/>
+ *
+ */
+
+#ifndef E_EDITOR_WEB_EXTENSION_NAMES_H
+#define E_EDITOR_WEB_EXTENSION_NAMES_H
+
+#define E_WEBKIT_EDITOR_WEB_EXTENSION_SERVICE_NAME "org.gnome.Evolution.WebExtension.EWebKitEditor"
+#define E_WEBKIT_EDITOR_WEB_EXTENSION_OBJECT_PATH "/org/gnome/Evolution/WebExtension/EWebKitEditor"
+#define E_WEBKIT_EDITOR_WEB_EXTENSION_INTERFACE "org.gnome.Evolution.WebExtension.EWebKitEditor"
+
+#endif /* E_EDITOR_WEB_EXTENSION_NAMES_H */
diff --git a/modules/webkit-editor/web-extension/e-editor-web-extension.c
b/modules/webkit-editor/web-extension/e-editor-web-extension.c
new file mode 100644
index 0000000..f387e26
--- /dev/null
+++ b/modules/webkit-editor/web-extension/e-editor-web-extension.c
@@ -0,0 +1,2501 @@
+/*
+ * e-editor-web-extension.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/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include <glib/gstdio.h>
+#include <gio/gio.h>
+#include <gtk/gtk.h>
+#include <webkit2/webkit-web-extension.h>
+#include <camel/camel.h>
+
+#include "web-extensions/e-dom-utils.h"
+
+#include "e-editor-page.h"
+#include "e-composer-dom-functions.h"
+#include "e-dialogs-dom-functions.h"
+#include "e-editor-dom-functions.h"
+#include "e-editor-undo-redo-manager.h"
+
+#include "e-editor-web-extension.h"
+
+#define E_EDITOR_WEB_EXTENSION_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_EDITOR_WEB_EXTENSION, EEditorWebExtensionPrivate))
+
+struct _EEditorWebExtensionPrivate {
+ WebKitWebExtension *wk_extension;
+
+ GDBusConnection *dbus_connection;
+ guint registration_id;
+
+ GHashTable *editor_pages; /* guint64 *webpage_id ~> EEditorPage * */
+};
+
+static CamelDataCache *emd_global_http_cache = NULL;
+
+static const gchar *introspection_xml =
+"<node>"
+" <interface name='" E_WEBKIT_EDITOR_WEB_EXTENSION_INTERFACE "'>"
+"<!-- ********************************************************* -->"
+"<!-- SIGNALS -->"
+"<!-- ********************************************************* -->"
+" <signal name='SelectionChanged'>"
+" <arg type='t' name='page_id' direction='out'/>"
+" <arg type='i' name='alignment' direction='out'/>"
+" <arg type='i' name='block_format' direction='out'/>"
+" <arg type='b' name='indented' direction='out'/>"
+" <arg type='i' name='style_flags' direction='out'/>"
+" <arg type='i' name='font_size' direction='out'/>"
+" <arg type='s' name='font_color' direction='out'/>"
+" </signal>"
+" <signal name='ContentChanged'>"
+" <arg type='t' name='page_id' direction='out'/>"
+" </signal>"
+" <signal name='UndoRedoStateChanged'>"
+" <arg type='t' name='page_id' direction='out'/>"
+" <arg type='b' name='can_undo' direction='out'/>"
+" <arg type='b' name='can_redo' direction='out'/>"
+" </signal>"
+"<!-- ********************************************************* -->"
+"<!-- METHODS -->"
+"<!-- ********************************************************* -->"
+"<!-- ********************************************************* -->"
+"<!-- FOR TESTING ONLY -->"
+"<!-- ********************************************************* -->"
+" <method name='TestHTMLEqual'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='html1' direction='in'/>"
+" <arg type='s' name='html2' direction='in'/>"
+" <arg type='b' name='equal' direction='out'/>"
+" </method>"
+"<!-- ********************************************************* -->"
+"<!-- GENERIC -->"
+"<!-- ********************************************************* -->"
+" <method name='ElementHasAttribute'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='element_id' direction='in'/>"
+" <arg type='s' name='attribute' direction='in'/>"
+" <arg type='b' name='has_attribute' direction='out'/>"
+" </method>"
+" <method name='ElementGetAttribute'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='element_id' direction='in'/>"
+" <arg type='s' name='attribute' direction='in'/>"
+" <arg type='s' name='value' direction='out'/>"
+" </method>"
+" <method name='ElementGetAttributeBySelector'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='selector' direction='in'/>"
+" <arg type='s' name='attribute' direction='in'/>"
+" <arg type='s' name='value' direction='out'/>"
+" </method>"
+" <method name='ElementRemoveAttribute'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='element_id' direction='in'/>"
+" <arg type='s' name='attribute' direction='in'/>"
+" </method>"
+" <method name='ElementRemoveAttributeBySelector'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='selector' direction='in'/>"
+" <arg type='s' name='attribute' direction='in'/>"
+" </method>"
+" <method name='ElementSetAttribute'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='element_id' direction='in'/>"
+" <arg type='s' name='attribute' direction='in'/>"
+" <arg type='s' name='value' direction='in'/>"
+" </method>"
+" <method name='ElementSetAttributeBySelector'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='selector' direction='in'/>"
+" <arg type='s' name='attribute' direction='in'/>"
+" <arg type='s' name='value' direction='in'/>"
+" </method>"
+" <method name='ElementGetTagName'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='element_id' direction='in'/>"
+" <arg type='s' name='tag_name' direction='out'/>"
+" </method>"
+"<!-- ********************************************************* -->"
+"<!-- Functions that are specific to composer -->"
+"<!-- ********************************************************* -->"
+" <method name='RemoveImageAttributesFromElementBySelector'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='selector' direction='in'/>"
+" </method>"
+"<!-- ********************************************************* -->"
+"<!-- Functions that are used in EEditorCellDialog -->"
+"<!-- ********************************************************* -->"
+" <method name='EEditorCellDialogMarkCurrentCellElement'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='element_id' direction='in'/>"
+" </method>"
+" <method name='EEditorCellDialogSaveHistoryOnExit'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" </method>"
+" <method name='EEditorCellDialogSetElementVAlign'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='value' direction='in'/>"
+" <arg type='i' name='scope' direction='in'/>"
+" </method>"
+" <method name='EEditorCellDialogSetElementAlign'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='value' direction='in'/>"
+" <arg type='i' name='scope' direction='in'/>"
+" </method>"
+" <method name='EEditorCellDialogSetElementNoWrap'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='b' name='value' direction='in'/>"
+" <arg type='i' name='scope' direction='in'/>"
+" </method>"
+" <method name='EEditorCellDialogSetElementHeaderStyle'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='b' name='value' direction='in'/>"
+" <arg type='i' name='scope' direction='in'/>"
+" </method>"
+" <method name='EEditorCellDialogSetElementWidth'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='value' direction='in'/>"
+" <arg type='i' name='scope' direction='in'/>"
+" </method>"
+" <method name='EEditorCellDialogSetElementColSpan'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='i' name='value' direction='in'/>"
+" <arg type='i' name='scope' direction='in'/>"
+" </method>"
+" <method name='EEditorCellDialogSetElementRowSpan'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='i' name='value' direction='in'/>"
+" <arg type='i' name='scope' direction='in'/>"
+" </method>"
+" <method name='EEditorCellDialogSetElementBgColor'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='value' direction='in'/>"
+" <arg type='i' name='scope' direction='in'/>"
+" </method>"
+"<!-- ********************************************************* -->"
+"<!-- Functions that are used in EEditorHRuleDialog -->"
+"<!-- ********************************************************* -->"
+" <method name='EEditorHRuleDialogFindHRule'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='b' name='created_new_hr' direction='out'/>"
+" </method>"
+" <method name='EEditorHRuleDialogOnClose'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" </method>"
+"<!-- ********************************************************* -->"
+"<!-- Functions that are used in EEditorImageDialog -->"
+"<!-- ********************************************************* -->"
+" <method name='EEditorImageDialogMarkImage'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" </method>"
+" <method name='EEditorImageDialogSaveHistoryOnExit'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" </method>"
+" <method name='EEditorImageDialogSetElementUrl'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='value' direction='in'/>"
+" </method>"
+" <method name='EEditorImageDialogGetElementUrl'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='value' direction='out'/>"
+" </method>"
+" <method name='ImageElementSetWidth'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='element_id' direction='in'/>"
+" <arg type='i' name='value' direction='in'/>"
+" </method>"
+" <method name='ImageElementGetWidth'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='element_id' direction='in'/>"
+" <arg type='i' name='value' direction='out'/>"
+" </method>"
+" <method name='ImageElementSetHeight'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='element_id' direction='in'/>"
+" <arg type='i' name='value' direction='in'/>"
+" </method>"
+" <method name='ImageElementGetHeight'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='element_id' direction='in'/>"
+" <arg type='i' name='value' direction='out'/>"
+" </method>"
+" <method name='ImageElementGetNaturalWidth'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='element_id' direction='in'/>"
+" <arg type='i' name='value' direction='out'/>"
+" </method>"
+" <method name='ImageElementGetNaturalHeight'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='element_id' direction='in'/>"
+" <arg type='i' name='value' direction='out'/>"
+" </method>"
+" <method name='ImageElementSetHSpace'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='element_id' direction='in'/>"
+" <arg type='i' name='value' direction='in'/>"
+" </method>"
+" <method name='ImageElementGetHSpace'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='element_id' direction='in'/>"
+" <arg type='i' name='value' direction='out'/>"
+" </method>"
+" <method name='ImageElementSetVSpace'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='element_id' direction='in'/>"
+" <arg type='i' name='value' direction='in'/>"
+" </method>"
+" <method name='ImageElementGetVSpace'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='element_id' direction='in'/>"
+" <arg type='i' name='value' direction='out'/>"
+" </method>"
+"<!-- ********************************************************* -->"
+"<!-- Functions that are used in EEditorLinkDialog -->"
+"<!-- ********************************************************* -->"
+" <method name='EEditorLinkDialogOk'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='url' direction='in'/>"
+" <arg type='s' name='inner_text' direction='in'/>"
+" </method>"
+" <method name='EEditorLinkDialogShow'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='url' direction='out'/>"
+" <arg type='s' name='inner_text' direction='out'/>"
+" </method>"
+" <method name='EEditorLinkDialogOnOpen'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" </method>"
+" <method name='EEditorLinkDialogOnClose'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" </method>"
+" <method name='EEditorLinkDialogUnlink'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" </method>"
+"<!-- ********************************************************* -->"
+"<!-- Functions that are used in EEditorPageDialog -->"
+"<!-- ********************************************************* -->"
+" <method name='EEditorPageDialogSaveHistory'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" </method>"
+" <method name='EEditorPageDialogSaveHistoryOnExit'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" </method>"
+"<!-- ********************************************************* -->"
+"<!-- Functions that are used in EEditorSpellCheckDialog -->"
+"<!-- ********************************************************* -->"
+" <method name='EEditorSpellCheckDialogNext'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='word' direction='in'/>"
+" <arg type='as' name='languages' direction='in'/>"
+" <arg type='s' name='next_word' direction='out'/>"
+" </method>"
+" <method name='EEditorSpellCheckDialogPrev'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='word' direction='in'/>"
+" <arg type='as' name='languages' direction='in'/>"
+" <arg type='s' name='prev_word' direction='out'/>"
+" </method>"
+"<!-- ********************************************************* -->"
+"<!-- Functions that are used in EEditorTableDialog -->"
+"<!-- ********************************************************* -->"
+" <method name='EEditorTableDialogSetRowCount'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='u' name='value' direction='in'/>"
+" </method>"
+" <method name='EEditorTableDialogGetRowCount'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='u' name='value' direction='out'/>"
+" </method>"
+" <method name='EEditorTableDialogSetColumnCount'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='u' name='value' direction='in'/>"
+" </method>"
+" <method name='EEditorTableDialogGetColumnCount'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='u' name='value' direction='out'/>"
+" </method>"
+" <method name='EEditorTableDialogShow'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='b' name='created_new_table' direction='out'/>"
+" </method>"
+" <method name='EEditorTableDialogSaveHistoryOnExit'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" </method>"
+"<!-- ********************************************************* -->"
+"<!-- Functions that are used in EEditorActions -->"
+"<!-- ********************************************************* -->"
+" <method name='TableCellElementGetNoWrap'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='element_id' direction='in'/>"
+" <arg type='b' name='no_wrap' direction='out'/>"
+" </method>"
+" <method name='TableCellElementGetRowSpan'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='element_id' direction='in'/>"
+" <arg type='i' name='row_span' direction='out'/>"
+" </method>"
+" <method name='TableCellElementGetColSpan'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='element_id' direction='in'/>"
+" <arg type='i' name='col_span' direction='out'/>"
+" </method>"
+" <method name='EEditorDialogDeleteCellContents'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" </method>"
+" <method name='EEditorDialogDeleteColumn'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" </method>"
+" <method name='EEditorDialogDeleteRow'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" </method>"
+" <method name='EEditorDialogDeleteTable'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" </method>"
+" <method name='EEditorDialogInsertColumnAfter'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" </method>"
+" <method name='EEditorDialogInsertColumnBefore'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" </method>"
+" <method name='EEditorDialogInsertRowAbove'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" </method>"
+" <method name='EEditorDialogInsertRowBelow'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" </method>"
+" <method name='EEditorActionsSaveHistoryForCut'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" </method>"
+"<!-- ********************************************************* -->"
+"<!-- Functions that are used in EEditorView -->"
+"<!-- ********************************************************* -->"
+" <method name='SetPastingContentFromItself'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='b' name='value' direction='in'/>"
+" </method>"
+" <method name='SetEditorHTMLMode'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='b' name='html_mode' direction='in'/>"
+" <arg type='b' name='convert' direction='in'/>"
+" </method>"
+" <method name='SetConvertInSitu'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='b' name='value' direction='in'/>"
+" </method>"
+" <method name='DOMForceSpellCheck'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" </method>"
+" <method name='DOMTurnSpellCheckOff'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" </method>"
+" <method name='DOMScrollToCaret'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" </method>"
+" <method name='DOMEmbedStyleSheet'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='style_sheet_content' direction='in'/>"
+" </method>"
+" <method name='DOMRemoveEmbeddedStyleSheet'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" </method>"
+" <method name='DOMSaveSelection'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" </method>"
+" <method name='DOMRestoreSelection'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" </method>"
+" <method name='DOMUndo'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" </method>"
+" <method name='DOMRedo'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" </method>"
+" <method name='DOMQuoteAndInsertTextIntoSelection'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='text' direction='in'/>"
+" <arg type='b' name='is_html' direction='in'/>"
+" </method>"
+" <method name='DOMConvertAndInsertHTMLIntoSelection'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='text' direction='in'/>"
+" <arg type='b' name='is_html' direction='in'/>"
+" </method>"
+" <method name='DOMCheckIfConversionNeeded'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='b' name='conversion_needed' direction='out'/>"
+" </method>"
+" <method name='DOMGetContent'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='from_domain' direction='in'/>"
+" <arg type='i' name='flags' direction='in'/>"
+" <arg type='s' name='content' direction='out'/>"
+" <arg type='v' name='inline_images' direction='out'/>"
+" </method>"
+" <method name='DOMInsertHTML'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='html' direction='in'/>"
+" </method>"
+" <method name='DOMConvertContent'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='preffered_text' direction='in'/>"
+" </method>"
+" <method name='DOMAddNewInlineImageIntoList'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='filename' direction='in'/>"
+" <arg type='s' name='cid_src' direction='in'/>"
+" <arg type='s' name='src' direction='in'/>"
+" </method>"
+" <method name='DOMReplaceImageSrc'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='selector' direction='in'/>"
+" <arg type='s' name='uri' direction='in'/>"
+" </method>"
+" <method name='DOMDragAndDropEnd'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" </method>"
+" <method name='DOMMoveSelectionOnPoint'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='i' name='x' direction='in'/>"
+" <arg type='i' name='y' direction='in'/>"
+" <arg type='b' name='cancel_if_not_collapsed' direction='in'/>"
+" </method>"
+" <method name='DOMInsertSmiley'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='smiley_name' direction='in'/>"
+" </method>"
+"<!-- ********************************************************* -->"
+"<!-- Functions that are used in EEditorSelection -->"
+"<!-- ********************************************************* -->"
+" <method name='DOMSelectionIndent'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" </method>"
+" <method name='DOMSelectionInsertImage'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='uri' direction='in'/>"
+" </method>"
+" <method name='DOMSelectionReplace'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='replacement' direction='in'/>"
+" </method>"
+" <method name='DOMSelectionSetAlignment'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='i' name='alignment' direction='in'/>"
+" </method>"
+" <method name='DOMSelectionSetBold'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='b' name='bold' direction='in'/>"
+" </method>"
+" <method name='DOMSelectionSetBlockFormat'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='i' name='block_format' direction='in'/>"
+" </method>"
+" <method name='DOMSelectionSetFontColor'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='color' direction='in'/>"
+" </method>"
+" <method name='DOMSelectionSetFontSize'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='i' name='font_size' direction='in'/>"
+" </method>"
+" <method name='DOMSelectionSetItalic'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='b' name='italic' direction='in'/>"
+" </method>"
+" <method name='DOMSelectionSetMonospaced'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='b' name='monospaced' direction='in'/>"
+" </method>"
+" <method name='DOMSelectionSetStrikethrough'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='b' name='strikethrough' direction='in'/>"
+" </method>"
+" <method name='DOMSelectionSetSubscript'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='b' name='subscript' direction='in'/>"
+" </method>"
+" <method name='DOMSelectionSetSuperscript'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='b' name='superscript' direction='in'/>"
+" </method>"
+" <method name='DOMSelectionSetUnderline'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='b' name='underline' direction='in'/>"
+" </method>"
+" <method name='DOMSelectionUnindent'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" </method>"
+" <method name='DOMSelectionWrap'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" </method>"
+" <method name='DOMGetCaretWord'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='word' direction='out'/>"
+" </method>"
+"<!-- ********************************************************* -->"
+"<!-- Functions that are used in EComposerPrivate -->"
+"<!-- ********************************************************* -->"
+" <method name='DOMInsertSignature'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='content' direction='in'/>"
+" <arg type='b' name='is_html' direction='in'/>"
+" <arg type='s' name='signature_id' direction='in'/>"
+" <arg type='b' name='set_signature_from_message' direction='in'/>"
+" <arg type='b' name='check_if_signature_is_changed' direction='in'/>"
+" <arg type='b' name='ignore_next_signature_change' direction='in'/>"
+" <arg type='s' name='new_signature_id' direction='out'/>"
+" <arg type='b' name='out_set_signature_from_message' direction='out'/>"
+" <arg type='b' name='out_check_if_signature_is_changed' direction='out'/>"
+" <arg type='b' name='out_ignore_next_signature_change' direction='out'/>"
+" </method>"
+" <method name='DOMSaveDragAndDropHistory'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" </method>"
+" <method name='DOMCleanAfterDragAndDrop'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" </method>"
+"<!-- ********************************************************* -->"
+"<!-- Functions that are used in External Editor plugin -->"
+"<!-- ********************************************************* -->"
+" <method name='DOMGetCaretPosition'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='u' name='position' direction='out'/>"
+" </method>"
+" <method name='DOMGetCaretOffset'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='u' name='offset' direction='out'/>"
+" </method>"
+" <method name='DOMClearUndoRedoHistory'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" </method>"
+" </interface>"
+"</node>";
+
+G_DEFINE_TYPE (EEditorWebExtension, e_editor_web_extension, G_TYPE_OBJECT)
+
+static EEditorPage *
+get_editor_page (EEditorWebExtension *extension,
+ guint64 page_id)
+{
+ g_return_val_if_fail (E_IS_EDITOR_WEB_EXTENSION (extension), NULL);
+
+ return g_hash_table_lookup (extension->priv->editor_pages, &page_id);
+}
+
+static EEditorPage *
+get_editor_page_or_return_dbus_error (GDBusMethodInvocation *invocation,
+ EEditorWebExtension *extension,
+ guint64 page_id)
+{
+ WebKitWebPage *web_page;
+ EEditorPage *editor_page;
+
+ g_return_val_if_fail (E_IS_EDITOR_WEB_EXTENSION (extension), NULL);
+
+ web_page = webkit_web_extension_get_page (extension->priv->wk_extension, page_id);
+ if (!web_page) {
+ g_dbus_method_invocation_return_error (
+ invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
+ "Invalid page ID: %" G_GUINT64_FORMAT, page_id);
+
+ return NULL;
+ }
+
+ editor_page = get_editor_page (extension, page_id);
+ if (!editor_page) {
+ g_dbus_method_invocation_return_error (
+ invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
+ "Invalid page ID: %" G_GUINT64_FORMAT, page_id);
+ }
+
+ return editor_page;
+}
+
+static void
+handle_method_call (GDBusConnection *connection,
+ const char *sender,
+ const char *object_path,
+ const char *interface_name,
+ const char *method_name,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation,
+ gpointer user_data)
+{
+ guint64 page_id;
+ EEditorWebExtension *extension = E_EDITOR_WEB_EXTENSION (user_data);
+ WebKitDOMDocument *document;
+ EEditorPage *editor_page;
+
+ if (g_strcmp0 (interface_name, E_WEBKIT_EDITOR_WEB_EXTENSION_INTERFACE) != 0)
+ return;
+
+ if (g_strcmp0 (method_name, "TestHTMLEqual") == 0) {
+ gboolean equal = FALSE;
+ const gchar *html1 = NULL, *html2 = NULL;
+
+ g_variant_get (parameters, "(t&s&s)", &page_id, &html1, &html2);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ document = e_editor_page_get_document (editor_page);
+ equal = e_editor_dom_test_html_equal (document, html1, html2);
+
+ g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", equal));
+ } else if (g_strcmp0 (method_name, "ElementHasAttribute") == 0) {
+ gboolean value = FALSE;
+ const gchar *element_id, *attribute;
+ WebKitDOMElement *element;
+
+ g_variant_get (
+ parameters, "(t&s&s)", &page_id, &element_id, &attribute);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ document = e_editor_page_get_document (editor_page);
+ element = webkit_dom_document_get_element_by_id (document, element_id);
+ if (element)
+ value = webkit_dom_element_has_attribute (element, attribute);
+
+ g_dbus_method_invocation_return_value (
+ invocation, g_variant_new ("(b)", value));
+ } else if (g_strcmp0 (method_name, "ElementGetAttribute") == 0) {
+ const gchar *element_id, *attribute;
+ gchar *value = NULL;
+ WebKitDOMElement *element;
+
+ g_variant_get (
+ parameters, "(t&s&s)", &page_id, &element_id, &attribute);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ document = e_editor_page_get_document (editor_page);
+ element = webkit_dom_document_get_element_by_id (document, element_id);
+ if (element)
+ value = webkit_dom_element_get_attribute (element, attribute);
+
+ g_dbus_method_invocation_return_value (
+ invocation,
+ g_variant_new (
+ "(@s)",
+ g_variant_new_take_string (
+ value ? value : g_strdup (""))));
+ } else if (g_strcmp0 (method_name, "ElementGetAttributeBySelector") == 0) {
+ const gchar *attribute, *selector;
+ gchar *value = NULL;
+ WebKitDOMElement *element;
+
+ g_variant_get (
+ parameters, "(t&s&s)", &page_id, &selector, &attribute);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ document = e_editor_page_get_document (editor_page);
+ element = webkit_dom_document_query_selector (document, selector, NULL);
+ if (element)
+ value = webkit_dom_element_get_attribute (element, attribute);
+
+ g_dbus_method_invocation_return_value (
+ invocation,
+ g_variant_new (
+ "(@s)",
+ g_variant_new_take_string (
+ value ? value : g_strdup (""))));
+ } else if (g_strcmp0 (method_name, "ElementRemoveAttribute") == 0) {
+ const gchar *element_id, *attribute;
+ WebKitDOMElement *element;
+
+ g_variant_get (
+ parameters, "(t&s&s)", &page_id, &element_id, &attribute);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ document = e_editor_page_get_document (editor_page);
+ element = webkit_dom_document_get_element_by_id (document, element_id);
+ if (element)
+ webkit_dom_element_remove_attribute (element, attribute);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "ElementRemoveAttributeBySelector") == 0) {
+ const gchar *attribute, *selector;
+ WebKitDOMElement *element;
+
+ g_variant_get (
+ parameters, "(t&s&s)", &page_id, &selector, &attribute);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ document = e_editor_page_get_document (editor_page);
+ element = webkit_dom_document_query_selector (document, selector, NULL);
+ if (element)
+ webkit_dom_element_remove_attribute (element, attribute);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "ElementSetAttribute") == 0) {
+ const gchar *element_id, *attribute, *value;
+ WebKitDOMElement *element;
+
+ g_variant_get (
+ parameters,
+ "(t&s&s&s)",
+ &page_id, &element_id, &attribute, &value);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ document = e_editor_page_get_document (editor_page);
+ element = webkit_dom_document_get_element_by_id (document, element_id);
+ if (element)
+ webkit_dom_element_set_attribute (
+ element, attribute, value, NULL);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "ElementSetAttributeBySelector") == 0) {
+ const gchar *attribute, *selector, *value;
+ WebKitDOMElement *element;
+
+ g_variant_get (
+ parameters, "(t&s&s&s)", &page_id, &selector, &attribute, &value);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ document = e_editor_page_get_document (editor_page);
+ element = webkit_dom_document_query_selector (document, selector, NULL);
+ if (element) {
+ if (g_strcmp0 (selector, "body") == 0 &&
+ g_strcmp0 (attribute, "link") == 0)
+ e_editor_dom_set_link_color (editor_page, value);
+ else if (g_strcmp0 (selector, "body") == 0 &&
+ g_strcmp0 (attribute, "vlink") == 0)
+ e_editor_dom_set_visited_link_color (editor_page, value);
+ else
+ webkit_dom_element_set_attribute (
+ element, attribute, value, NULL);
+ }
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "ElementGetTagName") == 0) {
+ const gchar *element_id;
+ gchar *value = NULL;
+ WebKitDOMElement *element;
+
+ g_variant_get (parameters, "(t&s)", &page_id, &element_id);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ document = e_editor_page_get_document (editor_page);
+ element = webkit_dom_document_get_element_by_id (document, element_id);
+ if (element)
+ value = webkit_dom_element_get_tag_name (element);
+
+ g_dbus_method_invocation_return_value (
+ invocation,
+ g_variant_new (
+ "(@s)",
+ g_variant_new_take_string (
+ value ? value : g_strdup (""))));
+ } else if (g_strcmp0 (method_name, "RemoveImageAttributesFromElementBySelector") == 0) {
+ const gchar *selector;
+ WebKitDOMElement *element;
+
+ g_variant_get (parameters, "(t&s)", &page_id, &selector);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ document = e_editor_page_get_document (editor_page);
+ element = webkit_dom_document_query_selector (document, selector, NULL);
+ if (element) {
+ webkit_dom_element_remove_attribute (element, "background");
+ webkit_dom_element_remove_attribute (element, "data-uri");
+ webkit_dom_element_remove_attribute (element, "data-inline");
+ webkit_dom_element_remove_attribute (element, "data-name");
+ }
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "EEditorCellDialogMarkCurrentCellElement") == 0) {
+ const gchar *element_id;
+
+ g_variant_get (parameters, "(t&s)", &page_id, &element_id);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_dialogs_dom_cell_mark_current_cell_element (editor_page, element_id);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "EEditorCellDialogSaveHistoryOnExit") == 0) {
+ g_variant_get (parameters, "(t)", &page_id);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_dialogs_dom_cell_save_history_on_exit (editor_page);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "EEditorCellDialogSetElementVAlign") == 0) {
+ const gchar *value;
+ EContentEditorScope scope;
+
+ g_variant_get (parameters, "(t&si)", &page_id, &value, &scope);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_dialogs_dom_cell_set_element_v_align (editor_page, value, scope);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "EEditorCellDialogSetElementAlign") == 0) {
+ const gchar *value;
+ EContentEditorScope scope;
+
+ g_variant_get (parameters, "(t&si)", &page_id, &value, &scope);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_dialogs_dom_cell_set_element_align (editor_page, value, scope);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "EEditorCellDialogSetElementNoWrap") == 0) {
+ gboolean value;
+ EContentEditorScope scope;
+
+ g_variant_get (parameters, "(tbi)", &page_id, &value, &scope);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_dialogs_dom_cell_set_element_no_wrap (editor_page, value, scope);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "EEditorCellDialogSetElementHeaderStyle") == 0) {
+ gboolean value;
+ EContentEditorScope scope;
+
+ g_variant_get (parameters, "(tbi)", &page_id, &value, &scope);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_dialogs_dom_cell_set_element_header_style (editor_page, value, scope);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "EEditorCellDialogSetElementWidth") == 0) {
+ const gchar *value;
+ EContentEditorScope scope;
+
+ g_variant_get (parameters, "(t&si)", &page_id, &value, &scope);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_dialogs_dom_cell_set_element_width (editor_page, value, scope);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "EEditorCellDialogSetElementColSpan") == 0) {
+ glong value;
+ EContentEditorScope scope;
+
+ g_variant_get (parameters, "(tii)", &page_id, &value, &scope);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_dialogs_dom_cell_set_element_col_span (editor_page, value, scope);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "EEditorCellDialogSetElementRowSpan") == 0) {
+ glong value;
+ EContentEditorScope scope;
+
+ g_variant_get (parameters, "(tii)", &page_id, &value, &scope);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_dialogs_dom_cell_set_element_row_span (editor_page, value, scope);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "EEditorCellDialogSetElementBgColor") == 0) {
+ const gchar *value;
+ EContentEditorScope scope;
+
+ g_variant_get (parameters, "(t&si)", &page_id, &value, &scope);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_dialogs_dom_cell_set_element_bg_color (editor_page, value, scope);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "EEditorHRuleDialogFindHRule") == 0) {
+ gboolean created_new_hr = FALSE;
+ g_variant_get (parameters, "(t)", &page_id);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ created_new_hr = e_dialogs_dom_h_rule_find_hrule (editor_page);
+
+ g_dbus_method_invocation_return_value (
+ invocation, g_variant_new ("(b)", created_new_hr));
+ } else if (g_strcmp0 (method_name, "EEditorHRuleDialogOnClose") == 0) {
+ g_variant_get (parameters, "(t)", &page_id);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_dialogs_dom_h_rule_dialog_on_close (editor_page);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "EEditorImageDialogMarkImage") == 0) {
+ g_variant_get (parameters, "(t)", &page_id);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_dialogs_dom_image_mark_image (editor_page);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "EEditorImageDialogSaveHistoryOnExit") == 0) {
+ g_variant_get (parameters, "(t)", &page_id);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_dialogs_dom_image_save_history_on_exit (editor_page);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "EEditorImageDialogSetElementUrl") == 0) {
+ const gchar *value;
+
+ g_variant_get (parameters, "(t&s)", &page_id, &value);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_dialogs_dom_image_set_element_url (editor_page, value);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "EEditorImageDialogGetElementUrl") == 0) {
+ gchar *value;
+
+ g_variant_get (parameters, "(t)", &page_id);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ value = e_dialogs_dom_image_get_element_url (editor_page);
+
+ g_dbus_method_invocation_return_value (
+ invocation,
+ g_variant_new (
+ "(@s)",
+ g_variant_new_take_string (
+ value ? value : g_strdup (""))));
+ } else if (g_strcmp0 (method_name, "ImageElementSetWidth") == 0) {
+ const gchar *element_id;
+ gint32 value;
+ WebKitDOMElement *element;
+
+ g_variant_get (
+ parameters, "(t&si)", &page_id, &element_id, &value);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ document = e_editor_page_get_document (editor_page);
+ element = webkit_dom_document_get_element_by_id (document, element_id);
+ if (element)
+ webkit_dom_html_image_element_set_width (
+ WEBKIT_DOM_HTML_IMAGE_ELEMENT (element), value);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "ImageElementGetWidth") == 0) {
+ const gchar *element_id;
+ glong value = 0;
+ WebKitDOMElement *element;
+
+ g_variant_get (
+ parameters, "(t&s)", &page_id, &element_id);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ document = e_editor_page_get_document (editor_page);
+ element = webkit_dom_document_get_element_by_id (document, element_id);
+ if (element)
+ value = webkit_dom_html_image_element_get_width (
+ WEBKIT_DOM_HTML_IMAGE_ELEMENT (element));
+
+ g_dbus_method_invocation_return_value (
+ invocation, g_variant_new ("(i)", value));
+ } else if (g_strcmp0 (method_name, "ImageElementSetHeight") == 0) {
+ const gchar *element_id;
+ gint32 value;
+ WebKitDOMElement *element;
+
+ g_variant_get (
+ parameters, "(t&si)", &page_id, &element_id, &value);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ document = e_editor_page_get_document (editor_page);
+ element = webkit_dom_document_get_element_by_id (document, element_id);
+ if (element)
+ webkit_dom_html_image_element_set_width (
+ WEBKIT_DOM_HTML_IMAGE_ELEMENT (element), value);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "ImageElementGetHeight") == 0) {
+ const gchar *element_id;
+ glong value = 0;
+ WebKitDOMElement *element;
+
+ g_variant_get (
+ parameters, "(t&s)", &page_id, &element_id);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ document = e_editor_page_get_document (editor_page);
+ element = webkit_dom_document_get_element_by_id (document, element_id);
+ if (element)
+ value = webkit_dom_html_image_element_get_height (
+ WEBKIT_DOM_HTML_IMAGE_ELEMENT (element));
+
+ g_dbus_method_invocation_return_value (
+ invocation, g_variant_new ("(i)", value));
+ } else if (g_strcmp0 (method_name, "ImageElementGetNaturalWidth") == 0) {
+ const gchar *element_id;
+ glong value = 0;
+ WebKitDOMElement *element;
+
+ g_variant_get (
+ parameters, "(t&s)", &page_id, &element_id);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ document = e_editor_page_get_document (editor_page);
+ element = webkit_dom_document_get_element_by_id (document, element_id);
+ if (element)
+ value = webkit_dom_html_image_element_get_natural_width (
+ WEBKIT_DOM_HTML_IMAGE_ELEMENT (element));
+
+ g_dbus_method_invocation_return_value (
+ invocation, g_variant_new ("(i)", value));
+ } else if (g_strcmp0 (method_name, "ImageElementGetNaturalHeight") == 0) {
+ const gchar *element_id;
+ glong value = 0;
+ WebKitDOMElement *element;
+
+ g_variant_get (
+ parameters, "(t&s)", &page_id, &element_id);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ document = e_editor_page_get_document (editor_page);
+ element = webkit_dom_document_get_element_by_id (document, element_id);
+ if (element)
+ value = webkit_dom_html_image_element_get_natural_height (
+ WEBKIT_DOM_HTML_IMAGE_ELEMENT (element));
+
+ g_dbus_method_invocation_return_value (
+ invocation, g_variant_new ("(i)", value));
+ } else if (g_strcmp0 (method_name, "ImageElementSetHSpace") == 0) {
+ const gchar *element_id;
+ gint32 value;
+ WebKitDOMElement *element;
+
+ g_variant_get (
+ parameters, "(t&si)", &page_id, &element_id, &value);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ document = e_editor_page_get_document (editor_page);
+ element = webkit_dom_document_get_element_by_id (document, element_id);
+ if (element)
+ webkit_dom_html_image_element_set_hspace (
+ WEBKIT_DOM_HTML_IMAGE_ELEMENT (element), value);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "ImageElementGetHSpace") == 0) {
+ const gchar *element_id;
+ glong value = 0;
+ WebKitDOMElement *element;
+
+ g_variant_get (
+ parameters, "(t&s)", &page_id, &element_id);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ document = e_editor_page_get_document (editor_page);
+ element = webkit_dom_document_get_element_by_id (document, element_id);
+ if (element)
+ value = webkit_dom_html_image_element_get_hspace (
+ WEBKIT_DOM_HTML_IMAGE_ELEMENT (element));
+
+ g_dbus_method_invocation_return_value (
+ invocation, g_variant_new ("(i)", value));
+ } else if (g_strcmp0 (method_name, "ImageElementSetVSpace") == 0) {
+ const gchar *element_id;
+ gint32 value;
+ WebKitDOMElement *element;
+
+ g_variant_get (
+ parameters, "(t&si)", &page_id, &element_id, &value);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ document = e_editor_page_get_document (editor_page);
+ element = webkit_dom_document_get_element_by_id (document, element_id);
+ if (element)
+ webkit_dom_html_image_element_set_vspace (
+ WEBKIT_DOM_HTML_IMAGE_ELEMENT (element), value);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "ImageElementGetVSpace") == 0) {
+ const gchar *element_id;
+ glong value = 0;
+ WebKitDOMElement *element;
+
+ g_variant_get (
+ parameters, "(t&s)", &page_id, &element_id);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ document = e_editor_page_get_document (editor_page);
+ element = webkit_dom_document_get_element_by_id (document, element_id);
+ if (element)
+ value = webkit_dom_html_image_element_get_vspace (
+ WEBKIT_DOM_HTML_IMAGE_ELEMENT (element));
+
+ g_dbus_method_invocation_return_value (
+ invocation, g_variant_new ("(i)", value));
+ } else if (g_strcmp0 (method_name, "EEditorLinkDialogOk") == 0) {
+ const gchar *url, *inner_text;
+
+ g_variant_get (parameters, "(t&s&s)", &page_id, &url, &inner_text);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_dialogs_dom_link_commit (editor_page, url, inner_text);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "EEditorLinkDialogShow") == 0) {
+ g_variant_get (parameters, "(t)", &page_id);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ g_dbus_method_invocation_return_value (
+ invocation, e_dialogs_dom_link_show (editor_page));
+ } else if (g_strcmp0 (method_name, "EEditorPageDialogSaveHistory") == 0) {
+ g_variant_get (parameters, "(t)", &page_id);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_dialogs_dom_page_save_history (editor_page);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "EEditorPageDialogSaveHistoryOnExit") == 0) {
+ g_variant_get (parameters, "(t)", &page_id);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_dialogs_dom_page_save_history_on_exit (editor_page);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "EEditorSpellCheckDialogNext") == 0) {
+ const gchar *from_word = NULL;
+ const gchar * const *languages = NULL;
+ gchar *value = NULL;
+
+ g_variant_get (parameters, "(t&s^as)", &page_id, &from_word, &languages);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ value = e_dialogs_dom_spell_check_next (editor_page, from_word, languages);
+
+ g_dbus_method_invocation_return_value (
+ invocation,
+ g_variant_new (
+ "(@s)",
+ g_variant_new_take_string (
+ value ? value : g_strdup (""))));
+ } else if (g_strcmp0 (method_name, "EEditorSpellCheckDialogPrev") == 0) {
+ const gchar *from_word = NULL;
+ const gchar * const *languages = NULL;
+ gchar *value = NULL;
+
+ g_variant_get (parameters, "(t&s^as)", &page_id, &from_word, &languages);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ value = e_dialogs_dom_spell_check_prev (editor_page, from_word, languages);
+
+ g_dbus_method_invocation_return_value (
+ invocation,
+ g_variant_new (
+ "(@s)",
+ g_variant_new_take_string (
+ value ? value : g_strdup (""))));
+ } else if (g_strcmp0 (method_name, "EEditorTableDialogSetRowCount") == 0) {
+ guint32 value;
+
+ g_variant_get (parameters, "(tu)", &page_id, &value);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_dialogs_dom_table_set_row_count (editor_page, value);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "EEditorTableDialogGetRowCount") == 0) {
+ gulong value;
+
+ g_variant_get (parameters, "(t)", &page_id);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ value = e_dialogs_dom_table_get_row_count (editor_page);
+
+ g_dbus_method_invocation_return_value (
+ invocation, g_variant_new ("(u)", value));
+ } else if (g_strcmp0 (method_name, "EEditorTableDialogSetColumnCount") == 0) {
+ guint32 value;
+
+ g_variant_get (parameters, "(tu)", &page_id, &value);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_dialogs_dom_table_set_column_count (editor_page, value);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "EEditorTableDialogGetColumnCount") == 0) {
+ gulong value;
+
+ g_variant_get (parameters, "(t)", &page_id);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ value = e_dialogs_dom_table_get_column_count (editor_page);
+
+ g_dbus_method_invocation_return_value (
+ invocation, g_variant_new ("(u)", value));
+ } else if (g_strcmp0 (method_name, "EEditorTableDialogShow") == 0) {
+ gboolean created_new_table;
+
+ g_variant_get (parameters, "(t)", &page_id);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ created_new_table = e_dialogs_dom_table_show (editor_page);
+
+ g_dbus_method_invocation_return_value (
+ invocation, g_variant_new ("(b)", created_new_table));
+ } else if (g_strcmp0 (method_name, "EEditorTableDialogSaveHistoryOnExit") == 0) {
+ g_variant_get (parameters, "(t)", &page_id);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_dialogs_dom_table_save_history_on_exit (editor_page);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "EEditorDialogDeleteCellContents") == 0) {
+ g_variant_get (parameters, "(t)", &page_id);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_editor_dom_delete_cell_contents (editor_page);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "EEditorDialogDeleteColumn") == 0) {
+ g_variant_get (parameters, "(t)", &page_id);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_editor_dom_delete_column (editor_page);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "EEditorDialogDeleteRow") == 0) {
+ g_variant_get (parameters, "(t)", &page_id);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_editor_dom_delete_row (editor_page);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "EEditorDialogDeleteTable") == 0) {
+ g_variant_get (parameters, "(t)", &page_id);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_editor_dom_delete_table (editor_page);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "EEditorDialogInsertColumnAfter") == 0) {
+ g_variant_get (parameters, "(t)", &page_id);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_editor_dom_insert_column_after (editor_page);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "EEditorDialogInsertColumnBefore") == 0) {
+ g_variant_get (parameters, "(t)", &page_id);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_editor_dom_insert_column_before (editor_page);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "EEditorDialogInsertRowAbove") == 0) {
+ g_variant_get (parameters, "(t)", &page_id);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_editor_dom_insert_row_above (editor_page);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "EEditorDialogInsertRowBelow") == 0) {
+ g_variant_get (parameters, "(t)", &page_id);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_editor_dom_insert_row_below (editor_page);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "EEditorLinkDialogOnOpen") == 0) {
+ g_variant_get (parameters, "(t)", &page_id);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_dialogs_dom_link_dialog_on_open (editor_page);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "EEditorLinkDialogOnClose") == 0) {
+ g_variant_get (parameters, "(t)", &page_id);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_dialogs_dom_link_dialog_on_close (editor_page);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "EEditorLinkDialogUnlink") == 0) {
+ EEditorUndoRedoManager *manager;
+
+ g_variant_get (parameters, "(t)", &page_id);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ manager = e_editor_page_get_undo_redo_manager (editor_page);
+ /* Remove the history event that was saved when the dialog was opened */
+ e_editor_undo_redo_manager_remove_current_history_event (manager);
+
+ e_editor_dom_selection_unlink (editor_page);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "EEditorActionsSaveHistoryForCut") == 0) {
+ g_variant_get (parameters, "(t)", &page_id);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_editor_dom_save_history_for_cut (editor_page);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "TableCellElementGetNoWrap") == 0) {
+ const gchar *element_id;
+ gboolean value = FALSE;
+ WebKitDOMElement *element;
+
+ g_variant_get (parameters, "(t&s)", &page_id, &element_id);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ document = e_editor_page_get_document (editor_page);
+ element = webkit_dom_document_get_element_by_id (document, element_id);
+ if (element)
+ value = webkit_dom_html_table_cell_element_get_no_wrap (
+ WEBKIT_DOM_HTML_TABLE_CELL_ELEMENT (element));
+
+ g_dbus_method_invocation_return_value (
+ invocation, g_variant_new ("(b)", value));
+ } else if (g_strcmp0 (method_name, "TableCellElementGetRowSpan") == 0) {
+ const gchar *element_id;
+ glong value = 0;
+ WebKitDOMElement *element;
+
+ g_variant_get (parameters, "(t&s)", &page_id, &element_id);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ document = e_editor_page_get_document (editor_page);
+ element = webkit_dom_document_get_element_by_id (document, element_id);
+ if (element)
+ value = webkit_dom_html_table_cell_element_get_row_span (
+ WEBKIT_DOM_HTML_TABLE_CELL_ELEMENT (element));
+
+ g_dbus_method_invocation_return_value (
+ invocation, g_variant_new ("(i)", value));
+ } else if (g_strcmp0 (method_name, "TableCellElementGetColSpan") == 0) {
+ const gchar *element_id;
+ glong value = 0;
+ WebKitDOMElement *element;
+
+ g_variant_get (parameters, "(t&s)", &page_id, &element_id);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ document = e_editor_page_get_document (editor_page);
+ element = webkit_dom_document_get_element_by_id (document, element_id);
+ if (element)
+ value = webkit_dom_html_table_cell_element_get_col_span (
+ WEBKIT_DOM_HTML_TABLE_CELL_ELEMENT (element));
+
+ g_dbus_method_invocation_return_value (
+ invocation, g_variant_new ("(i)", value));
+ } else if (g_strcmp0 (method_name, "DOMSaveSelection") == 0) {
+ g_variant_get (parameters, "(t)", &page_id);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_editor_dom_selection_save (editor_page);
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "DOMRestoreSelection") == 0) {
+ g_variant_get (parameters, "(t)", &page_id);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_editor_dom_selection_restore (editor_page);
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "DOMUndo") == 0) {
+ EEditorUndoRedoManager *manager;
+
+ g_variant_get (parameters, "(t)", &page_id);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ manager = e_editor_page_get_undo_redo_manager (editor_page);
+
+ e_editor_undo_redo_manager_undo (manager);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "DOMRedo") == 0) {
+ EEditorUndoRedoManager *manager;
+
+ g_variant_get (parameters, "(t)", &page_id);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ manager = e_editor_page_get_undo_redo_manager (editor_page);
+
+ e_editor_undo_redo_manager_redo (manager);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "DOMTurnSpellCheckOff") == 0) {
+ g_variant_get (parameters, "(t)", &page_id);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_editor_dom_turn_spell_check_off (editor_page);
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "DOMQuoteAndInsertTextIntoSelection") == 0) {
+ gboolean is_html = FALSE;
+ const gchar *text;
+
+ g_variant_get (parameters, "(t&sb)", &page_id, &text, &is_html);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_editor_dom_quote_and_insert_text_into_selection (editor_page, text, is_html);
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "DOMConvertAndInsertHTMLIntoSelection") == 0) {
+ gboolean is_html;
+ const gchar *text;
+
+ g_variant_get (parameters, "(t&sb)", &page_id, &text, &is_html);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_editor_dom_convert_and_insert_html_into_selection (editor_page, text, is_html);
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "DOMEmbedStyleSheet") == 0) {
+ const gchar *style_sheet_content;
+
+ g_variant_get (parameters, "(t&s)", &page_id, &style_sheet_content);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_editor_dom_embed_style_sheet (editor_page, style_sheet_content);
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "DOMRemoveEmbeddedStyleSheet") == 0) {
+ g_variant_get (parameters, "(t)", &page_id);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_editor_dom_remove_embedded_style_sheet (editor_page);
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "SetPastingContentFromItself") == 0) {
+ gboolean value = FALSE;
+
+ g_variant_get (parameters, "(tb)", &page_id, &value);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_editor_page_set_pasting_content_from_itself (editor_page, value);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "SetEditorHTMLMode") == 0) {
+ gboolean html_mode = FALSE;
+ gboolean convert = FALSE;
+
+ g_variant_get (parameters, "(tbb)", &page_id, &html_mode, &convert);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ convert = convert && e_editor_page_get_html_mode (editor_page) && !html_mode;
+ e_editor_page_set_html_mode (editor_page, html_mode);
+
+ if (convert)
+ e_editor_dom_convert_when_changing_composer_mode (editor_page);
+ else
+ e_editor_dom_process_content_after_mode_change (editor_page);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "SetConvertInSitu") == 0) {
+ gboolean value = FALSE;
+
+ g_variant_get (parameters, "(tb)", &page_id, &value);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_editor_page_set_convert_in_situ (editor_page, value);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "DOMForceSpellCheck") == 0) {
+ g_variant_get (parameters, "(t)", &page_id);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_editor_dom_force_spell_check (editor_page);
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "DOMCheckIfConversionNeeded") == 0) {
+ gboolean conversion_needed;
+
+ g_variant_get (parameters, "(t)", &page_id);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ conversion_needed = e_editor_dom_check_if_conversion_needed (editor_page);
+ g_dbus_method_invocation_return_value (
+ invocation, g_variant_new ("(b)", conversion_needed));
+ } else if (g_strcmp0 (method_name, "DOMGetContent") == 0) {
+ EContentEditorGetContentFlags flags;
+ const gchar *from_domain;
+ gchar *value = NULL;
+ GVariant *inline_images = NULL;
+
+ g_variant_get (parameters, "(t&si)", &page_id, &from_domain, &flags);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ if ((flags & E_CONTENT_EDITOR_GET_INLINE_IMAGES) && from_domain && *from_domain)
+ inline_images = e_editor_dom_get_inline_images_data (editor_page, from_domain);
+
+ if ((flags & E_CONTENT_EDITOR_GET_TEXT_HTML) &&
+ !(flags & E_CONTENT_EDITOR_GET_PROCESSED)) {
+ value = e_editor_dom_process_content_for_draft (
+ editor_page, (flags & E_CONTENT_EDITOR_GET_BODY));
+ } else if ((flags & E_CONTENT_EDITOR_GET_TEXT_HTML) &&
+ (flags & E_CONTENT_EDITOR_GET_PROCESSED) &&
+ !(flags & E_CONTENT_EDITOR_GET_BODY)) {
+ value = e_editor_dom_process_content_to_html_for_exporting (editor_page);
+ } else if ((flags & E_CONTENT_EDITOR_GET_TEXT_PLAIN) &&
+ (flags & E_CONTENT_EDITOR_GET_PROCESSED) &&
+ !(flags & E_CONTENT_EDITOR_GET_BODY)) {
+ value = e_editor_dom_process_content_to_plain_text_for_exporting (editor_page);
+ } else if ((flags & E_CONTENT_EDITOR_GET_TEXT_PLAIN) &&
+ (flags & E_CONTENT_EDITOR_GET_BODY) &&
+ !(flags & E_CONTENT_EDITOR_GET_PROCESSED)) {
+ if (flags & E_CONTENT_EDITOR_GET_EXCLUDE_SIGNATURE)
+ value = e_composer_dom_get_raw_body_content_without_signature (editor_page);
+ else
+ value = e_composer_dom_get_raw_body_content (editor_page);
+ } else {
+ g_warning ("Unsupported flags combination (%d) in (%s)", flags, G_STRFUNC);
+ }
+
+ /* If no inline images are requested we still have to return
+ * something even it won't be used at all. */
+ g_dbus_method_invocation_return_value (
+ invocation,
+ g_variant_new (
+ "(sv)",
+ value ? value : "",
+ inline_images ? inline_images : g_variant_new_int32 (0)));
+
+ g_free (value);
+
+ if ((flags & E_CONTENT_EDITOR_GET_INLINE_IMAGES) && from_domain && *from_domain &&
inline_images)
+ e_editor_dom_restore_images (editor_page, inline_images);
+ } else if (g_strcmp0 (method_name, "DOMInsertHTML") == 0) {
+ const gchar *html;
+
+ g_variant_get (parameters, "(t&s)", &page_id, &html);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_editor_dom_insert_html (editor_page, html);
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "DOMConvertContent") == 0) {
+ const gchar *preferred_text;
+
+ g_variant_get (parameters, "(t&s)", &page_id, &preferred_text);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_editor_dom_convert_content (editor_page, preferred_text);
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "DOMAddNewInlineImageIntoList") == 0) {
+ const gchar *cid_uri, *src, *filename;
+
+ g_variant_get (parameters, "(t&s&s&s)", &page_id, &filename, &cid_uri, &src);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_editor_page_add_new_inline_image_into_list (
+ editor_page, cid_uri, src);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "DOMReplaceImageSrc") == 0) {
+ const gchar *selector, *uri;
+
+ g_variant_get (parameters, "(t&s&s)", &page_id, &selector, &uri);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_editor_dom_replace_image_src (editor_page, selector, uri);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "DOMDragAndDropEnd") == 0) {
+ g_variant_get (parameters, "(t)", &page_id);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_editor_dom_drag_and_drop_end (editor_page);
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "DOMInsertSmiley") == 0) {
+ const gchar *smiley_name;
+
+ g_variant_get (parameters, "(t&s)", &page_id, &smiley_name);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_editor_dom_insert_smiley_by_name (editor_page, smiley_name);
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "DOMMoveSelectionOnPoint") == 0) {
+ gboolean cancel_if_not_collapsed;
+ gint x, y;
+
+ g_variant_get (parameters, "(tiib)", &page_id, &x, &y, &cancel_if_not_collapsed);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ if (cancel_if_not_collapsed) {
+ if (e_editor_dom_selection_is_collapsed (editor_page))
+ e_editor_dom_selection_set_on_point (editor_page, x, y);
+ } else
+ e_editor_dom_selection_set_on_point (editor_page, x, y);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "DOMSelectionIndent") == 0) {
+ g_variant_get (parameters, "(t)", &page_id);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_editor_dom_selection_indent (editor_page);
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "DOMSelectionSave") == 0) {
+ g_variant_get (parameters, "(t)", &page_id);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_editor_dom_selection_save (editor_page);
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "DOMSelectionRestore") == 0) {
+ g_variant_get (parameters, "(t)", &page_id);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_editor_dom_selection_restore (editor_page);
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "DOMSelectionInsertImage") == 0) {
+ const gchar *uri;
+
+ g_variant_get (parameters, "(t&s)", &page_id, &uri);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_editor_dom_insert_image (editor_page, uri);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "DOMSelectionReplace") == 0) {
+ const gchar *replacement;
+
+ g_variant_get (parameters, "(t&s)", &page_id, &replacement);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_editor_dom_selection_replace (editor_page, replacement);
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "DOMSelectionSetAlignment") == 0) {
+ EContentEditorAlignment alignment;
+
+ g_variant_get (parameters, "(ti)", &page_id, &alignment);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_editor_dom_selection_set_alignment (editor_page, alignment);
+ e_editor_page_set_alignment (editor_page, alignment);
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "DOMSelectionSetBold") == 0) {
+ gboolean bold;
+
+ g_variant_get (parameters, "(tb)", &page_id, &bold);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_editor_page_set_bold (editor_page, bold);
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "DOMSelectionSetBlockFormat") == 0) {
+ EContentEditorBlockFormat block_format;
+
+ g_variant_get (parameters, "(ti)", &page_id, &block_format);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_editor_dom_selection_set_block_format (editor_page, block_format);
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "DOMSelectionSetFontColor") == 0) {
+ const gchar *color;
+
+ g_variant_get (parameters, "(t&s)", &page_id, &color);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_editor_dom_selection_set_font_color (editor_page, color);
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "DOMSelectionSetFontSize") == 0) {
+ EContentEditorFontSize font_size;
+
+ g_variant_get (parameters, "(ti)", &page_id, &font_size);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_editor_dom_selection_set_font_size (editor_page, font_size);
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "DOMSelectionSetItalic") == 0) {
+ gboolean italic;
+
+ g_variant_get (parameters, "(tb)", &page_id, &italic);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_editor_page_set_italic (editor_page, italic);
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "DOMSelectionSetMonospaced") == 0) {
+ gboolean monospaced;
+
+ g_variant_get (parameters, "(tb)", &page_id, &monospaced);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_editor_page_set_monospace (editor_page, monospaced);
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "DOMSelectionSetStrikethrough") == 0) {
+ gboolean strikethrough;
+
+ g_variant_get (parameters, "(tb)", &page_id, &strikethrough);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_editor_page_set_strikethrough (editor_page, strikethrough);
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "DOMSelectionSetSubscript") == 0) {
+ gboolean subscript;
+
+ g_variant_get (parameters, "(tb)", &page_id, &subscript);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_editor_dom_selection_set_subscript (editor_page, subscript);
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "DOMSelectionSetSuperscript") == 0) {
+ gboolean superscript;
+
+ g_variant_get (parameters, "(tb)", &page_id, &superscript);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_editor_dom_selection_set_superscript (editor_page, superscript);
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "DOMSelectionSetUnderline") == 0) {
+ gboolean underline;
+
+ g_variant_get (parameters, "(tb)", &page_id, &underline);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_editor_page_set_underline (editor_page, underline);
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "DOMSelectionUnindent") == 0) {
+ g_variant_get (parameters, "(t)", &page_id);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_editor_dom_selection_unindent (editor_page);
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "DOMSelectionWrap") == 0) {
+ g_variant_get (parameters, "(t)", &page_id);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_editor_dom_selection_wrap (editor_page);
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "DOMGetCaretWord") == 0) {
+ gchar *word;
+
+ g_variant_get (parameters, "(t)", &page_id);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ word = e_editor_dom_get_caret_word (editor_page);
+
+ g_dbus_method_invocation_return_value (
+ invocation,
+ g_variant_new (
+ "(@s)",
+ g_variant_new_take_string (
+ word ? word : g_strdup (""))));
+ } else if (g_strcmp0 (method_name, "DOMInsertSignature") == 0) {
+ gboolean is_html, set_signature_from_message;
+ gboolean check_if_signature_is_changed, ignore_next_signature_change;
+ const gchar *content, *signature_id;
+ gchar *new_signature_id = NULL;
+
+ g_variant_get (
+ parameters,
+ "(t&sb&sbbb)",
+ &page_id,
+ &content,
+ &is_html,
+ &signature_id,
+ &set_signature_from_message,
+ &check_if_signature_is_changed,
+ &ignore_next_signature_change);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ new_signature_id = e_composer_dom_insert_signature (
+ editor_page,
+ content,
+ is_html,
+ signature_id,
+ &set_signature_from_message,
+ &check_if_signature_is_changed,
+ &ignore_next_signature_change);
+
+ g_dbus_method_invocation_return_value (
+ invocation,
+ g_variant_new (
+ "(sbbb)",
+ new_signature_id ? new_signature_id : "",
+ set_signature_from_message,
+ check_if_signature_is_changed,
+ ignore_next_signature_change));
+
+ g_free (new_signature_id);
+ } else if (g_strcmp0 (method_name, "DOMSaveDragAndDropHistory") == 0) {
+ g_variant_get (
+ parameters, "(t)", &page_id);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_composer_dom_save_drag_and_drop_history (editor_page);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "DOMCleanAfterDragAndDrop") == 0) {
+ g_variant_get (
+ parameters, "(t)", &page_id);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ e_composer_dom_clean_after_drag_and_drop (editor_page);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "DOMGetActiveSignatureUid") == 0) {
+ gchar *value;
+
+ g_variant_get (parameters, "(t)", &page_id);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ value = e_composer_dom_get_active_signature_uid (editor_page);
+
+ g_dbus_method_invocation_return_value (
+ invocation,
+ g_variant_new (
+ "(@s)",
+ g_variant_new_take_string (
+ value ? value : g_strdup (""))));
+ } else if (g_strcmp0 (method_name, "DOMGetCaretPosition") == 0) {
+ guint32 value;
+
+ g_variant_get (parameters, "(t)", &page_id);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ value = e_editor_dom_get_caret_position (editor_page);
+
+ g_dbus_method_invocation_return_value (
+ invocation,
+ value ? g_variant_new_uint32 (value) : NULL);
+ } else if (g_strcmp0 (method_name, "DOMGetCaretOffset") == 0) {
+ guint32 value;
+
+ g_variant_get (parameters, "(t)", &page_id);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ value = e_editor_dom_get_caret_offset (editor_page);
+
+ g_dbus_method_invocation_return_value (
+ invocation,
+ value ? g_variant_new_uint32 (value) : NULL);
+ } else if (g_strcmp0 (method_name, "DOMClearUndoRedoHistory") == 0) {
+ EEditorUndoRedoManager *manager;
+
+ g_variant_get (parameters, "(t)", &page_id);
+
+ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+ if (!editor_page)
+ goto error;
+
+ manager = e_editor_page_get_undo_redo_manager (editor_page);
+ if (manager)
+ e_editor_undo_redo_manager_clean_history (manager);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else {
+ g_warning ("UNKNOWN METHOD '%s'", method_name);
+ }
+
+ return;
+
+ error:
+ g_warning ("Cannot obtain WebKitWebPage for '%ld'", page_id);
+}
+
+static void
+web_page_gone_cb (gpointer user_data,
+ GObject *gone_web_page)
+{
+ EEditorWebExtension *extension = user_data;
+ GHashTableIter iter;
+ gpointer key, value;
+
+ g_return_if_fail (E_IS_EDITOR_WEB_EXTENSION (extension));
+
+ g_hash_table_iter_init (&iter, extension->priv->editor_pages);
+ while (g_hash_table_iter_next (&iter, &key, &value)) {
+ if (value == gone_web_page) {
+ g_hash_table_remove (extension->priv->editor_pages, key);
+ break;
+ }
+ }
+}
+
+static const GDBusInterfaceVTable interface_vtable = {
+ handle_method_call,
+ NULL,
+ NULL
+};
+
+static void
+e_editor_web_extension_dispose (GObject *object)
+{
+ EEditorWebExtension *extension = E_EDITOR_WEB_EXTENSION (object);
+
+ if (extension->priv->dbus_connection) {
+ g_dbus_connection_unregister_object (
+ extension->priv->dbus_connection,
+ extension->priv->registration_id);
+ extension->priv->registration_id = 0;
+ extension->priv->dbus_connection = NULL;
+ }
+
+ g_hash_table_remove_all (extension->priv->editor_pages);
+
+ g_clear_object (&extension->priv->wk_extension);
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (e_editor_web_extension_parent_class)->dispose (object);
+}
+
+static void
+e_editor_web_extension_finalize (GObject *object)
+{
+ EEditorWebExtension *extension = E_EDITOR_WEB_EXTENSION (object);
+
+ if (extension->priv->editor_pages) {
+ g_hash_table_destroy (extension->priv->editor_pages);
+ extension->priv->editor_pages = NULL;
+ }
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (e_editor_web_extension_parent_class)->finalize (object);
+}
+
+static void
+e_editor_web_extension_class_init (EEditorWebExtensionClass *class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+ object_class->dispose = e_editor_web_extension_dispose;
+ object_class->finalize = e_editor_web_extension_finalize;
+
+ g_type_class_add_private (object_class, sizeof(EEditorWebExtensionPrivate));
+}
+
+static void
+e_editor_web_extension_init (EEditorWebExtension *extension)
+{
+ extension->priv = E_EDITOR_WEB_EXTENSION_GET_PRIVATE (extension);
+ extension->priv->editor_pages = g_hash_table_new_full (g_int64_hash, g_int64_equal, g_free,
g_object_unref);
+}
+
+static gpointer
+e_editor_web_extension_create_instance(gpointer data)
+{
+ return g_object_new (E_TYPE_EDITOR_WEB_EXTENSION, NULL);
+}
+
+EEditorWebExtension *
+e_editor_web_extension_get_default (void)
+{
+ static GOnce once_init = G_ONCE_INIT;
+ return E_EDITOR_WEB_EXTENSION (g_once (&once_init, e_editor_web_extension_create_instance, NULL));
+}
+
+static gboolean
+image_exists_in_cache (const gchar *image_uri)
+{
+ gchar *filename;
+ gchar *hash;
+ gboolean exists = FALSE;
+
+ if (!emd_global_http_cache)
+ return FALSE;
+
+ hash = g_compute_checksum_for_string (G_CHECKSUM_MD5, image_uri, -1);
+ filename = camel_data_cache_get_filename (
+ emd_global_http_cache, "http", hash);
+
+ if (filename != NULL) {
+ struct stat st;
+
+ exists = g_file_test (filename, G_FILE_TEST_EXISTS);
+ if (exists && g_stat (filename, &st) == 0) {
+ exists = st.st_size != 0;
+ } else {
+ exists = FALSE;
+ }
+ g_free (filename);
+ }
+
+ g_free (hash);
+
+ return exists;
+}
+
+static void
+redirect_http_uri (EEditorWebExtension *extension,
+ WebKitWebPage *web_page,
+ WebKitURIRequest *request)
+{
+ const gchar *uri;
+ gchar *new_uri;
+ SoupURI *soup_uri;
+ gboolean image_exists;
+ EEditorPage *editor_page;
+ EImageLoadingPolicy image_policy;
+
+ editor_page = get_editor_page (extension, webkit_web_page_get_id (web_page));
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ uri = webkit_uri_request_get_uri (request);
+
+ /* Check Evolution's cache */
+ image_exists = image_exists_in_cache (uri);
+
+ /* If the URI is not cached and we are not allowed to load it
+ * then redirect to invalid URI, so that webkit would display
+ * a native placeholder for it. */
+ image_policy = e_editor_page_get_image_loading_policy (editor_page);
+ if (!image_exists && !e_editor_page_get_force_image_load (editor_page) &&
+ (image_policy == E_IMAGE_LOADING_POLICY_NEVER)) {
+ webkit_uri_request_set_uri (request, "about:blank");
+ return;
+ }
+
+ new_uri = g_strconcat ("evo-", uri, NULL);
+ soup_uri = soup_uri_new (new_uri);
+ g_free (new_uri);
+
+ new_uri = soup_uri_to_string (soup_uri, FALSE);
+ webkit_uri_request_set_uri (request, new_uri);
+ soup_uri_free (soup_uri);
+
+ g_free (new_uri);
+}
+
+static gboolean
+web_page_send_request_cb (WebKitWebPage *web_page,
+ WebKitURIRequest *request,
+ WebKitURIResponse *redirected_response,
+ EEditorWebExtension *extension)
+{
+ const char *request_uri;
+ const char *page_uri;
+ gboolean uri_is_http;
+
+ request_uri = webkit_uri_request_get_uri (request);
+ page_uri = webkit_web_page_get_uri (web_page);
+
+ /* Always load the main resource. */
+ if (g_strcmp0 (request_uri, page_uri) == 0)
+ return FALSE;
+
+ uri_is_http =
+ g_str_has_prefix (request_uri, "http:") ||
+ g_str_has_prefix (request_uri, "https:") ||
+ g_str_has_prefix (request_uri, "evo-http:") ||
+ g_str_has_prefix (request_uri, "evo-https:");
+
+ if (uri_is_http)
+ redirect_http_uri (extension, web_page, request);
+
+ return FALSE;
+}
+
+static void
+web_page_created_cb (WebKitWebExtension *wk_extension,
+ WebKitWebPage *web_page,
+ EEditorWebExtension *extension)
+{
+ EEditorPage *editor_page;
+ guint64 *ppage_id;
+
+ g_return_if_fail (WEBKIT_IS_WEB_PAGE (web_page));
+ g_return_if_fail (E_IS_EDITOR_WEB_EXTENSION (extension));
+
+ ppage_id = g_new (guint64, 1);
+ *ppage_id = webkit_web_page_get_id (web_page);
+
+ editor_page = e_editor_page_new (web_page, extension);
+ g_hash_table_insert (extension->priv->editor_pages, ppage_id, editor_page);
+
+ g_object_weak_ref (G_OBJECT (web_page), web_page_gone_cb, extension);
+
+ g_signal_connect (
+ web_page, "send-request",
+ G_CALLBACK (web_page_send_request_cb), extension);
+}
+
+void
+e_editor_web_extension_initialize (EEditorWebExtension *extension,
+ WebKitWebExtension *wk_extension)
+{
+ g_return_if_fail (E_IS_EDITOR_WEB_EXTENSION (extension));
+
+ extension->priv->wk_extension = g_object_ref (wk_extension);
+
+ if (emd_global_http_cache == NULL) {
+ emd_global_http_cache = camel_data_cache_new (
+ e_get_user_cache_dir (), NULL);
+
+ if (emd_global_http_cache) {
+ /* cache expiry - 2 hour access, 1 day max */
+ camel_data_cache_set_expire_age (
+ emd_global_http_cache, 24 * 60 * 60);
+ camel_data_cache_set_expire_access (
+ emd_global_http_cache, 2 * 60 * 60);
+ }
+ }
+
+ g_signal_connect (
+ wk_extension, "page-created",
+ G_CALLBACK (web_page_created_cb), extension);
+}
+
+void
+e_editor_web_extension_dbus_register (EEditorWebExtension *extension,
+ GDBusConnection *connection)
+{
+ GError *error = NULL;
+ static GDBusNodeInfo *introspection_data = NULL;
+
+ g_return_if_fail (E_IS_EDITOR_WEB_EXTENSION (extension));
+ g_return_if_fail (G_IS_DBUS_CONNECTION (connection));
+
+ if (!introspection_data) {
+ introspection_data =
+ g_dbus_node_info_new_for_xml (introspection_xml, NULL);
+
+ extension->priv->registration_id =
+ g_dbus_connection_register_object (
+ connection,
+ E_WEBKIT_EDITOR_WEB_EXTENSION_OBJECT_PATH,
+ introspection_data->interfaces[0],
+ &interface_vtable,
+ extension,
+ NULL,
+ &error);
+
+ if (!extension->priv->registration_id) {
+ g_warning ("Failed to register object: %s\n", error->message);
+ g_error_free (error);
+ } else {
+ extension->priv->dbus_connection = connection;
+ g_object_add_weak_pointer (
+ G_OBJECT (connection),
+ (gpointer *) &extension->priv->dbus_connection);
+ }
+ }
+}
+
+GDBusConnection *
+e_editor_web_extension_get_connection (EEditorWebExtension *extension)
+{
+ g_return_val_if_fail (E_IS_EDITOR_WEB_EXTENSION (extension), NULL);
+
+ return extension->priv->dbus_connection;
+}
diff --git a/modules/webkit-editor/web-extension/e-editor-web-extension.h
b/modules/webkit-editor/web-extension/e-editor-web-extension.h
new file mode 100644
index 0000000..987b3de
--- /dev/null
+++ b/modules/webkit-editor/web-extension/e-editor-web-extension.h
@@ -0,0 +1,82 @@
+/*
+ * e-editor-web-extension.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/>
+ *
+ */
+
+#ifndef E_EDITOR_WEB_EXTENSION_H
+#define E_EDITOR_WEB_EXTENSION_H
+
+#include <glib-object.h>
+#include <webkit2/webkit-web-extension.h>
+
+#define E_UTIL_INCLUDE_WITHOUT_WEBKIT
+#include <e-util/e-util.h>
+#undef E_UTIL_INCLUDE_WITHOUT_WEBKIT
+
+#include "e-editor-web-extension-names.h"
+
+/* Standard GObject macros */
+#define E_TYPE_EDITOR_WEB_EXTENSION \
+ (e_editor_web_extension_get_type ())
+#define E_EDITOR_WEB_EXTENSION(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_EDITOR_WEB_EXTENSION, EEditorWebExtension))
+#define E_EDITOR_WEB_EXTENSION_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_EDITOR_WEB_EXTENSION, EEditorWebExtensionClass))
+#define E_IS_EDITOR_WEB_EXTENSION(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_EDITOR_WEB_EXTENSION))
+#define E_IS_EDITOR_WEB_EXTENSION_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_EDITOR_WEB_EXTENSION))
+#define E_EDITOR_WEB_EXTENSION_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_EDITOR_WEB_EXTENSION, EEditorWebExtensionClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EEditorWebExtension EEditorWebExtension;
+typedef struct _EEditorWebExtensionClass EEditorWebExtensionClass;
+typedef struct _EEditorWebExtensionPrivate EEditorWebExtensionPrivate;
+
+struct _EEditorWebExtension {
+ GObject parent;
+ EEditorWebExtensionPrivate *priv;
+};
+
+struct _EEditorWebExtensionClass
+{
+ GObjectClass parent_class;
+};
+
+GType e_editor_web_extension_get_type (void) G_GNUC_CONST;
+
+EEditorWebExtension *
+ e_editor_web_extension_get_default
+ (void);
+
+void e_editor_web_extension_initialize
+ (EEditorWebExtension *extension,
+ WebKitWebExtension *wk_extension);
+void e_editor_web_extension_dbus_register
+ (EEditorWebExtension *extension,
+ GDBusConnection *connection);
+GDBusConnection *
+ e_editor_web_extension_get_connection
+ (EEditorWebExtension *extension);
+
+#endif /* E_EDITOR_WEB_EXTENSION_H */
diff --git a/modules/web-inspector/Makefile.am b/modules/webkit-inspector/Makefile.am
similarity index 56%
rename from modules/web-inspector/Makefile.am
rename to modules/webkit-inspector/Makefile.am
index 237121e..eedaf12 100644
--- a/modules/web-inspector/Makefile.am
+++ b/modules/webkit-inspector/Makefile.am
@@ -1,24 +1,24 @@
-module_LTLIBRARIES = module-web-inspector.la
+module_LTLIBRARIES = module-webkit-inspector.la
-module_web_inspector_la_CPPFLAGS = \
+module_webkit_inspector_la_CPPFLAGS = \
$(AM_CPPFLAGS) \
-I$(top_srcdir) \
- -DG_LOG_DOMAIN=\"evolution-web-inspector\" \
+ -DG_LOG_DOMAIN=\"evolution-webkit-inspector\" \
$(EVOLUTION_DATA_SERVER_CFLAGS) \
$(GNOME_PLATFORM_CFLAGS) \
$(CODE_COVERAGE_CFLAGS) \
$(NULL)
-module_web_inspector_la_SOURCES = \
- evolution-web-inspector.c
+module_webkit_inspector_la_SOURCES = \
+ evolution-webkit-inspector.c
-module_web_inspector_la_LIBADD = \
+module_webkit_inspector_la_LIBADD = \
$(top_builddir)/e-util/libevolution-util.la \
$(EVOLUTION_DATA_SERVER_LIBS) \
$(GNOME_PLATFORM_LIBS) \
$(NULL)
-module_web_inspector_la_LDFLAGS = \
+module_webkit_inspector_la_LDFLAGS = \
-module -avoid-version $(NO_UNDEFINED) $(CODE_COVERAGE_LDFLAGS)
-include $(top_srcdir)/git.mk
diff --git a/modules/webkit-inspector/evolution-webkit-inspector.c
b/modules/webkit-inspector/evolution-webkit-inspector.c
new file mode 100644
index 0000000..4c9a141
--- /dev/null
+++ b/modules/webkit-inspector/evolution-webkit-inspector.c
@@ -0,0 +1,140 @@
+/*
+ * evolution-webkit-inspector.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.
+ *
+ * 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 General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <config.h>
+#include <glib/gi18n-lib.h>
+#include <gdk/gdkkeysyms.h>
+
+#include <libebackend/libebackend.h>
+
+#include <e-util/e-util.h>
+
+/* Standard GObject macros */
+#define E_TYPE_WEBKIT_INSPECTOR \
+ (e_webkit_inspector_get_type ())
+#define E_WEBKIT_INSPECTOR(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_WEBKIT_INSPECTOR, EWebKitInspector))
+
+/* <Control>+<Shift>+I */
+#define WEBKIT_INSPECTOR_MOD (GDK_CONTROL_MASK | GDK_SHIFT_MASK)
+#define WEBKIT_INSPECTOR_KEY (GDK_KEY_I)
+
+#define WEBKIT_INSPECTOR_SHORTCUT_SHOW(event) \
+ ((((event)->state & WEBKIT_INSPECTOR_MOD) == WEBKIT_INSPECTOR_MOD) && \
+ ((event)->keyval == WEBKIT_INSPECTOR_KEY))
+
+typedef struct _EWebKitInspector EWebKitInspector;
+typedef struct _EWebKitInspectorClass EWebKitInspectorClass;
+
+struct _EWebKitInspector {
+ EExtension parent;
+};
+
+struct _EWebKitInspectorClass {
+ EExtensionClass parent_class;
+};
+
+/* Module Entry Points */
+void e_module_load (GTypeModule *type_module);
+void e_module_unload (GTypeModule *type_module);
+
+/* Forward Declarations */
+GType e_webkit_inspector_get_type (void);
+
+G_DEFINE_DYNAMIC_TYPE (EWebKitInspector, e_webkit_inspector, E_TYPE_EXTENSION)
+
+static WebKitWebView *
+webkit_inspector_get_web_view (EWebKitInspector *extension)
+{
+ EExtensible *extensible;
+
+ extensible = e_extension_get_extensible (E_EXTENSION (extension));
+
+ return WEBKIT_WEB_VIEW (extensible);
+}
+
+static gboolean
+webkit_inspector_key_press_event_cb (WebKitWebView *web_view,
+ GdkEventKey *event)
+{
+ WebKitWebInspector *inspector;
+ gboolean handled = FALSE;
+
+ inspector = webkit_web_view_get_inspector (web_view);
+
+ if (WEBKIT_INSPECTOR_SHORTCUT_SHOW (event)) {
+ webkit_web_inspector_show (inspector);
+ handled = TRUE;
+ }
+
+ return handled;
+}
+
+static void
+webkit_inspector_constructed (GObject *object)
+{
+ EWebKitInspector *extension;
+ WebKitWebView *web_view;
+ WebKitSettings *settings;
+
+ /* Chain up to parent's method. */
+ G_OBJECT_CLASS (e_webkit_inspector_parent_class)->constructed (object);
+
+ extension = E_WEBKIT_INSPECTOR (object);
+ web_view = webkit_inspector_get_web_view (extension);
+ settings = webkit_web_view_get_settings (web_view);
+ webkit_settings_set_enable_developer_extras (settings, TRUE);
+
+ g_signal_connect (
+ web_view, "key-press-event",
+ G_CALLBACK (webkit_inspector_key_press_event_cb), NULL);
+}
+
+static void
+e_webkit_inspector_class_init (EWebKitInspectorClass *class)
+{
+ GObjectClass *object_class;
+ EExtensionClass *extension_class;
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->constructed = webkit_inspector_constructed;
+
+ extension_class = E_EXTENSION_CLASS (class);
+ extension_class->extensible_type = WEBKIT_TYPE_WEB_VIEW;
+}
+
+static void
+e_webkit_inspector_class_finalize (EWebKitInspectorClass *class)
+{
+}
+
+static void
+e_webkit_inspector_init (EWebKitInspector *extension)
+{
+}
+
+G_MODULE_EXPORT void
+e_module_load (GTypeModule *type_module)
+{
+ e_webkit_inspector_register_type (type_module);
+}
+
+G_MODULE_EXPORT void
+e_module_unload (GTypeModule *type_module)
+{
+}
diff --git a/plugins/external-editor/external-editor.c b/plugins/external-editor/external-editor.c
index 2709c84..f349b5f 100644
--- a/plugins/external-editor/external-editor.c
+++ b/plugins/external-editor/external-editor.c
@@ -150,16 +150,16 @@ enable_disable_composer (EMsgComposer *composer,
gboolean enable)
{
EHTMLEditor *editor;
- EHTMLEditorView *view;
+ EContentEditor *cnt_editor;
GtkAction *action;
GtkActionGroup *action_group;
g_return_if_fail (E_IS_MSG_COMPOSER (composer));
editor = e_msg_composer_get_editor (composer);
- view = e_html_editor_get_view (editor);
+ cnt_editor = e_html_editor_get_content_editor (editor);
- webkit_web_view_set_editable (WEBKIT_WEB_VIEW (view), enable);
+ e_content_editor_set_editable (cnt_editor, enable);
action = E_HTML_EDITOR_ACTION_EDIT_MENU (editor);
gtk_action_set_sensitive (action, enable);
@@ -192,20 +192,20 @@ update_composer_text (GArray *array)
{
EMsgComposer *composer;
EHTMLEditor *editor;
- EHTMLEditorView *view;
+ EContentEditor *cnt_editor;
gchar *text;
composer = g_array_index (array, gpointer, 0);
text = g_array_index (array, gpointer, 1);
editor = e_msg_composer_get_editor (composer);
- view = e_html_editor_get_view (editor);
+ cnt_editor = e_html_editor_get_content_editor (editor);
e_msg_composer_set_body_text (composer, text, FALSE);
enable_composer (composer);
- e_html_editor_view_set_changed (view, TRUE);
+ e_content_editor_set_changed (cnt_editor, TRUE);
g_free (text);
@@ -239,117 +239,19 @@ numlines (const gchar *text,
gint ctr = 0;
gint lineno = 0;
- while (text && *text && ctr < pos) {
- if (*text == '\n') {
- /* Because the get_caret_position is returning a position
- * without new lines, we can't increment the counter when
- * we hit the new line. */
+ while (text && *text && ctr <= pos) {
+ if (*text == '\n')
lineno++;
- } else {
- ctr++;
- }
- text++;
+ text++;
+ ctr++;
}
- if (lineno > 0)
+ if (lineno > 0) {
lineno++;
-
- return lineno;
-}
-
-static gint
-get_caret_offset (EHTMLEditorView *view)
-{
- gint ret_val;
- gchar *text;
- WebKitDOMDocument *document;
- WebKitDOMDOMWindow *dom_window;
- WebKitDOMDOMSelection *dom_selection;
- WebKitDOMNode *anchor;
- WebKitDOMRange *range;
-
- document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (view));
- dom_window = webkit_dom_document_get_default_view (document);
- dom_selection = webkit_dom_dom_window_get_selection (dom_window);
- g_object_unref (dom_window);
-
- if (webkit_dom_dom_selection_get_range_count (dom_selection) < 1) {
- g_object_unref (dom_selection);
- return 0;
}
- webkit_dom_dom_selection_collapse_to_start (dom_selection, NULL);
- /* Select the text from the current caret position to the beginning of the line. */
- webkit_dom_dom_selection_modify (dom_selection, "extend", "left", "lineBoundary");
-
- range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
- anchor = webkit_dom_dom_selection_get_anchor_node (dom_selection);
- text = webkit_dom_range_to_string (range, NULL);
- ret_val = strlen (text);
- g_free (text);
-
- webkit_dom_dom_selection_collapse_to_end (dom_selection, NULL);
-
- /* In the plain text mode we need to increase the return value by 2 per
- * citation level because of "> ". */
- if (!e_html_editor_view_get_html_mode (view)) {
- WebKitDOMNode *parent = anchor;
-
- while (parent && !WEBKIT_DOM_IS_HTML_BODY_ELEMENT (parent)) {
- if (WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (parent) &&
- element_has_class (WEBKIT_DOM_ELEMENT (parent), "-x-evo-plaintext-quoted"))
- ret_val += 2;
-
- parent = webkit_dom_node_get_parent_node (parent);
- }
- }
-
- g_object_unref (range);
- g_object_unref (dom_selection);
-
- return ret_val;
-}
-
-static gint
-get_caret_position (EHTMLEditorView *view)
-{
- gint ret_val;
- gchar *text;
- WebKitDOMDocument *document;
- WebKitDOMHTMLElement *body;
- WebKitDOMDOMWindow *dom_window;
- WebKitDOMDOMSelection *dom_selection;
- WebKitDOMRange *range, *range_clone;
-
- document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (view));
- dom_window = webkit_dom_document_get_default_view (document);
- dom_selection = webkit_dom_dom_window_get_selection (dom_window);
- g_object_unref (dom_window);
-
- if (webkit_dom_dom_selection_get_range_count (dom_selection) < 1) {
- g_object_unref (dom_selection);
- return 0;
- }
-
- range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
- range_clone = webkit_dom_range_clone_range (range, NULL);
-
- body = webkit_dom_document_get_body (document);
- /* Select the text from the beginning of the body to the current caret. */
- webkit_dom_range_set_start_before (
- range_clone, webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (body)), NULL);
-
- /* This is returning a text without new lines! */
- text = webkit_dom_range_to_string (range_clone, NULL);
- ret_val = strlen (text);
- g_free (text);
-
- g_object_unref (range_clone);
- g_object_unref (range);
- g_object_unref (dom_selection);
-
- return ret_val;
+ return lineno;
}
static gboolean external_editor_running = FALSE;
@@ -365,10 +267,10 @@ external_editor_thread (gpointer user_data)
gchar *editor_cmd_line = NULL, *editor_cmd = NULL, *content;
gint fd, position = -1, offset = -1;
EHTMLEditor *editor;
- EHTMLEditorView *view;
+ EContentEditor *cnt_editor;
editor = e_msg_composer_get_editor (composer);
- view = e_html_editor_get_view (editor);
+ cnt_editor = e_html_editor_get_content_editor (editor);
/* prefix temp files with evo so .*vimrc can be setup to recognize them */
fd = g_file_open_tmp ("evoXXXXXX", &filename, NULL);
@@ -377,8 +279,13 @@ external_editor_thread (gpointer user_data)
d (printf ("\n\aTemporary-file Name is : [%s] \n\a", filename));
/* Push the text (if there is one) from the composer to the file */
- content = e_html_editor_view_get_text_plain (view);
- g_file_set_contents (filename, content, strlen (content), NULL);
+ content = e_content_editor_get_content (
+ cnt_editor,
+ E_CONTENT_EDITOR_GET_TEXT_PLAIN |
+ E_CONTENT_EDITOR_GET_PROCESSED,
+ NULL, NULL);
+ if (content && *content)
+ g_file_set_contents (filename, content, strlen (content), NULL);
} else {
struct run_error_dialog_data *data;
@@ -406,14 +313,14 @@ external_editor_thread (gpointer user_data)
g_object_unref (settings);
if (g_strrstr (editor_cmd, "vim") != NULL &&
- ((position = get_caret_position (view)) > 0)) {
+ ((position = e_content_editor_get_caret_position (cnt_editor)) > 0)) {
gchar *tmp = editor_cmd;
gint lineno;
gboolean set_nofork;
set_nofork = g_strrstr (editor_cmd, "gvim") != NULL;
- offset = get_caret_offset (view);
+ offset = e_content_editor_get_caret_offset (cnt_editor);
/* Increment by 1 so that entering vim insert mode places you
* in the same entry position you were at in the html. */
offset++;
@@ -500,7 +407,7 @@ finished:
static void launch_editor (GtkAction *action, EMsgComposer *composer)
{
EHTMLEditor *editor;
- EHTMLEditorView *view;
+ EContentEditor *cnt_editor;
d (printf ("\n\nexternal_editor plugin is launched \n\n"));
@@ -510,9 +417,9 @@ static void launch_editor (GtkAction *action, EMsgComposer *composer)
}
editor = e_msg_composer_get_editor (composer);
- view = e_html_editor_get_view (editor);
+ cnt_editor = e_html_editor_get_content_editor (editor);
- e_html_editor_view_clear_history (view);
+ e_content_editor_clear_undo_redo_history (cnt_editor);
disable_composer (composer);
g_mutex_lock (&external_editor_running_lock);
@@ -596,10 +503,10 @@ e_plugin_ui_init (GtkUIManager *manager,
EMsgComposer *composer)
{
EHTMLEditor *editor;
- EHTMLEditorView *view;
+ EContentEditor *cnt_editor;
editor = e_msg_composer_get_editor (composer);
- view = e_html_editor_get_view (editor);
+ cnt_editor = e_html_editor_get_content_editor (editor);
/* Add actions to the "composer" action group. */
gtk_action_group_add_actions (
@@ -607,11 +514,11 @@ e_plugin_ui_init (GtkUIManager *manager,
entries, G_N_ELEMENTS (entries), composer);
g_signal_connect (
- view, "key_press_event",
+ cnt_editor, "key_press_event",
G_CALLBACK (key_press_cb), composer);
g_signal_connect (
- view, "delete-event",
+ cnt_editor, "delete-event",
G_CALLBACK (delete_cb), composer);
return TRUE;
diff --git a/plugins/mail-to-task/mail-to-task.c b/plugins/mail-to-task/mail-to-task.c
index 7774044..ef0fda4 100644
--- a/plugins/mail-to-task/mail-to-task.c
+++ b/plugins/mail-to-task/mail-to-task.c
@@ -799,7 +799,7 @@ typedef struct {
ECalClientSourceType source_type;
CamelFolder *folder;
GPtrArray *uids;
- gchar *selected_text;
+ const gchar *selected_text;
gboolean with_attendees;
}AsyncData;
@@ -1009,7 +1009,6 @@ do_mail_to_event (AsyncData *data)
g_object_unref (data->client_cache);
g_object_unref (data->source);
- g_free (data->selected_text);
g_free (data);
data = NULL;
@@ -1045,24 +1044,21 @@ text_contains_nonwhitespace (const gchar *text,
return p - text < len - 1 && c != 0;
}
-/* should be freed with g_free after done with it */
-static gchar *
+static const gchar *
get_selected_text (EMailReader *reader)
{
EMailDisplay *display;
- gchar *text = NULL;
+ const gchar *text = NULL;
display = e_mail_reader_get_mail_display (reader);
if (!e_web_view_is_selection_active (E_WEB_VIEW (display)))
return NULL;
- text = e_mail_display_get_selection_plain_text (display);
+ text = e_mail_display_get_selection_plain_text_sync (display, NULL, NULL);
- if (text == NULL || !text_contains_nonwhitespace (text, strlen (text))) {
- g_free (text);
+ if (text == NULL || !text_contains_nonwhitespace (text, strlen (text)))
return NULL;
- }
return text;
}
diff --git a/plugins/mailing-list-actions/mailing-list-actions.c
b/plugins/mailing-list-actions/mailing-list-actions.c
index 498a94d..58f58f6 100644
--- a/plugins/mailing-list-actions/mailing-list-actions.c
+++ b/plugins/mailing-list-actions/mailing-list-actions.c
@@ -116,6 +116,44 @@ async_context_free (AsyncContext *context)
g_slice_free (AsyncContext, context);
}
+typedef struct _SendMessageData {
+ gchar *url;
+ gchar *uid;
+} SendMessageData;
+
+static void
+send_message_composer_created_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ SendMessageData *smd = user_data;
+ EMsgComposer *composer;
+ GError *error = NULL;
+
+ g_return_if_fail (smd != NULL);
+
+ composer = e_msg_composer_new_finish (result, &error);
+ if (error) {
+ g_warning ("%s: Failed to create msg composer: %s", G_STRFUNC, error->message);
+ g_clear_error (&error);
+ } else {
+ EComposerHeaderTable *table;
+
+ /* directly send message */
+ e_msg_composer_setup_from_url (composer, smd->url);
+ table = e_msg_composer_get_header_table (composer);
+
+ if (smd->uid)
+ e_composer_header_table_set_identity_uid (table, smd->uid);
+
+ e_msg_composer_send (composer);
+ }
+
+ g_free (smd->url);
+ g_free (smd->uid);
+ g_free (smd);
+}
+
static void
emla_list_action_cb (CamelFolder *folder,
GAsyncResult *result,
@@ -124,7 +162,6 @@ emla_list_action_cb (CamelFolder *folder,
const gchar *header = NULL, *headerpos;
gchar *end, *url = NULL;
gint t;
- EMsgComposer *composer;
EAlertSink *alert_sink;
CamelMimeMessage *message;
gint send_message_response;
@@ -239,15 +276,13 @@ emla_list_action_cb (CamelFolder *folder,
url, NULL);
if (send_message_response == GTK_RESPONSE_YES) {
- EComposerHeaderTable *table;
+ SendMessageData *smd;
- /* directly send message */
- composer = e_msg_composer_new_from_url (shell, url);
- table = e_msg_composer_get_header_table (composer);
+ smd = g_new0 (SendMessageData, 1);
+ smd->url = g_strdup (url);
+ smd->uid = g_strdup (uid);
- if (uid != NULL)
- e_composer_header_table_set_identity_uid (table, uid);
- e_msg_composer_send (composer);
+ e_msg_composer_new (shell, send_message_composer_created_cb, smd);
} else if (send_message_response == GTK_RESPONSE_NO) {
/* show composer */
em_utils_compose_new_message_with_mailto (shell, url, folder);
diff --git a/plugins/templates/templates.c b/plugins/templates/templates.c
index 57229dd..3f98a6e 100644
--- a/plugins/templates/templates.c
+++ b/plugins/templates/templates.c
@@ -51,6 +51,7 @@ struct _AsyncContext {
EActivity *activity;
EMailReader *reader;
CamelMimeMessage *message;
+ CamelMimeMessage *template;
CamelFolder *template_folder;
gchar *source_folder_uri;
gchar *message_uid;
@@ -123,17 +124,11 @@ static gboolean plugin_enabled;
static void
async_context_free (AsyncContext *context)
{
- if (context->activity != NULL)
- g_object_unref (context->activity);
-
- if (context->reader != NULL)
- g_object_unref (context->reader);
-
- if (context->message != NULL)
- g_object_unref (context->message);
-
- if (context->template_folder != NULL)
- g_object_unref (context->template_folder);
+ g_clear_object (&context->activity);
+ g_clear_object (&context->reader);
+ g_clear_object (&context->message);
+ g_clear_object (&context->template);
+ g_clear_object (&context->template_folder);
g_free (context->source_folder_uri);
g_free (context->message_uid);
@@ -846,10 +841,11 @@ find_template_part_in_multipart (CamelMultipart *multipart,
}
static void
-create_new_message (CamelFolder *folder,
- GAsyncResult *result,
- AsyncContext *context)
+create_new_message_composer_created_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
{
+ AsyncContext *context = user_data;
EAlertSink *alert_sink;
CamelMimeMessage *new;
CamelMimeMessage *message;
@@ -859,24 +855,26 @@ create_new_message (CamelFolder *folder,
struct _camel_header_raw *header;
EMailBackend *backend;
EMailSession *session;
- EShell *shell;
const gchar *message_uid;
EMsgComposer *composer;
GError *error = NULL;
CamelMimePart *template_part = NULL;
+ CamelFolder *folder;
+
+ g_return_if_fail (context != NULL);
alert_sink = e_activity_get_alert_sink (context->activity);
- template = camel_folder_get_message_finish (folder, result, &error);
+ composer = e_msg_composer_new_finish (result, &error);
if (e_activity_handle_cancellation (context->activity, error)) {
- g_warn_if_fail (template == NULL);
+ g_warn_if_fail (context->template == NULL);
async_context_free (context);
g_error_free (error);
return;
} else if (error != NULL) {
- g_warn_if_fail (template == NULL);
+ g_warn_if_fail (context->template == NULL);
e_alert_submit (
alert_sink, "mail:no-retrieve-message",
error->message, NULL);
@@ -885,17 +883,16 @@ create_new_message (CamelFolder *folder,
return;
}
- g_return_if_fail (CAMEL_IS_MIME_MESSAGE (template));
+ g_return_if_fail (E_IS_MSG_COMPOSER (composer));
message = context->message;
message_uid = context->message_uid;
+ template = context->template;
backend = e_mail_reader_get_backend (context->reader);
session = e_mail_backend_get_session (backend);
- shell = e_shell_backend_get_shell (E_SHELL_BACKEND (backend));
- folder = e_mail_session_get_local_folder (
- session, E_MAIL_LOCAL_FOLDER_TEMPLATES);
+ folder = e_mail_session_get_local_folder (session, E_MAIL_LOCAL_FOLDER_TEMPLATES);
new = camel_mime_message_new ();
new_multipart = camel_multipart_new ();
@@ -989,14 +986,12 @@ create_new_message (CamelFolder *folder,
template, CAMEL_RECIPIENT_TYPE_BCC));
/* Create the composer */
- composer = em_utils_edit_message (
- shell, folder, new, message_uid, TRUE);
+ em_utils_edit_message (composer, folder, new, message_uid, TRUE);
if (composer && context->source_folder_uri && context->message_uid)
e_msg_composer_set_source_headers (
composer, context->source_folder_uri,
context->message_uid, CAMEL_MESSAGE_ANSWERED | CAMEL_MESSAGE_SEEN);
- g_object_unref (template);
g_object_unref (new_multipart);
g_object_unref (new);
@@ -1004,6 +999,51 @@ create_new_message (CamelFolder *folder,
}
static void
+create_new_message (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ AsyncContext *context = user_data;
+ EAlertSink *alert_sink;
+ EMailBackend *backend;
+ EShell *shell;
+ CamelFolder *folder;
+ GError *error = NULL;
+
+ g_return_if_fail (CAMEL_IS_FOLDER (source_object));
+ g_return_if_fail (context != NULL);
+
+ folder = CAMEL_FOLDER (source_object);
+
+ alert_sink = e_activity_get_alert_sink (context->activity);
+
+ context->template = camel_folder_get_message_finish (folder, result, &error);
+
+ if (e_activity_handle_cancellation (context->activity, error)) {
+ g_warn_if_fail (context->template == NULL);
+ async_context_free (context);
+ g_error_free (error);
+ return;
+
+ } else if (error != NULL) {
+ g_warn_if_fail (context->template == NULL);
+ e_alert_submit (
+ alert_sink, "mail:no-retrieve-message",
+ error->message, NULL);
+ async_context_free (context);
+ g_error_free (error);
+ return;
+ }
+
+ g_return_if_fail (CAMEL_IS_MIME_MESSAGE (context->template));
+
+ backend = e_mail_reader_get_backend (context->reader);
+ shell = e_shell_backend_get_shell (E_SHELL_BACKEND (backend));
+
+ e_msg_composer_new (shell, create_new_message_composer_created_cb, context);
+}
+
+static void
template_got_source_message (CamelFolder *folder,
GAsyncResult *result,
AsyncContext *context)
@@ -1044,8 +1084,7 @@ template_got_source_message (CamelFolder *folder,
context->template_folder,
context->template_message_uid,
G_PRIORITY_DEFAULT, cancellable,
- (GAsyncReadyCallback) create_new_message,
- context);
+ create_new_message, context);
}
static void
diff --git a/po/POTFILES.in b/po/POTFILES.in
index b536530..218cb2d 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -145,6 +145,7 @@ em-format/e-mail-parser-message-external.c
em-format/e-mail-parser-multipart-encrypted.c
em-format/e-mail-parser-multipart-signed.c
em-format/e-mail-part-headers.c
+em-format/e-mail-part-secure-button.c
em-format/e-mail-part-utils.c
e-util/ea-calendar-item.c
e-util/e-action-combo-box.c
@@ -213,7 +214,6 @@ e-util/e-html-editor-replace-dialog.c
e-util/e-html-editor-spell-check-dialog.c
e-util/e-html-editor-table-dialog.c
e-util/e-html-editor-text-dialog.c
-e-util/e-html-editor-view.c
e-util/e-image-chooser.c
e-util/e-image-chooser-dialog.c
e-util/e-import-assistant.c
@@ -463,7 +463,7 @@ modules/text-highlight/languages.c
modules/vcard-inline/e-mail-formatter-vcard.c
modules/vcard-inline/e-mail-parser-vcard.c
modules/vcard-inline/e-mail-part-vcard.c
-modules/web-inspector/evolution-web-inspector.c
+modules/webkit-inspector/evolution-webkit-inspector.c
plugins/attachment-reminder/attachment-reminder.c
plugins/attachment-reminder/org-gnome-attachment-reminder.error.xml
plugins/attachment-reminder/org-gnome-evolution-attachment-reminder.eplug.xml
diff --git a/shell/e-shell.c b/shell/e-shell.c
index 30c4670..c3d0be6 100644
--- a/shell/e-shell.c
+++ b/shell/e-shell.c
@@ -1628,13 +1628,13 @@ shell_initable_init (GInitable *initable,
/* Configure WebKit's default SoupSession. */
proxy_source = e_source_registry_ref_builtin_proxy (registry);
-
+/* FIXME WK2
g_object_set (
webkit_get_default_session (),
SOUP_SESSION_PROXY_RESOLVER,
G_PROXY_RESOLVER (proxy_source),
NULL);
-
+*/
g_object_unref (proxy_source);
g_object_unref (registry);
diff --git a/shell/main.c b/shell/main.c
index 1083c7d..f472b2c 100644
--- a/shell/main.c
+++ b/shell/main.c
@@ -52,7 +52,7 @@
#include <libxml/parser.h>
#include <libxml/tree.h>
-#include <webkit/webkit.h>
+#include <webkit2/webkit2.h>
#include "e-shell.h"
#include "e-shell-migrate.h"
@@ -569,6 +569,7 @@ main (gint argc,
handle_term_signal, NULL, NULL);
#endif
+ e_util_init_main_thread (NULL);
e_passwords_init ();
gtk_window_set_default_icon_name ("evolution");
@@ -592,6 +593,7 @@ main (gint argc,
g_object_unref (settings);
#endif
+ /* FIXME WK2 - Look if we still need this it looks like it's not. */
/* Workaround https://bugzilla.gnome.org/show_bug.cgi?id=683548 */
if (!quit)
g_type_ensure (WEBKIT_TYPE_WEB_VIEW);
diff --git a/ui/evolution-mail.ui b/ui/evolution-mail.ui
index 7d95d73..322c83b 100644
--- a/ui/evolution-mail.ui
+++ b/ui/evolution-mail.ui
@@ -19,6 +19,7 @@
<placeholder name='view-custom-menus'>
<menu action='mail-preview-menu'>
<menuitem action='mail-preview'/>
+ <menuitem action='mail-attachment-bar'/>
<separator/>
<menuitem action='mail-view-classic'/>
<menuitem action='mail-view-vertical'/>
diff --git a/web-extensions/Makefile.am b/web-extensions/Makefile.am
new file mode 100644
index 0000000..07854c2
--- /dev/null
+++ b/web-extensions/Makefile.am
@@ -0,0 +1,44 @@
+webextensions_LTLIBRARIES = libewebextension.la libedomutils.la
+
+libedomutils_la_SOURCES = \
+ e-dom-utils.h \
+ e-dom-utils.c
+
+libedomutils_la_CPPFLAGS = \
+ $(AM_CPPFLAGS) \
+ -I$(top_srcdir) \
+ -DEVOLUTION_IMAGESDIR=\""$(imagesdir)"\" \
+ $(EVOLUTION_DATA_SERVER_CFLAGS) \
+ $(GNOME_PLATFORM_CFLAGS)
+
+libedomutils_la_LIBADD = \
+ $(top_builddir)/e-util/libevolution-util.la \
+ $(EVOLUTION_DATA_SERVER_LIBS) \
+ $(GNOME_PLATFORM_LIBS)
+
+libewebextension_la_SOURCES = \
+ e-web-extension.h \
+ e-web-extension-names.h \
+ e-dom-utils.h \
+ e-web-extension.c \
+ e-web-extension-main.c \
+ e-dom-utils.c
+
+libewebextension_la_CPPFLAGS = \
+ $(AM_CPPFLAGS) \
+ -I$(top_srcdir) \
+ -DEVOLUTION_IMAGESDIR=\""$(imagesdir)"\" \
+ $(EVOLUTION_DATA_SERVER_CFLAGS) \
+ $(GNOME_PLATFORM_CFLAGS) \
+ $(WEB_EXTENSIONS_CFLAGS)
+
+libewebextension_la_LIBADD = \
+ $(top_builddir)/e-util/libevolution-util.la \
+ $(EVOLUTION_DATA_SERVER_LIBS) \
+ $(GNOME_PLATFORM_LIBS) \
+ $(WEB_EXTENSIONS_LIBS)
+
+libewebextension_la_LDFLAGS = \
+ -module -avoid-version -no-undefined
+
+-include $(top_srcdir)/git.mk
diff --git a/web-extensions/e-dom-utils.c b/web-extensions/e-dom-utils.c
new file mode 100644
index 0000000..f671f77
--- /dev/null
+++ b/web-extensions/e-dom-utils.c
@@ -0,0 +1,2022 @@
+/*
+ * e-dom-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/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#define WEBKIT_DOM_USE_UNSTABLE_API
+#include <webkitdom/WebKitDOMDOMSelection.h>
+#include <webkitdom/WebKitDOMDOMWindowUnstable.h>
+#include <webkitdom/WebKitDOMHTMLElementUnstable.h>
+
+#include "e-web-extension.h"
+#include "e-web-extension-names.h"
+
+#include "e-dom-utils.h"
+
+void
+e_dom_utils_replace_local_image_links (WebKitDOMDocument *document)
+{
+ gint ii, length;
+ WebKitDOMNodeList *list = NULL;
+
+ list = webkit_dom_document_query_selector_all (
+ document, "img[src^=\"file://\"]", NULL);
+ length = webkit_dom_node_list_get_length (list);
+
+ for (ii = 0; ii < length; ii++) {
+ gchar *src, *new_src;
+ WebKitDOMHTMLImageElement *img;
+
+ img = WEBKIT_DOM_HTML_IMAGE_ELEMENT (
+ webkit_dom_node_list_item (list, ii));
+ src = webkit_dom_html_image_element_get_src (img);
+
+ /* this forms "evo-file://", which can be loaded,
+ * while "file://" cannot be, due to WebKit policy */
+ new_src = g_strconcat ("evo-", src, NULL);
+ webkit_dom_html_image_element_set_src (img, new_src);
+ g_free (new_src);
+ g_free (src);
+ g_object_unref (img);
+ }
+ g_clear_object (&list);
+
+ list = webkit_dom_document_query_selector_all (
+ document, "iframe", NULL);
+ length = webkit_dom_node_list_get_length (list);
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMDocument *content_document;
+ WebKitDOMHTMLIFrameElement *iframe;
+
+ iframe = WEBKIT_DOM_HTML_IFRAME_ELEMENT (
+ webkit_dom_node_list_item (list, ii));
+
+ content_document =
+ webkit_dom_html_iframe_element_get_content_document (iframe);
+
+ if (content_document && WEBKIT_DOM_IS_DOCUMENT (content_document))
+ e_dom_utils_replace_local_image_links (content_document);
+ g_object_unref (iframe);
+ }
+ g_clear_object (&list);
+}
+
+gboolean
+e_dom_utils_document_has_selection (WebKitDOMDocument *document)
+{
+ gboolean ret_val = FALSE;
+ WebKitDOMDOMWindow *dom_window = NULL;
+ WebKitDOMDOMSelection *dom_selection = NULL;
+
+ if (!document)
+ return FALSE;
+
+ dom_window = webkit_dom_document_get_default_view (document);
+ if (!dom_window)
+ goto out;
+
+ dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+ if (!WEBKIT_DOM_IS_DOM_SELECTION (dom_selection))
+ goto out;
+
+ if (webkit_dom_dom_selection_get_is_collapsed (dom_selection))
+ goto out;
+
+ ret_val = TRUE;
+ out:
+ g_clear_object (&dom_window);
+ g_clear_object (&dom_selection);
+
+ if (!ret_val) {
+ WebKitDOMHTMLCollection *frames = NULL;
+ gulong ii, length;
+
+ frames = webkit_dom_document_get_elements_by_tag_name_as_html_collection (document, "iframe");
+ length = webkit_dom_html_collection_get_length (frames);
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMNode *node;
+ WebKitDOMDocument *content_document;
+
+ node = webkit_dom_html_collection_item (frames, ii);
+ content_document = webkit_dom_html_iframe_element_get_content_document (
+ WEBKIT_DOM_HTML_IFRAME_ELEMENT (node));
+
+ if ((ret_val = e_dom_utils_document_has_selection (content_document))) {
+ g_object_unref (node);
+ break;
+ }
+
+ g_object_unref (node);
+ }
+
+ g_clear_object (&frames);
+ }
+
+ return ret_val;
+}
+
+
+gchar *
+e_dom_utils_get_document_content_html (WebKitDOMDocument *document)
+{
+ WebKitDOMElement *element;
+
+ element = webkit_dom_document_get_document_element (document);
+
+ return webkit_dom_element_get_outer_html (element);
+}
+
+static gboolean
+element_is_in_pre_tag (WebKitDOMNode *node)
+{
+ WebKitDOMElement *element;
+
+ if (!node)
+ return FALSE;
+
+ while (element = webkit_dom_node_get_parent_element (node), element) {
+ node = WEBKIT_DOM_NODE (element);
+
+ if (WEBKIT_DOM_IS_HTML_PRE_ELEMENT (element)) {
+ return TRUE;
+ } else if (WEBKIT_DOM_IS_HTML_IFRAME_ELEMENT (element)) {
+ break;
+ }
+ }
+
+ return FALSE;
+}
+
+static gchar *
+get_frame_selection_html (WebKitDOMElement *iframe)
+{
+ WebKitDOMDocument *content_document;
+ WebKitDOMDOMWindow *dom_window = NULL;
+ WebKitDOMDOMSelection *dom_selection = NULL;
+ WebKitDOMHTMLCollection *frames = NULL;
+ gulong ii, length;
+
+ content_document = webkit_dom_html_iframe_element_get_content_document (
+ WEBKIT_DOM_HTML_IFRAME_ELEMENT (iframe));
+
+ if (!content_document)
+ return NULL;
+
+ dom_window = webkit_dom_document_get_default_view (content_document);
+ dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+ g_clear_object (&dom_window);
+ if (dom_selection && (webkit_dom_dom_selection_get_range_count (dom_selection) > 0)) {
+ WebKitDOMRange *range = NULL;
+ WebKitDOMElement *element;
+ WebKitDOMDocumentFragment *fragment;
+
+ range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+ if (range != NULL) {
+ gchar *inner_html;
+ WebKitDOMNode *node;
+
+ fragment = webkit_dom_range_clone_contents (
+ range, NULL);
+
+ element = webkit_dom_document_create_element (
+ content_document, "DIV", NULL);
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (element),
+ WEBKIT_DOM_NODE (fragment), NULL);
+
+ inner_html = webkit_dom_element_get_inner_html (element);
+
+ node = webkit_dom_range_get_start_container (range, NULL);
+ if (element_is_in_pre_tag (node)) {
+ gchar *tmp = inner_html;
+ inner_html = g_strconcat ("<pre>", tmp, "</pre>", NULL);
+ g_free (tmp);
+ }
+
+ g_clear_object (&range);
+ g_clear_object (&dom_selection);
+ return inner_html;
+ }
+ }
+
+ g_clear_object (&dom_selection);
+
+ frames = webkit_dom_document_get_elements_by_tag_name_as_html_collection (content_document, "iframe");
+ length = webkit_dom_html_collection_get_length (frames);
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMNode *node;
+ gchar *text;
+
+ node = webkit_dom_html_collection_item (frames, ii);
+
+ text = get_frame_selection_html (
+ WEBKIT_DOM_ELEMENT (node));
+
+ g_object_unref (node);
+ if (text != NULL) {
+ g_clear_object (&frames);
+ return text;
+ }
+ }
+
+ g_clear_object (&frames);
+
+ return NULL;
+}
+
+gchar *
+e_dom_utils_get_selection_content_html (WebKitDOMDocument *document)
+{
+ WebKitDOMHTMLCollection *frames = NULL;
+ gulong ii, length;
+
+ if (!e_dom_utils_document_has_selection (document))
+ return NULL;
+
+ frames = webkit_dom_document_get_elements_by_tag_name_as_html_collection (document, "iframe");
+ length = webkit_dom_html_collection_get_length (frames);
+
+ for (ii = 0; ii < length; ii++) {
+ gchar *text;
+ WebKitDOMNode *node;
+
+ node = webkit_dom_html_collection_item (frames, ii);
+
+ text = get_frame_selection_html (
+ WEBKIT_DOM_ELEMENT (node));
+
+ g_object_unref (node);
+ if (text != NULL) {
+ g_clear_object (&frames);
+ return text;
+ }
+ }
+
+ g_clear_object (&frames);
+ return NULL;
+}
+
+static gchar *
+get_frame_selection_content_text (WebKitDOMElement *iframe)
+{
+ WebKitDOMDocument *content_document;
+ WebKitDOMDOMWindow *dom_window = NULL;
+ WebKitDOMDOMSelection *dom_selection = NULL;
+ WebKitDOMHTMLCollection *frames = NULL;
+ gulong ii, length;
+
+ content_document = webkit_dom_html_iframe_element_get_content_document (
+ WEBKIT_DOM_HTML_IFRAME_ELEMENT (iframe));
+
+ if (!content_document)
+ return NULL;
+
+ dom_window = webkit_dom_document_get_default_view (content_document);
+ dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+ g_clear_object (&dom_window);
+ if (dom_selection && (webkit_dom_dom_selection_get_range_count (dom_selection) > 0)) {
+ WebKitDOMRange *range = NULL;
+ gchar *text = NULL;
+
+ range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+ if (range)
+ text = webkit_dom_range_to_string (range, NULL);
+ g_clear_object (&range);
+ g_clear_object (&dom_selection);
+ return text;
+ }
+ g_clear_object (&dom_selection);
+
+ frames = webkit_dom_document_get_elements_by_tag_name_as_html_collection (content_document, "iframe");
+ length = webkit_dom_html_collection_get_length (frames);
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMNode *node;
+ gchar *text;
+
+ node = webkit_dom_html_collection_item (frames, ii);
+
+ text = get_frame_selection_content_text (
+ WEBKIT_DOM_ELEMENT (node));
+
+ g_object_unref (node);
+ if (text != NULL) {
+ g_clear_object (&frames);
+ return text;
+ }
+ }
+
+ g_clear_object (&frames);
+ return NULL;
+}
+
+gchar *
+e_dom_utils_get_selection_content_text (WebKitDOMDocument *document)
+{
+ WebKitDOMHTMLCollection *frames = NULL;
+ gulong ii, length;
+
+ frames = webkit_dom_document_get_elements_by_tag_name_as_html_collection (document, "iframe");
+ length = webkit_dom_html_collection_get_length (frames);
+
+ for (ii = 0; ii < length; ii++) {
+ gchar *text;
+ WebKitDOMNode *node;
+
+ node = webkit_dom_html_collection_item (frames, ii);
+
+ text = get_frame_selection_content_text (
+ WEBKIT_DOM_ELEMENT (node));
+
+ g_object_unref (node);
+ if (text != NULL) {
+ g_clear_object (&frames);
+ return text;
+ }
+ }
+
+ g_clear_object (&frames);
+ return NULL;
+}
+
+void
+e_dom_utils_create_and_add_css_style_sheet (WebKitDOMDocument *document,
+ const gchar *style_sheet_id)
+{
+ WebKitDOMElement *style_element;
+
+ style_element = webkit_dom_document_get_element_by_id (document, style_sheet_id);
+
+ if (!style_element) {
+ WebKitDOMText *dom_text;
+ WebKitDOMHTMLHeadElement *head;
+
+ dom_text = webkit_dom_document_create_text_node (document, "");
+
+ /* Create new <style> element */
+ style_element = webkit_dom_document_create_element (document, "style", NULL);
+ webkit_dom_element_set_id (
+ style_element,
+ style_sheet_id);
+ webkit_dom_html_style_element_set_media (
+ WEBKIT_DOM_HTML_STYLE_ELEMENT (style_element),
+ "screen");
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (style_element),
+ /* WebKit hack - we have to insert empty TextNode into style element */
+ WEBKIT_DOM_NODE (dom_text),
+ NULL);
+
+ head = webkit_dom_document_get_head (document);
+
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (head),
+ WEBKIT_DOM_NODE (style_element),
+ NULL);
+
+ g_object_unref (head);
+ g_object_unref (dom_text);
+ g_object_unref (style_element);
+ }
+}
+
+static void
+add_css_rule_into_style_sheet (WebKitDOMDocument *document,
+ const gchar *style_sheet_id,
+ const gchar *selector,
+ const gchar *style)
+{
+ WebKitDOMElement *style_element;
+ WebKitDOMStyleSheet *sheet = NULL;
+ WebKitDOMCSSRuleList *rules_list = NULL;
+ gint length, ii, selector_length;
+ gboolean removed = FALSE;
+
+ g_return_if_fail (selector != NULL);
+
+ selector_length = strlen (selector);
+ style_element = webkit_dom_document_get_element_by_id (document, style_sheet_id);
+
+ if (!style_element) {
+ e_dom_utils_create_and_add_css_style_sheet (document, style_sheet_id);
+ style_element = webkit_dom_document_get_element_by_id (document, style_sheet_id);
+ }
+
+ /* Get sheet that is associated with style element */
+ sheet = webkit_dom_html_style_element_get_sheet (WEBKIT_DOM_HTML_STYLE_ELEMENT (style_element));
+
+ rules_list = webkit_dom_css_style_sheet_get_css_rules (WEBKIT_DOM_CSS_STYLE_SHEET (sheet));
+ length = webkit_dom_css_rule_list_get_length (rules_list);
+
+ /* Check if rule exists */
+ for (ii = 0; ii < length && !removed; ii++) {
+ WebKitDOMCSSRule *rule;
+ gchar *rule_text = NULL;
+
+ rule = webkit_dom_css_rule_list_item (rules_list, ii);
+
+ g_return_if_fail (WEBKIT_DOM_IS_CSS_RULE (rule));
+
+ rule_text = webkit_dom_css_rule_get_css_text (rule);
+
+ /* Find the start of the style => end of the selector */
+ if (rule_text && selector && g_str_has_prefix (rule_text, selector) &&
+ rule_text[selector_length] == ' ' && rule_text[selector_length + 1] == '{') {
+ /* If exists remove it */
+ webkit_dom_css_style_sheet_remove_rule (
+ WEBKIT_DOM_CSS_STYLE_SHEET (sheet),
+ ii, NULL);
+ length--;
+ removed = TRUE;
+ }
+
+ g_free (rule_text);
+ g_object_unref (rule);
+ }
+
+ g_clear_object (&rules_list);
+
+ /* Insert the rule at the end, so it will override previously inserted */
+ webkit_dom_css_style_sheet_add_rule (
+ WEBKIT_DOM_CSS_STYLE_SHEET (sheet), selector, style, length, NULL);
+
+ g_clear_object (&sheet);
+ g_object_unref (style_element);
+}
+
+static void
+add_css_rule_into_style_sheet_recursive (WebKitDOMDocument *document,
+ const gchar *style_sheet_id,
+ const gchar *selector,
+ const gchar *style)
+{
+ WebKitDOMHTMLCollection *frames = NULL;
+ gint ii, length;
+
+ /* Add rule to document */
+ add_css_rule_into_style_sheet (
+ document,
+ style_sheet_id,
+ selector,
+ style);
+
+ frames = webkit_dom_document_get_elements_by_tag_name_as_html_collection (document, "iframe");
+ length = webkit_dom_html_collection_get_length (frames);
+
+ /* Add rules to every sub document */
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMDocument *content_document = NULL;
+ WebKitDOMNode *node;
+
+ node = webkit_dom_html_collection_item (frames, ii);
+ content_document =
+ webkit_dom_html_iframe_element_get_content_document (
+ WEBKIT_DOM_HTML_IFRAME_ELEMENT (node));
+
+ if (!content_document)
+ continue;
+
+ add_css_rule_into_style_sheet_recursive (
+ content_document,
+ style_sheet_id,
+ selector,
+ style);
+ g_object_unref (node);
+ }
+ g_clear_object (&frames);
+}
+
+void
+e_dom_utils_add_css_rule_into_style_sheet (WebKitDOMDocument *document,
+ const gchar *style_sheet_id,
+ const gchar *selector,
+ const gchar *style)
+{
+ g_return_if_fail (style_sheet_id && *style_sheet_id);
+ g_return_if_fail (selector && *selector);
+ g_return_if_fail (style && *style);
+
+ add_css_rule_into_style_sheet_recursive (
+ document,
+ style_sheet_id,
+ selector,
+ style);
+}
+
+static void
+collapse_contacts_list (WebKitDOMEventTarget *event_target,
+ WebKitDOMEvent *event,
+ gpointer user_data)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *list;
+ gchar *id, *list_id;
+ gchar *imagesdir, *src;
+ gboolean hidden;
+
+ document = user_data;
+ id = webkit_dom_element_get_id (WEBKIT_DOM_ELEMENT (event_target));
+
+ if (!id)
+ return;
+
+ list_id = g_strconcat ("list-", id, NULL);
+ list = webkit_dom_document_get_element_by_id (document, list_id);
+ g_free (id);
+ g_free (list_id);
+
+ if (list == NULL)
+ return;
+
+ imagesdir = g_filename_to_uri (EVOLUTION_IMAGESDIR, NULL, NULL);
+ hidden = webkit_dom_html_element_get_hidden (WEBKIT_DOM_HTML_ELEMENT (list));
+
+ if (hidden)
+ src = g_strdup_printf ("evo-file://%s/minus.png", imagesdir);
+ else
+ src = g_strdup_printf ("evo-file://%s/plus.png", imagesdir);
+
+ webkit_dom_html_element_set_hidden (
+ WEBKIT_DOM_HTML_ELEMENT (list), !hidden);
+ webkit_dom_html_image_element_set_src (
+ WEBKIT_DOM_HTML_IMAGE_ELEMENT (event_target), src);
+
+ g_free (src);
+ g_free (imagesdir);
+}
+
+static void
+toggle_headers_visibility (WebKitDOMElement *button,
+ WebKitDOMEvent *event,
+ WebKitDOMDocument *document)
+{
+ WebKitDOMElement *short_headers = NULL, *full_headers = NULL;
+ WebKitDOMCSSStyleDeclaration *css_short = NULL, *css_full = NULL;
+ gboolean expanded;
+ const gchar *path;
+ gchar *css_value;
+
+ short_headers = webkit_dom_document_get_element_by_id (
+ document, "__evo-short-headers");
+ if (short_headers == NULL)
+ return;
+
+ css_short = webkit_dom_element_get_style (short_headers);
+
+ full_headers = webkit_dom_document_get_element_by_id (
+ document, "__evo-full-headers");
+ if (full_headers == NULL)
+ goto clean;
+
+ css_full = webkit_dom_element_get_style (full_headers);
+ css_value = webkit_dom_css_style_declaration_get_property_value (
+ css_full, "display");
+ expanded = (g_strcmp0 (css_value, "table") == 0);
+ g_free (css_value);
+
+ webkit_dom_css_style_declaration_set_property (
+ css_full, "display",
+ expanded ? "none" : "table", "", NULL);
+ webkit_dom_css_style_declaration_set_property (
+ css_short, "display",
+ expanded ? "table" : "none", "", NULL);
+
+ if (expanded)
+ path = "evo-file://" EVOLUTION_IMAGESDIR "/plus.png";
+ else
+ path = "evo-file://" EVOLUTION_IMAGESDIR "/minus.png";
+
+ webkit_dom_html_image_element_set_src (
+ WEBKIT_DOM_HTML_IMAGE_ELEMENT (button), path);
+ clean:
+ g_clear_object (&short_headers);
+ g_clear_object (&css_short);
+ g_clear_object (&full_headers);
+ g_clear_object (&css_full);
+}
+
+static void
+toggle_address_visibility (WebKitDOMElement *button,
+ WebKitDOMEvent *event,
+ GDBusConnection *connection)
+{
+ WebKitDOMElement *full_addr = NULL, *ellipsis = NULL;
+ WebKitDOMElement *parent = NULL, *bold = NULL;
+ WebKitDOMCSSStyleDeclaration *css_full = NULL, *css_ellipsis = NULL;
+ const gchar *path;
+ gchar *property_value;
+ gboolean expanded;
+ GError *error = NULL;
+
+ /* <b> element */
+ bold = webkit_dom_node_get_parent_element (WEBKIT_DOM_NODE (button));
+ /* <td> element */
+ parent = webkit_dom_node_get_parent_element (WEBKIT_DOM_NODE (bold));
+ g_object_unref (bold);
+
+ full_addr = webkit_dom_element_query_selector (parent, "#__evo-moreaddr", NULL);
+
+ if (!full_addr)
+ goto clean;
+
+ css_full = webkit_dom_element_get_style (full_addr);
+
+ ellipsis = webkit_dom_element_query_selector (parent, "#__evo-moreaddr-ellipsis", NULL);
+
+ if (!ellipsis)
+ goto clean;
+
+ css_ellipsis = webkit_dom_element_get_style (ellipsis);
+
+ property_value = webkit_dom_css_style_declaration_get_property_value (css_full, "display");
+ expanded = g_strcmp0 (property_value, "inline") == 0;
+ g_free (property_value);
+
+ webkit_dom_css_style_declaration_set_property (
+ css_full, "display", (expanded ? "none" : "inline"), "", NULL);
+ webkit_dom_css_style_declaration_set_property (
+ css_ellipsis, "display", (expanded ? "inline" : "none"), "", NULL);
+
+ if (expanded)
+ path = "evo-file://" EVOLUTION_IMAGESDIR "/plus.png";
+ else
+ path = "evo-file://" EVOLUTION_IMAGESDIR "/minus.png";
+
+ if (!WEBKIT_DOM_IS_HTML_IMAGE_ELEMENT (button)) {
+ WebKitDOMElement *element;
+
+ element = webkit_dom_element_query_selector (parent, "#__evo-moreaddr-img", NULL);
+ if (!element)
+ goto clean;
+
+ webkit_dom_html_image_element_set_src (WEBKIT_DOM_HTML_IMAGE_ELEMENT (element), path);
+
+ g_object_unref (element);
+ } else
+ webkit_dom_html_image_element_set_src (WEBKIT_DOM_HTML_IMAGE_ELEMENT (button), path);
+
+ g_dbus_connection_emit_signal (
+ connection,
+ NULL,
+ E_WEB_EXTENSION_OBJECT_PATH,
+ E_WEB_EXTENSION_INTERFACE,
+ "HeadersCollapsed",
+ g_variant_new ("(b)", expanded),
+ &error);
+
+ if (error) {
+ g_warning ("Error emitting signal HeadersCollapsed: %s\n", error->message);
+ g_error_free (error);
+ }
+
+ clean:
+ g_clear_object (&css_full);
+ g_clear_object (&css_ellipsis);
+ g_clear_object (&full_addr);
+ g_clear_object (&ellipsis);
+ g_clear_object (&parent);
+}
+
+static void
+e_dom_utils_bind_dom (WebKitDOMDocument *document,
+ const gchar *selector,
+ const gchar *event,
+ gpointer callback,
+ gpointer user_data)
+{
+ WebKitDOMNodeList *nodes = NULL;
+ gulong ii, length;
+
+ nodes = webkit_dom_document_query_selector_all (
+ document, selector, NULL);
+
+ length = webkit_dom_node_list_get_length (nodes);
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMNode *node;
+
+ node = webkit_dom_node_list_item (nodes, ii);
+ webkit_dom_event_target_add_event_listener (
+ WEBKIT_DOM_EVENT_TARGET (node), event,
+ G_CALLBACK (callback), FALSE, user_data);
+ }
+ g_clear_object (&nodes);
+}
+
+static void
+e_dom_utils_bind_elements_recursively (WebKitDOMDocument *document,
+ const gchar *selector,
+ const gchar *event,
+ gpointer callback,
+ gpointer user_data)
+{
+ WebKitDOMNodeList *nodes = NULL;
+ WebKitDOMHTMLCollection *frames = NULL;
+ gulong ii, length;
+
+ nodes = webkit_dom_document_query_selector_all (
+ document, selector, NULL);
+
+ length = webkit_dom_node_list_get_length (nodes);
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMNode *node;
+
+ node = webkit_dom_node_list_item (nodes, ii);
+ webkit_dom_event_target_add_event_listener (
+ WEBKIT_DOM_EVENT_TARGET (node), event,
+ G_CALLBACK (callback), FALSE, user_data);
+ }
+ g_clear_object (&nodes);
+
+ frames = webkit_dom_document_get_elements_by_tag_name_as_html_collection (document, "iframe");
+ length = webkit_dom_html_collection_get_length (frames);
+
+ /* Add rules to every sub document */
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMDocument *content_document = NULL;
+ WebKitDOMNode *node;
+
+ node = webkit_dom_html_collection_item (frames, ii);
+ content_document =
+ webkit_dom_html_iframe_element_get_content_document (
+ WEBKIT_DOM_HTML_IFRAME_ELEMENT (node));
+
+ if (!content_document)
+ continue;
+
+ e_dom_utils_bind_elements_recursively (
+ content_document,
+ selector,
+ event,
+ callback,
+ user_data);
+ }
+ g_clear_object (&frames);
+}
+
+static void
+element_focus_cb (WebKitDOMElement *element,
+ WebKitDOMEvent *event,
+ GDBusConnection *connection)
+{
+ g_dbus_connection_call (
+ connection,
+ E_WEB_EXTENSION_SERVICE_NAME,
+ E_WEB_EXTENSION_OBJECT_PATH,
+ E_WEB_EXTENSION_INTERFACE,
+ "Set",
+ g_variant_new (
+ "(ssv)",
+ E_WEB_EXTENSION_INTERFACE,
+ "NeedInput",
+ g_variant_new_boolean (TRUE)),
+ NULL,
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+
+}
+
+static void
+element_blur_cb (WebKitDOMElement *element,
+ WebKitDOMEvent *event,
+ GDBusConnection *connection)
+{
+ g_dbus_connection_call (
+ connection,
+ E_WEB_EXTENSION_SERVICE_NAME,
+ E_WEB_EXTENSION_OBJECT_PATH,
+ E_WEB_EXTENSION_INTERFACE,
+ "Set",
+ g_variant_new (
+ "(ssv)",
+ E_WEB_EXTENSION_INTERFACE,
+ "NeedInput",
+ g_variant_new_boolean (FALSE)),
+ NULL,
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
+}
+
+
+void
+e_dom_utils_bind_focus_on_elements (WebKitDOMDocument *document,
+ GDBusConnection *connection)
+{
+ const gchar *elements = "input, textarea, select, button, label";
+
+ e_dom_utils_bind_elements_recursively (
+ document,
+ elements,
+ "focus",
+ element_focus_cb,
+ connection);
+
+ e_dom_utils_bind_elements_recursively (
+ document,
+ elements,
+ "blur",
+ element_blur_cb,
+ connection);
+}
+
+void
+e_dom_utils_e_mail_display_bind_dom (WebKitDOMDocument *document,
+ GDBusConnection *connection)
+{
+ e_dom_utils_bind_dom (
+ document,
+ "#__evo-collapse-headers-img",
+ "click",
+ toggle_headers_visibility,
+ document);
+
+ e_dom_utils_bind_dom (
+ document,
+ "*[id^=__evo-moreaddr-]",
+ "click",
+ toggle_address_visibility,
+ connection);
+}
+
+void
+e_dom_utils_eab_contact_formatter_bind_dom (WebKitDOMDocument *document)
+{
+ e_dom_utils_bind_dom (
+ document,
+ "._evo_collapse_button",
+ "click",
+ collapse_contacts_list,
+ document);
+}
+
+/* ! This function can be called only from WK2 web-extension ! */
+WebKitDOMElement *
+e_dom_utils_find_element_by_selector (WebKitDOMDocument *document,
+ const gchar *selector)
+{
+ WebKitDOMHTMLCollection *frames = NULL;
+ WebKitDOMElement *element;
+ gulong ii, length;
+
+ /* Try to look up the element in this DOM document */
+ element = webkit_dom_document_query_selector (document, selector, NULL);
+ if (element != NULL)
+ return element;
+
+ /* If the element is not here then recursively scan all frames */
+ frames = webkit_dom_document_get_elements_by_tag_name_as_html_collection (document, "iframe");
+ length = webkit_dom_html_collection_get_length (frames);
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMHTMLIFrameElement *iframe;
+ WebKitDOMDocument *content_document;
+
+ iframe = WEBKIT_DOM_HTML_IFRAME_ELEMENT (
+ webkit_dom_html_collection_item (frames, ii));
+
+ content_document = webkit_dom_html_iframe_element_get_content_document (iframe);
+ if (!content_document)
+ continue;
+
+ element = e_dom_utils_find_element_by_id (content_document, selector);
+
+ g_object_unref (iframe);
+ if (element != NULL)
+ break;
+ }
+
+ g_clear_object (&frames);
+ return element;
+}
+
+/* ! This function can be called only from WK2 web-extension ! */
+WebKitDOMElement *
+e_dom_utils_find_element_by_id (WebKitDOMDocument *document,
+ const gchar *id)
+{
+ WebKitDOMHTMLCollection *frames = NULL;
+ WebKitDOMElement *element;
+ gulong ii, length;
+
+ /* Try to look up the element in this DOM document */
+ element = webkit_dom_document_get_element_by_id (document, id);
+ if (element != NULL)
+ return element;
+
+ /* If the element is not here then recursively scan all frames */
+ frames = webkit_dom_document_get_elements_by_tag_name_as_html_collection (document, "iframe");
+ length = webkit_dom_html_collection_get_length (frames);
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMHTMLIFrameElement *iframe;
+ WebKitDOMDocument *content_document;
+
+ iframe = WEBKIT_DOM_HTML_IFRAME_ELEMENT (
+ webkit_dom_html_collection_item (frames, ii));
+
+ content_document = webkit_dom_html_iframe_element_get_content_document (iframe);
+ if (!content_document)
+ continue;
+
+ element = e_dom_utils_find_element_by_id (content_document, id);
+
+ g_object_unref (iframe);
+ if (element != NULL)
+ break;
+ }
+
+ g_clear_object (&frames);
+ return element;
+}
+
+gboolean
+e_dom_utils_element_exists (WebKitDOMDocument *document,
+ const gchar *element_id)
+{
+ WebKitDOMElement *element;
+
+ element = e_dom_utils_find_element_by_id (document, element_id);
+
+ return element != NULL;
+}
+
+gchar *
+e_dom_utils_get_active_element_name (WebKitDOMDocument *document)
+{
+ WebKitDOMElement *element;
+
+ element = webkit_dom_document_get_active_element (document);
+
+ if (!element)
+ return NULL;
+
+ while (WEBKIT_DOM_IS_HTML_IFRAME_ELEMENT (element)) {
+ WebKitDOMDocument *content_document;
+
+ content_document =
+ webkit_dom_html_iframe_element_get_content_document (
+ WEBKIT_DOM_HTML_IFRAME_ELEMENT (element));
+
+ if (!content_document)
+ break;
+
+ element = webkit_dom_document_get_active_element (content_document);
+ }
+
+ return webkit_dom_node_get_local_name (WEBKIT_DOM_NODE (element));
+}
+
+void
+e_dom_utils_e_mail_part_headers_bind_dom_element (WebKitDOMDocument *document,
+ const gchar *element_id)
+{
+ WebKitDOMDocument *element_document;
+ WebKitDOMElement *element;
+ WebKitDOMElement *photo;
+ gchar *addr;
+
+ element = e_dom_utils_find_element_by_id (document, element_id);
+ if (!element)
+ return;
+
+ element_document = webkit_dom_node_get_owner_document (
+ WEBKIT_DOM_NODE (element));
+ photo = webkit_dom_document_get_element_by_id (
+ element_document, "__evo-contact-photo");
+
+ /* Contact photos disabled, the <img> tag is not there. */
+ if (!photo)
+ return;
+
+ addr = webkit_dom_element_get_attribute (photo, "data-mailaddr");
+ if (addr) {
+ gchar *uri;
+
+ uri = g_strdup_printf ("mail://contact-photo?mailaddr=%s", addr);
+
+ webkit_dom_html_image_element_set_src (
+ WEBKIT_DOM_HTML_IMAGE_ELEMENT (photo), uri);
+
+ g_free (uri);
+ }
+
+ g_free (addr);
+}
+
+void
+e_dom_utils_element_set_inner_html (WebKitDOMDocument *document,
+ const gchar *element_id,
+ const gchar *inner_html)
+{
+ WebKitDOMElement *element;
+
+ element = e_dom_utils_find_element_by_id (document, element_id);
+
+ if (!element)
+ return;
+
+ webkit_dom_element_set_inner_html (element, inner_html, NULL);
+}
+
+void
+e_dom_utils_remove_element (WebKitDOMDocument *document,
+ const gchar *element_id)
+{
+ WebKitDOMElement *element;
+
+ element = e_dom_utils_find_element_by_id (document, element_id);
+
+ if (!element)
+ return;
+
+ webkit_dom_node_remove_child (
+ webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element)),
+ WEBKIT_DOM_NODE (element),
+ NULL);
+}
+
+void
+e_dom_utils_element_remove_child_nodes (WebKitDOMDocument *document,
+ const gchar *element_id)
+{
+ WebKitDOMNode *node;
+ WebKitDOMElement *element;
+
+ element = e_dom_utils_find_element_by_id (document, element_id);
+ if (!element)
+ return;
+
+ node = WEBKIT_DOM_NODE (element);
+
+ if (!node)
+ return;
+
+ while (webkit_dom_node_has_child_nodes (node)) {
+ webkit_dom_node_remove_child (
+ node,
+ webkit_dom_node_get_last_child (node),
+ NULL);
+ }
+}
+
+void
+e_dom_utils_hide_element (WebKitDOMDocument *document,
+ const gchar *element_id,
+ gboolean hide)
+{
+ WebKitDOMElement *element;
+
+ element = e_dom_utils_find_element_by_id (document, element_id);
+
+ if (!element)
+ return;
+
+ webkit_dom_html_element_set_hidden (
+ WEBKIT_DOM_HTML_ELEMENT (element), hide);
+}
+
+gboolean
+e_dom_utils_element_is_hidden (WebKitDOMDocument *document,
+ const gchar *element_id)
+{
+ WebKitDOMElement *element;
+
+ element = e_dom_utils_find_element_by_id (document, element_id);
+
+ if (!element)
+ return FALSE;
+
+ return webkit_dom_html_element_get_hidden (WEBKIT_DOM_HTML_ELEMENT (element));
+}
+
+static void
+get_total_offsets (WebKitDOMElement *element,
+ glong *left,
+ glong *top)
+{
+ WebKitDOMElement *offset_parent;
+
+ if (left)
+ *left = 0;
+
+ if (top)
+ *top = 0;
+
+ offset_parent = element;
+ do {
+ if (left) {
+ *left += webkit_dom_element_get_offset_left (offset_parent);
+ *left -= webkit_dom_element_get_scroll_left (offset_parent);
+ }
+ if (top) {
+ *top += webkit_dom_element_get_offset_top (offset_parent);
+ *top -= webkit_dom_element_get_scroll_top (offset_parent);
+ }
+ offset_parent = webkit_dom_element_get_offset_parent (offset_parent);
+ } while (offset_parent);
+}
+
+static WebKitDOMElement *
+find_element_from_point (WebKitDOMDocument *document,
+ gint32 x,
+ gint32 y,
+ WebKitDOMElement *element_on_point)
+{
+ WebKitDOMDocument *content_document;
+ WebKitDOMElement *element;
+
+ if (!element_on_point)
+ element = webkit_dom_document_element_from_point (document, x, y);
+ else {
+ glong left, top;
+ get_total_offsets (element_on_point, &left, &top);
+
+ element = webkit_dom_document_element_from_point (
+ document, x - left, y - top);
+ }
+
+ if (!element)
+ return element_on_point;
+ else if (!WEBKIT_DOM_IS_HTML_IFRAME_ELEMENT (element))
+ element_on_point = element;
+
+ if (element_on_point && webkit_dom_node_is_equal_node (
+ WEBKIT_DOM_NODE (element),
+ WEBKIT_DOM_NODE (element_on_point))) {
+ return element_on_point;
+ }
+
+ if (!WEBKIT_DOM_IS_HTML_IFRAME_ELEMENT (element))
+ return element_on_point;
+
+ content_document =
+ webkit_dom_html_iframe_element_get_content_document (
+ WEBKIT_DOM_HTML_IFRAME_ELEMENT (element));
+
+ if (!content_document)
+ return element_on_point;
+
+ return find_element_from_point (content_document, x, y, element);
+}
+
+/* ! This function can be called only from WK2 web-extension ! */
+WebKitDOMElement *
+e_dom_utils_get_element_from_point (WebKitDOMDocument *document,
+ gint32 x,
+ gint32 y)
+{
+ return find_element_from_point (document, x, y, NULL);
+}
+
+/* ! This function can be called only from WK2 web-extension ! */
+WebKitDOMDocument *
+e_dom_utils_get_document_from_point (WebKitDOMDocument *document,
+ gint32 x,
+ gint32 y)
+{
+ WebKitDOMElement *element;
+
+ if (x == 0 && y == 0)
+ element = webkit_dom_document_get_active_element (document);
+ else
+ element = find_element_from_point (document, x, y, NULL);
+
+ if (WEBKIT_DOM_IS_HTML_IFRAME_ELEMENT (element))
+ return webkit_dom_html_iframe_element_get_content_document (
+ WEBKIT_DOM_HTML_IFRAME_ELEMENT (element));
+ else
+ return webkit_dom_node_get_owner_document (
+ WEBKIT_DOM_NODE (element));
+}
+
+/* VCard Inline Module DOM functions */
+
+static void
+display_mode_toggle_button_cb (WebKitDOMElement *button,
+ WebKitDOMEvent *event,
+ GDBusConnection *connection)
+{
+ GError *error = NULL;
+ gchar *element_id;
+
+ element_id = webkit_dom_element_get_id (button);
+
+ g_dbus_connection_emit_signal (
+ connection,
+ NULL,
+ E_WEB_EXTENSION_OBJECT_PATH,
+ E_WEB_EXTENSION_INTERFACE,
+ "VCardInlineDisplayModeToggled",
+ g_variant_new ("(s)", element_id ? element_id : ""),
+ &error);
+
+ if (error) {
+ g_warning ("Error emitting signal DisplayModeToggled: %s\n", error->message);
+ g_error_free (error);
+ }
+
+ g_free (element_id);
+}
+
+static void
+save_vcard_button_cb (WebKitDOMElement *button,
+ WebKitDOMEvent *event,
+ GDBusConnection *connection)
+{
+ GError *error = NULL;
+ gchar *button_value;
+
+ button_value = webkit_dom_html_button_element_get_value (
+ WEBKIT_DOM_HTML_BUTTON_ELEMENT (button));
+
+ g_dbus_connection_emit_signal (
+ connection,
+ NULL,
+ E_WEB_EXTENSION_OBJECT_PATH,
+ E_WEB_EXTENSION_INTERFACE,
+ "VCardInlineSaveButtonPressed",
+ g_variant_new ("(s)", button_value),
+ &error);
+
+ if (error) {
+ g_warning ("Error emitting signal SaveVCardButtonPressed: %s\n", error->message);
+ g_error_free (error);
+ }
+
+ g_free (button_value);
+}
+
+void
+e_dom_utils_module_vcard_inline_bind_dom (WebKitDOMDocument *document,
+ const gchar *element_id,
+ GDBusConnection *connection)
+{
+ WebKitDOMElement *element;
+ WebKitDOMDocument *element_document;
+ gchar *selector;
+
+ element = e_dom_utils_find_element_by_id (document, element_id);
+ if (!element)
+ return;
+
+ element_document = webkit_dom_node_get_owner_document (
+ WEBKIT_DOM_NODE (element));
+
+ selector = g_strconcat ("button[id='", element_id, "']", NULL);
+ e_dom_utils_bind_dom (
+ element_document,
+ selector,
+ "click",
+ display_mode_toggle_button_cb,
+ connection);
+ g_free (selector);
+
+ selector = g_strconcat ("button[value='", element_id, "']", NULL);
+ e_dom_utils_bind_dom (
+ element_document,
+ selector,
+ "click",
+ save_vcard_button_cb,
+ connection);
+ g_free (selector);
+
+ e_dom_utils_eab_contact_formatter_bind_dom (element_document);
+}
+
+void
+e_dom_utils_module_vcard_inline_update_button (WebKitDOMDocument *document,
+ const gchar *button_id,
+ const gchar *html_label,
+ const gchar *access_key)
+{
+ WebKitDOMElement *element;
+ gchar *selector;
+
+ selector = g_strconcat ("button[id='", button_id, "']", NULL);
+ element = e_dom_utils_find_element_by_selector (document, selector);
+ g_free (selector);
+
+ if (!element)
+ return;
+
+ webkit_dom_element_set_inner_html (element, html_label, NULL);
+
+ if (access_key) {
+ webkit_dom_html_element_set_access_key (
+ WEBKIT_DOM_HTML_ELEMENT (element), access_key);
+ }
+}
+
+void
+e_dom_utils_module_vcard_inline_set_iframe_src (WebKitDOMDocument *document,
+ const gchar *button_id,
+ const gchar *src)
+{
+ WebKitDOMElement *element, *parent, *iframe;
+ gchar *selector;
+
+ selector = g_strconcat ("button[id='", button_id, "']", NULL);
+ element = e_dom_utils_find_element_by_selector (document, selector);
+ g_free (selector);
+
+ parent = webkit_dom_node_get_parent_element (WEBKIT_DOM_NODE (element));
+ if (!parent)
+ return;
+
+ iframe = webkit_dom_element_query_selector (parent, "iframe", NULL);
+ if (!iframe)
+ return;
+
+ webkit_dom_html_iframe_element_set_src (
+ WEBKIT_DOM_HTML_IFRAME_ELEMENT (iframe), src);
+}
+
+/**
+ * e_html_editor_dom_node_find_parent_element:
+ * @node: Start node
+ * @tagname: Tag name of element to search
+ *
+ * Recursively searches for first occurance of element with given @tagname
+ * that is parent of given @node.
+ *
+ * Returns: A #WebKitDOMElement with @tagname representing parent of @node or
+ * @NULL when @node has no parent with given @tagname. When @node matches @tagname,
+ * then the @node is returned.
+ */
+WebKitDOMElement *
+dom_node_find_parent_element (WebKitDOMNode *node,
+ const gchar *tagname)
+{
+ WebKitDOMNode *tmp_node = node;
+ gint taglen = strlen (tagname);
+
+ while (tmp_node) {
+ if (WEBKIT_DOM_IS_ELEMENT (tmp_node)) {
+ gchar *node_tagname;
+
+ node_tagname = webkit_dom_element_get_tag_name (
+ WEBKIT_DOM_ELEMENT (tmp_node));
+
+ if (node_tagname &&
+ (strlen (node_tagname) == taglen) &&
+ (g_ascii_strncasecmp (node_tagname, tagname, taglen) == 0)) {
+ g_free (node_tagname);
+ return WEBKIT_DOM_ELEMENT (tmp_node);
+ }
+
+ g_free (node_tagname);
+ }
+
+ tmp_node = webkit_dom_node_get_parent_node (tmp_node);
+ }
+
+ return NULL;
+}
+
+/**
+ * e_html_editor_dom_node_find_child_element:
+ * @node: Start node
+ * @tagname: Tag name of element to search.
+ *
+ * Recursively searches for first occurrence of element with given @tagname that
+ * is a child of @node.
+ *
+ * Returns: A #WebKitDOMElement with @tagname representing a child of @node or
+ * @NULL when @node has no child with given @tagname. When @node matches @tagname,
+ * then the @node is returned.
+ */
+WebKitDOMElement *
+dom_node_find_child_element (WebKitDOMNode *node,
+ const gchar *tagname)
+{
+ WebKitDOMNode *start_node = node;
+ gint taglen = strlen (tagname);
+
+ do {
+ if (WEBKIT_DOM_IS_ELEMENT (node)) {
+ gchar *node_tagname;
+
+ node_tagname = webkit_dom_element_get_tag_name (
+ WEBKIT_DOM_ELEMENT (node));
+
+ if (node_tagname &&
+ (strlen (node_tagname) == taglen) &&
+ (g_ascii_strncasecmp (node_tagname, tagname, taglen) == 0)) {
+ g_free (node_tagname);
+ return WEBKIT_DOM_ELEMENT (node);
+ }
+
+ g_free (node_tagname);
+ }
+
+ if (webkit_dom_node_has_child_nodes (node)) {
+ node = webkit_dom_node_get_first_child (node);
+ } else if (webkit_dom_node_get_next_sibling (node)) {
+ node = webkit_dom_node_get_next_sibling (node);
+ } else {
+ node = webkit_dom_node_get_parent_node (node);
+ }
+ } while (!webkit_dom_node_is_same_node (node, start_node));
+
+ return NULL;
+}
+
+gboolean
+element_has_id (WebKitDOMElement *element,
+ const gchar* id)
+{
+ gchar *element_id;
+
+ if (!element)
+ return FALSE;
+
+ if (!WEBKIT_DOM_IS_ELEMENT (element))
+ return FALSE;
+
+ element_id = webkit_dom_element_get_id (element);
+
+ if (element_id && g_ascii_strcasecmp (element_id, id) == 0) {
+ g_free (element_id);
+ return TRUE;
+ }
+ g_free (element_id);
+
+ return FALSE;
+}
+
+gboolean
+element_has_tag (WebKitDOMElement *element,
+ const gchar* tag)
+{
+ gchar *element_tag;
+
+ if (!WEBKIT_DOM_IS_ELEMENT (element))
+ return FALSE;
+
+ element_tag = webkit_dom_node_get_local_name (WEBKIT_DOM_NODE (element));
+
+ if (g_ascii_strcasecmp (element_tag, tag) != 0) {
+ g_free (element_tag);
+ return FALSE;
+ }
+ g_free (element_tag);
+
+ return TRUE;
+}
+
+gboolean
+element_has_class (WebKitDOMElement *element,
+ const gchar* class)
+{
+ gchar *element_class;
+
+ if (!element)
+ return FALSE;
+
+ if (!WEBKIT_DOM_IS_ELEMENT (element))
+ return FALSE;
+
+ element_class = webkit_dom_element_get_class_name (element);
+
+ if (element_class && g_strstr_len (element_class, -1, class)) {
+ g_free (element_class);
+ return TRUE;
+ }
+ g_free (element_class);
+
+ return FALSE;
+}
+
+void
+element_add_class (WebKitDOMElement *element,
+ const gchar* class)
+{
+ gchar *element_class;
+ gchar *new_class;
+
+ if (!WEBKIT_DOM_IS_ELEMENT (element))
+ return;
+
+ if (element_has_class (element, class))
+ return;
+
+ element_class = webkit_dom_element_get_class_name (element);
+
+ if (!element_class)
+ new_class = g_strdup (class);
+ else
+ new_class = g_strconcat (element_class, " ", class, NULL);
+
+ webkit_dom_element_set_class_name (element, new_class);
+
+ g_free (element_class);
+ g_free (new_class);
+}
+
+void
+element_remove_class (WebKitDOMElement *element,
+ const gchar* class)
+{
+ gchar *element_class, *final_class;
+ GRegex *regex;
+ gchar *pattern = NULL;
+
+ if (!WEBKIT_DOM_IS_ELEMENT (element))
+ return;
+
+ if (!element_has_class (element, class))
+ return;
+
+ element_class = webkit_dom_element_get_class_name (element);
+
+ pattern = g_strconcat ("[\\s]*", class, "[\\s]*", NULL);
+ regex = g_regex_new (pattern, 0, 0, NULL);
+ final_class = g_regex_replace (regex, element_class, -1, 0, " ", 0, NULL);
+
+ if (g_strcmp0 (final_class, " ") != 0)
+ webkit_dom_element_set_class_name (element, final_class);
+ else
+ webkit_dom_element_remove_attribute (element, "class");
+
+ g_free (element_class);
+ g_free (final_class);
+ g_free (pattern);
+ g_regex_unref (regex);
+}
+
+void
+element_rename_attribute (WebKitDOMElement *element,
+ const gchar *from,
+ const gchar *to)
+{
+ gchar *value;
+
+ if (!webkit_dom_element_has_attribute (element, from))
+ return;
+
+ value = webkit_dom_element_get_attribute (element, from);
+ webkit_dom_element_set_attribute (element, to, (value && *value) ? value : "", NULL);
+ webkit_dom_element_remove_attribute (element, from);
+ g_free (value);
+}
+
+void
+remove_node (WebKitDOMNode *node)
+{
+ WebKitDOMNode *parent = webkit_dom_node_get_parent_node (node);
+
+ /* Check if the parent exists, if so it means that the node is still
+ * in the DOM or at least the parent is. If it doesn't exists it is not
+ * in the DOM and we can free it. */
+ if (parent)
+ webkit_dom_node_remove_child (parent, node, NULL);
+ else
+ g_object_unref (node);
+}
+
+void
+remove_node_if_empty (WebKitDOMNode *node)
+{
+ WebKitDOMNode *child;
+
+ if (!WEBKIT_DOM_IS_NODE (node))
+ return;
+
+ if ((child = webkit_dom_node_get_first_child (node))) {
+ WebKitDOMNode *prev_sibling, *next_sibling;
+
+ prev_sibling = webkit_dom_node_get_previous_sibling (child);
+ next_sibling = webkit_dom_node_get_next_sibling (child);
+ /* Empty or BR as sibling, but no sibling after it. */
+ if (!webkit_dom_node_get_first_child (child) &&
+ !WEBKIT_DOM_IS_TEXT (child) &&
+ (!prev_sibling ||
+ (WEBKIT_DOM_IS_HTML_BR_ELEMENT (prev_sibling) &&
+ !webkit_dom_node_get_previous_sibling (prev_sibling))) &&
+ (!next_sibling ||
+ (WEBKIT_DOM_IS_HTML_BR_ELEMENT (next_sibling) &&
+ !webkit_dom_node_get_next_sibling (next_sibling)))) {
+
+ remove_node (node);
+ } else {
+ gchar *text_content;
+
+ text_content = webkit_dom_node_get_text_content (node);
+ if (!text_content)
+ remove_node (node);
+
+ if (text_content && !*text_content)
+ remove_node (node);
+
+ g_free (text_content);
+ }
+ } else
+ remove_node (node);
+}
+
+WebKitDOMNode *
+split_list_into_two (WebKitDOMNode *item,
+ gint level)
+{
+ gint current_level = 1;
+ WebKitDOMDocument *document;
+ WebKitDOMDocumentFragment *fragment;
+ WebKitDOMNode *parent, *prev_parent = NULL, *tmp;
+
+ document = webkit_dom_node_get_owner_document (item);
+ fragment = webkit_dom_document_create_document_fragment (document);
+
+ tmp = item;
+ parent = webkit_dom_node_get_parent_node (item);
+ while (!WEBKIT_DOM_IS_HTML_BODY_ELEMENT (parent)) {
+ WebKitDOMNode *clone, *first_child, *insert_before = NULL, *sibling;
+
+ first_child = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (fragment));
+ clone = webkit_dom_node_clone_node_with_error (parent, FALSE, NULL);
+ webkit_dom_node_insert_before (
+ WEBKIT_DOM_NODE (fragment), clone, first_child, NULL);
+
+ if (first_child)
+ insert_before = webkit_dom_node_get_first_child (first_child);
+
+ while (first_child && (sibling = webkit_dom_node_get_next_sibling (first_child)))
+ webkit_dom_node_insert_before (first_child, sibling, insert_before, NULL);
+
+ while (tmp && (sibling = webkit_dom_node_get_next_sibling (tmp)))
+ webkit_dom_node_append_child (clone, sibling, NULL);
+
+ if (tmp)
+ webkit_dom_node_insert_before (
+ clone, tmp, webkit_dom_node_get_first_child (clone), NULL);
+
+ prev_parent = parent;
+ tmp = webkit_dom_node_get_next_sibling (parent);
+ parent = webkit_dom_node_get_parent_node (parent);
+ if (WEBKIT_DOM_IS_HTML_BODY_ELEMENT (parent)) {
+ first_child = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (fragment));
+ insert_before = webkit_dom_node_get_first_child (first_child);
+ while (first_child && (sibling = webkit_dom_node_get_next_sibling (first_child))) {
+ webkit_dom_node_insert_before (
+ first_child, sibling, insert_before, NULL);
+ }
+ }
+
+ if (current_level >= level && level >= 0)
+ break;
+
+ current_level++;
+ }
+
+ tmp = webkit_dom_node_insert_before (
+ parent,
+ webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (fragment)),
+ prev_parent ? webkit_dom_node_get_next_sibling (prev_parent) : NULL,
+ NULL);
+ remove_node_if_empty (prev_parent);
+
+ return tmp;
+}
+
+WebKitDOMElement *
+dom_create_selection_marker (WebKitDOMDocument *document,
+ gboolean selection_start_marker)
+{
+ WebKitDOMElement *element;
+
+ element = webkit_dom_document_create_element (
+ document, "SPAN", NULL);
+ webkit_dom_element_set_id (
+ element,
+ selection_start_marker ?
+ "-x-evo-selection-start-marker" :
+ "-x-evo-selection-end-marker");
+
+ return element;
+}
+
+void
+dom_remove_selection_markers (WebKitDOMDocument *document)
+{
+ WebKitDOMElement *marker;
+
+ marker = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-start-marker");
+ if (marker)
+ remove_node (WEBKIT_DOM_NODE (marker));
+ marker = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-end-marker");
+ if (marker)
+ remove_node (WEBKIT_DOM_NODE (marker));
+}
+
+void
+dom_add_selection_markers_into_element_start (WebKitDOMDocument *document,
+ WebKitDOMElement *element,
+ WebKitDOMElement **selection_start_marker,
+ WebKitDOMElement **selection_end_marker)
+{
+ WebKitDOMElement *marker;
+
+ dom_remove_selection_markers (document);
+ marker = dom_create_selection_marker (document, FALSE);
+ webkit_dom_node_insert_before (
+ WEBKIT_DOM_NODE (element),
+ WEBKIT_DOM_NODE (marker),
+ webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (element)),
+ NULL);
+ if (selection_end_marker)
+ *selection_end_marker = marker;
+
+ marker = dom_create_selection_marker (document, TRUE);
+ webkit_dom_node_insert_before (
+ WEBKIT_DOM_NODE (element),
+ WEBKIT_DOM_NODE (marker),
+ webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (element)),
+ NULL);
+ if (selection_start_marker)
+ *selection_start_marker = marker;
+}
+
+void
+dom_add_selection_markers_into_element_end (WebKitDOMDocument *document,
+ WebKitDOMElement *element,
+ WebKitDOMElement **selection_start_marker,
+ WebKitDOMElement **selection_end_marker)
+{
+ WebKitDOMElement *marker;
+
+ dom_remove_selection_markers (document);
+ marker = dom_create_selection_marker (document, TRUE);
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (element), WEBKIT_DOM_NODE (marker), NULL);
+ if (selection_start_marker)
+ *selection_start_marker = marker;
+
+ marker = dom_create_selection_marker (document, FALSE);
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (element), WEBKIT_DOM_NODE (marker), NULL);
+ if (selection_end_marker)
+ *selection_end_marker = marker;
+}
+
+gboolean
+node_is_list_or_item (WebKitDOMNode *node)
+{
+ return node && (
+ WEBKIT_DOM_IS_HTML_O_LIST_ELEMENT (node) ||
+ WEBKIT_DOM_IS_HTML_U_LIST_ELEMENT (node) ||
+ WEBKIT_DOM_IS_HTML_LI_ELEMENT (node));
+}
+
+gboolean
+node_is_list (WebKitDOMNode *node)
+{
+ return node && (
+ WEBKIT_DOM_IS_HTML_O_LIST_ELEMENT (node) ||
+ WEBKIT_DOM_IS_HTML_U_LIST_ELEMENT (node));
+}
+
+/**
+ * e_html_editor_selection_get_list_format_from_node:
+ * @node: an #WebKitDOMNode
+ *
+ * Returns block format of given list.
+ *
+ * Returns: #EContentEditorBlockFormat
+ */
+EContentEditorBlockFormat
+dom_get_list_format_from_node (WebKitDOMNode *node)
+{
+ EContentEditorBlockFormat format =
+ E_CONTENT_EDITOR_BLOCK_FORMAT_UNORDERED_LIST;
+
+ if (WEBKIT_DOM_IS_HTML_LI_ELEMENT (node))
+ return E_CONTENT_EDITOR_BLOCK_FORMAT_NONE;
+
+ if (WEBKIT_DOM_IS_HTML_U_LIST_ELEMENT (node))
+ return format;
+
+ if (WEBKIT_DOM_IS_HTML_O_LIST_ELEMENT (node)) {
+ gchar *type_value = webkit_dom_element_get_attribute (
+ WEBKIT_DOM_ELEMENT (node), "type");
+
+ if (!type_value)
+ return E_CONTENT_EDITOR_BLOCK_FORMAT_ORDERED_LIST;
+
+ if (!*type_value)
+ format = E_CONTENT_EDITOR_BLOCK_FORMAT_ORDERED_LIST;
+ else if (g_ascii_strcasecmp (type_value, "A") == 0)
+ format = E_CONTENT_EDITOR_BLOCK_FORMAT_ORDERED_LIST_ALPHA;
+ else if (g_ascii_strcasecmp (type_value, "I") == 0)
+ format = E_CONTENT_EDITOR_BLOCK_FORMAT_ORDERED_LIST_ROMAN;
+ g_free (type_value);
+
+ return format;
+ }
+
+ return E_CONTENT_EDITOR_BLOCK_FORMAT_NONE;
+}
+
+void
+merge_list_into_list (WebKitDOMNode *from,
+ WebKitDOMNode *to,
+ gboolean insert_before)
+{
+ WebKitDOMNode *item, *insert_before_node;
+
+ if (!(to && from))
+ return;
+
+ insert_before_node = webkit_dom_node_get_first_child (to);
+ while ((item = webkit_dom_node_get_first_child (from)) != NULL) {
+ if (insert_before)
+ webkit_dom_node_insert_before (
+ to, item, insert_before_node, NULL);
+ else
+ webkit_dom_node_append_child (to, item, NULL);
+ }
+
+ if (!webkit_dom_node_has_child_nodes (from))
+ remove_node (from);
+
+}
+
+void
+merge_lists_if_possible (WebKitDOMNode *list)
+{
+ EContentEditorBlockFormat format, prev, next;
+ gint ii, length;
+ WebKitDOMNode *prev_sibling, *next_sibling;
+ WebKitDOMNodeList *lists = NULL;
+
+ prev_sibling = webkit_dom_node_get_previous_sibling (WEBKIT_DOM_NODE (list));
+ next_sibling = webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (list));
+
+ format = dom_get_list_format_from_node (list),
+ prev = dom_get_list_format_from_node (prev_sibling);
+ next = dom_get_list_format_from_node (next_sibling);
+
+ if (format != E_CONTENT_EDITOR_BLOCK_FORMAT_NONE) {
+ if (format == prev && prev != E_CONTENT_EDITOR_BLOCK_FORMAT_NONE)
+ merge_list_into_list (prev_sibling, list, TRUE);
+
+ if (format == next && next != E_CONTENT_EDITOR_BLOCK_FORMAT_NONE)
+ merge_list_into_list (next_sibling, list, FALSE);
+ }
+
+ lists = webkit_dom_element_query_selector_all (
+ WEBKIT_DOM_ELEMENT (list), "ol + ol, ul + ul", NULL);
+ length = webkit_dom_node_list_get_length (lists);
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMNode *node;
+
+ node = webkit_dom_node_list_item (lists, ii);
+ merge_lists_if_possible (node);
+ g_object_unref (node);
+ }
+ g_clear_object (&lists);
+}
+
+WebKitDOMElement *
+get_parent_block_element (WebKitDOMNode *node)
+{
+ WebKitDOMElement *parent = webkit_dom_node_get_parent_element (node);
+
+ if (WEBKIT_DOM_IS_HTML_BODY_ELEMENT (parent))
+ return WEBKIT_DOM_ELEMENT (node);
+
+ while (parent &&
+ !WEBKIT_DOM_IS_HTML_PARAGRAPH_ELEMENT (parent) &&
+ !WEBKIT_DOM_IS_HTML_DIV_ELEMENT (parent) &&
+ !WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (parent) &&
+ !WEBKIT_DOM_IS_HTML_U_LIST_ELEMENT (parent) &&
+ !WEBKIT_DOM_IS_HTML_O_LIST_ELEMENT (parent) &&
+ !WEBKIT_DOM_IS_HTML_PRE_ELEMENT (parent) &&
+ !WEBKIT_DOM_IS_HTML_HEADING_ELEMENT (parent) &&
+ !WEBKIT_DOM_IS_HTML_TABLE_CELL_ELEMENT (parent) &&
+ !element_has_tag (parent, "address")) {
+ parent = webkit_dom_node_get_parent_element (
+ WEBKIT_DOM_NODE (parent));
+ }
+
+ return parent;
+}
+
+gchar *
+dom_get_node_inner_html (WebKitDOMNode *node)
+{
+ gchar *inner_html;
+ WebKitDOMDocument *document;
+ WebKitDOMElement *div;
+
+ document = webkit_dom_node_get_owner_document (node);
+ div = webkit_dom_document_create_element (document, "div", NULL);
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (div),
+ webkit_dom_node_clone_node_with_error (node, TRUE, NULL),
+ NULL);
+
+ inner_html = webkit_dom_element_get_inner_html (div);
+ remove_node (WEBKIT_DOM_NODE (div));
+
+ return inner_html;
+}
+
+WebKitDOMDocument *
+e_dom_utils_find_document_with_uri (WebKitDOMDocument *root_document,
+ const gchar *find_document_uri)
+{
+ WebKitDOMDocument *res_document = NULL;
+ GSList *todo;
+
+ g_return_val_if_fail (WEBKIT_DOM_IS_DOCUMENT (root_document), NULL);
+ g_return_val_if_fail (find_document_uri != NULL, NULL);
+
+ todo = g_slist_append (NULL, root_document);
+
+ while (todo) {
+ WebKitDOMDocument *document;
+ WebKitDOMHTMLCollection *frames = NULL;
+ gchar *document_uri;
+ gint ii, length;
+
+ document = todo->data;
+ todo = g_slist_remove (todo, document);
+
+ document_uri = webkit_dom_document_get_document_uri (document);
+ if (g_strcmp0 (document_uri, find_document_uri) == 0) {
+ g_free (document_uri);
+ res_document = document;
+ break;
+ }
+
+ g_free (document_uri);
+
+ frames = webkit_dom_document_get_elements_by_tag_name_as_html_collection (document, "iframe");
+ length = webkit_dom_html_collection_get_length (frames);
+
+ /* Add rules to every sub document */
+ for (ii = 0; ii < length; ii++) {
+ WebKitDOMDocument *content_document;
+ WebKitDOMNode *node;
+
+ node = webkit_dom_html_collection_item (frames, ii);
+ content_document =
+ webkit_dom_html_iframe_element_get_content_document (
+ WEBKIT_DOM_HTML_IFRAME_ELEMENT (node));
+
+ if (!content_document)
+ continue;
+
+ todo = g_slist_prepend (todo, content_document);
+
+ g_object_unref (node);
+ }
+
+ g_clear_object (&frames);
+ }
+
+ g_slist_free (todo);
+
+ return res_document;
+}
+
+void
+dom_element_swap_attributes (WebKitDOMElement *element,
+ const gchar *from,
+ const gchar *to)
+{
+ gchar *value_from, *value_to;
+
+ if (!webkit_dom_element_has_attribute (element, from) ||
+ !webkit_dom_element_has_attribute (element, to))
+ return;
+
+ value_from = webkit_dom_element_get_attribute (element, from);
+ value_to = webkit_dom_element_get_attribute (element, to);
+ webkit_dom_element_set_attribute (element, to, (value_from && *value_from) ? value_from : "", NULL);
+ webkit_dom_element_set_attribute (element, from, (value_to && *value_to) ? value_to : "", NULL);
+ g_free (value_from);
+ g_free (value_to);
+}
diff --git a/web-extensions/e-dom-utils.h b/web-extensions/e-dom-utils.h
new file mode 100644
index 0000000..3ec289d
--- /dev/null
+++ b/web-extensions/e-dom-utils.h
@@ -0,0 +1,169 @@
+/*
+ * e-dom-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/>
+ *
+ */
+
+#ifndef E_DOM_UTILS_H
+#define E_DOM_UTILS_H
+
+#define E_UTIL_INCLUDE_WITHOUT_WEBKIT
+#include <e-util/e-util.h>
+#undef E_UTIL_INCLUDE_WITHOUT_WEBKIT
+
+#include <webkitdom/webkitdom.h>
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+void e_dom_utils_replace_local_image_links
+ (WebKitDOMDocument *document);
+gboolean e_dom_utils_document_has_selection
+ (WebKitDOMDocument *document);
+gchar * e_dom_utils_get_document_content_html
+ (WebKitDOMDocument *document);
+gchar * e_dom_utils_get_selection_content_html
+ (WebKitDOMDocument *document);
+gchar * e_dom_utils_get_selection_content_text
+ (WebKitDOMDocument *document);
+void e_dom_utils_create_and_add_css_style_sheet
+ (WebKitDOMDocument *document,
+ const gchar *style_sheet_id);
+void e_dom_utils_add_css_rule_into_style_sheet
+ (WebKitDOMDocument *document,
+ const gchar *style_sheet_id,
+ const gchar *selector,
+ const gchar *style);
+void e_dom_utils_eab_contact_formatter_bind_dom
+ (WebKitDOMDocument *document);
+void e_dom_utils_bind_focus_on_elements
+ (WebKitDOMDocument *document,
+ GDBusConnection *connection);
+void e_dom_utils_e_mail_display_bind_dom
+ (WebKitDOMDocument *document,
+ GDBusConnection *connection);
+WebKitDOMElement *
+ e_dom_utils_find_element_by_selector
+ (WebKitDOMDocument *document,
+ const gchar *selector);
+WebKitDOMElement *
+ e_dom_utils_find_element_by_id (WebKitDOMDocument *document,
+ const gchar *element_id);
+gboolean e_dom_utils_element_exists
+ (WebKitDOMDocument *document,
+ const gchar *element_id);
+gchar * e_dom_utils_get_active_element_name
+ (WebKitDOMDocument *document);
+void e_dom_utils_e_mail_part_headers_bind_dom_element
+ (WebKitDOMDocument *document,
+ const gchar *element_id);
+void e_dom_utils_element_set_inner_html
+ (WebKitDOMDocument *document,
+ const gchar *element_id,
+ const gchar *inner_html);
+void e_dom_utils_remove_element (WebKitDOMDocument *document,
+ const gchar *element_id);
+void e_dom_utils_element_remove_child_nodes
+ (WebKitDOMDocument *document,
+ const gchar *element_id);
+void e_dom_utils_hide_element (WebKitDOMDocument *document,
+ const gchar *element_id,
+ gboolean hide);
+gboolean e_dom_utils_element_is_hidden (WebKitDOMDocument *document,
+ const gchar *element_id);
+WebKitDOMElement *
+ e_dom_utils_get_element_from_point
+ (WebKitDOMDocument *document,
+ gint32 x,
+ gint32 y);
+WebKitDOMDocument *
+ e_dom_utils_get_document_from_point
+ (WebKitDOMDocument *document,
+ gint32 x,
+ gint32 y);
+/* VCard Inline Module DOM functions */
+void e_dom_utils_module_vcard_inline_bind_dom
+ (WebKitDOMDocument *document,
+ const gchar *element_id,
+ GDBusConnection *connection);
+void e_dom_utils_module_vcard_inline_update_button
+ (WebKitDOMDocument *document,
+ const gchar *button_id,
+ const gchar *html_label,
+ const gchar *access_key);
+void e_dom_utils_module_vcard_inline_set_iframe_src
+ (WebKitDOMDocument *document,
+ const gchar *button_id,
+ const gchar *src);
+WebKitDOMElement *
+ dom_node_find_parent_element (WebKitDOMNode *node,
+ const gchar *tagname);
+WebKitDOMElement *
+ dom_node_find_child_element (WebKitDOMNode *node,
+ const gchar *tagname);
+gboolean element_has_id (WebKitDOMElement *element,
+ const gchar* id);
+gboolean element_has_tag (WebKitDOMElement *element,
+ const gchar* tag);
+gboolean element_has_class (WebKitDOMElement *element,
+ const gchar* class);
+void element_add_class (WebKitDOMElement *element,
+ const gchar* class);
+void element_remove_class (WebKitDOMElement *element,
+ const gchar* class);
+void element_rename_attribute (WebKitDOMElement *element,
+ const gchar *from,
+ const gchar *to);
+void remove_node (WebKitDOMNode *node);
+void remove_node_if_empty (WebKitDOMNode *node);
+WebKitDOMNode * split_list_into_two (WebKitDOMNode *item,
+ gint level);
+WebKitDOMElement *
+ dom_create_selection_marker (WebKitDOMDocument *document,
+ gboolean start);
+void dom_add_selection_markers_into_element_start
+ (WebKitDOMDocument *document,
+ WebKitDOMElement *element,
+ WebKitDOMElement **selection_start_marker,
+ WebKitDOMElement **selection_end_marker);
+void dom_add_selection_markers_into_element_end
+ (WebKitDOMDocument *document,
+ WebKitDOMElement *element,
+ WebKitDOMElement **selection_start_marker,
+ WebKitDOMElement **selection_end_marker);
+void dom_remove_selection_markers (WebKitDOMDocument *document);
+gboolean node_is_list (WebKitDOMNode *node);
+gboolean node_is_list_or_item (WebKitDOMNode *node);
+EContentEditorBlockFormat
+ dom_get_list_format_from_node (WebKitDOMNode *node);
+void merge_list_into_list (WebKitDOMNode *from,
+ WebKitDOMNode *to,
+ gboolean insert_before);
+void merge_lists_if_possible (WebKitDOMNode *list);
+WebKitDOMElement *
+ get_parent_block_element (WebKitDOMNode *node);
+gchar * dom_get_node_inner_html (WebKitDOMNode *node);
+WebKitDOMDocument *
+ e_dom_utils_find_document_with_uri
+ (WebKitDOMDocument *root_document,
+ const gchar *find_document_uri);
+void dom_element_swap_attributes (WebKitDOMElement *element,
+ const gchar *from,
+ const gchar *to);
+
+G_END_DECLS
+
+#endif /* E_DOM_UTILS_H */
diff --git a/web-extensions/e-web-extension-main.c b/web-extensions/e-web-extension-main.c
new file mode 100644
index 0000000..5276734
--- /dev/null
+++ b/web-extensions/e-web-extension-main.c
@@ -0,0 +1,61 @@
+/*
+ * e-web-extension-main.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/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <camel/camel.h>
+
+#include "e-web-extension.h"
+#include "e-web-extension-names.h"
+
+static void
+bus_acquired_cb (GDBusConnection *connection,
+ const gchar *name,
+ EWebExtension *extension)
+{
+ e_web_extension_dbus_register (extension, connection);
+}
+
+/* Forward declaration */
+G_MODULE_EXPORT void webkit_web_extension_initialize (WebKitWebExtension *wk_extension);
+
+G_MODULE_EXPORT void
+webkit_web_extension_initialize (WebKitWebExtension *wk_extension)
+{
+ EWebExtension *extension;
+
+ camel_debug_init ();
+
+ if (camel_debug ("wex"))
+ printf ("%s\n", G_STRFUNC);
+
+ extension = e_web_extension_get ();
+ e_web_extension_initialize (extension, wk_extension);
+
+ g_bus_own_name (
+ G_BUS_TYPE_SESSION,
+ E_WEB_EXTENSION_SERVICE_NAME,
+ G_BUS_NAME_OWNER_FLAGS_NONE,
+ (GBusAcquiredCallback) bus_acquired_cb,
+ NULL, /* GBusNameAcquiredCallback */
+ NULL, /* GBusNameLostCallback */
+ g_object_ref (extension),
+ (GDestroyNotify) g_object_unref);
+}
diff --git a/web-extensions/e-web-extension-names.h b/web-extensions/e-web-extension-names.h
new file mode 100644
index 0000000..eedf271
--- /dev/null
+++ b/web-extensions/e-web-extension-names.h
@@ -0,0 +1,26 @@
+/*
+ * e-web-extension-names.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/>
+ *
+ */
+
+#ifndef E_WEB_EXTENSION_NAMES_H
+#define E_WEB_EXTENSION_NAMES_H
+
+#define E_WEB_EXTENSION_SERVICE_NAME "org.gnome.Evolution.WebExtension"
+#define E_WEB_EXTENSION_OBJECT_PATH "/org/gnome/Evolution/WebExtension"
+#define E_WEB_EXTENSION_INTERFACE "org.gnome.Evolution.WebExtension"
+
+#endif /* E_WEB_EXTENSION_NAMES_H */
diff --git a/web-extensions/e-web-extension.c b/web-extensions/e-web-extension.c
new file mode 100644
index 0000000..0492077
--- /dev/null
+++ b/web-extensions/e-web-extension.c
@@ -0,0 +1,999 @@
+/*
+ * e-web-extension.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/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include <gio/gio.h>
+#include <glib/gstdio.h>
+#include <gtk/gtk.h>
+
+#include <camel/camel.h>
+#include <libedataserver/libedataserver.h>
+
+#include "e-web-extension.h"
+#include "e-dom-utils.h"
+#include "e-web-extension-names.h"
+
+#define WEBKIT_DOM_USE_UNSTABLE_API
+#include <webkitdom/WebKitDOMDOMWindowUnstable.h>
+
+#define WEB_EXTENSION_PAGE_ID_KEY "web-extension-page-id"
+
+#define E_WEB_EXTENSION_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_WEB_EXTENSION, EWebExtensionPrivate))
+
+struct _EWebExtensionPrivate {
+ WebKitWebExtension *wk_extension;
+
+ GDBusConnection *dbus_connection;
+ guint registration_id;
+
+ gboolean initialized;
+
+ gboolean need_input;
+};
+
+static const char introspection_xml[] =
+"<node>"
+" <interface name='" E_WEB_EXTENSION_INTERFACE "'>"
+" <method name='RegisterElementClicked'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='element_class' direction='in'/>"
+" </method>"
+" <signal name='ElementClicked'>"
+" <arg type='t' name='page_id' direction='out'/>"
+" <arg type='s' name='element_class' direction='out'/>"
+" <arg type='s' name='element_value' direction='out'/>"
+" <arg type='i' name='position_left' direction='out'/>"
+" <arg type='i' name='position_top' direction='out'/>"
+" <arg type='i' name='position_width' direction='out'/>"
+" <arg type='i' name='position_height' direction='out'/>"
+" </signal>"
+" <method name='SetElementHidden'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='element_id' direction='in'/>"
+" <arg type='b' name='hidden' direction='in'/>"
+" </method>"
+" <method name='SetElementStyleProperty'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='element_id' direction='in'/>"
+" <arg type='s' name='property_name' direction='in'/>"
+" <arg type='s' name='value' direction='in'/>"
+" <arg type='s' name='priority' direction='in'/>"
+" </method>"
+" <method name='SetElementAttribute'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='element_id' direction='in'/>"
+" <arg type='s' name='namespace_uri' direction='in'/>"
+" <arg type='s' name='qualified_name' direction='in'/>"
+" <arg type='s' name='value' direction='in'/>"
+" </method>"
+" <signal name='HeadersCollapsed'>"
+" <arg type='b' name='expanded' direction='out'/>"
+" </signal>"
+" <method name='DocumentHasSelection'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='b' name='has_selection' direction='out'/>"
+" </method>"
+" <method name='GetDocumentContentHTML'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='html_content' direction='out'/>"
+" </method>"
+" <method name='GetSelectionContentHTML'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='html_content' direction='out'/>"
+" </method>"
+" <method name='GetSelectionContentText'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='text_content' direction='out'/>"
+" </method>"
+" <method name='CreateAndAddCSSStyleSheet'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='style_sheet_id' direction='in'/>"
+" </method>"
+" <method name='AddCSSRuleIntoStyleSheet'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='style_sheet_id' direction='in'/>"
+" <arg type='s' name='selector' direction='in'/>"
+" <arg type='s' name='style' direction='in'/>"
+" </method>"
+" <method name='EABContactFormatterBindDOM'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" </method>"
+" <method name='EMailDisplayBindDOM'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" </method>"
+" <method name='ElementExists'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='element_id' direction='in'/>"
+" <arg type='b' name='element_exists' direction='out'/>"
+" <arg type='t' name='page_id' direction='out'/>"
+" </method>"
+" <method name='GetActiveElementName'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='element_name' direction='out'/>"
+" </method>"
+" <method name='EMailPartHeadersBindDOMElement'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='element_id' direction='in'/>"
+" </method>"
+" <signal name='VCardInlineDisplayModeToggled'>"
+" <arg type='s' name='button_id' direction='out'/>"
+" </signal>"
+" <signal name='VCardInlineSaveButtonPressed'>"
+" <arg type='s' name='button_value' direction='out'/>"
+" </signal>"
+" <method name='VCardInlineBindDOM'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='element_id' direction='in'/>"
+" </method>"
+" <method name='VCardInlineUpdateButton'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='button_id' direction='in'/>"
+" <arg type='s' name='html_label' direction='in'/>"
+" <arg type='s' name='access_key' direction='in'/>"
+" </method>"
+" <method name='VCardInlineSetIFrameSrc'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='button_id' direction='in'/>"
+" <arg type='s' name='src' direction='in'/>"
+" </method>"
+" <method name='GetDocumentURIFromPoint'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='i' name='x' direction='in'/>"
+" <arg type='i' name='y' direction='in'/>"
+" <arg type='s' name='document_uri' direction='out'/>"
+" </method>"
+" <method name='SetDocumentIFrameSrc'>"
+" <arg type='t' name='page_id' direction='in'/>"
+" <arg type='s' name='document_uri' direction='in'/>"
+" <arg type='s' name='new_iframe_src' direction='in'/>"
+" </method>"
+" <property type='b' name='NeedInput' access='readwrite'/>"
+" </interface>"
+"</node>";
+
+G_DEFINE_TYPE (EWebExtension, e_web_extension, G_TYPE_OBJECT)
+
+static WebKitWebPage *
+get_webkit_web_page_or_return_dbus_error (GDBusMethodInvocation *invocation,
+ WebKitWebExtension *web_extension,
+ guint64 page_id)
+{
+ WebKitWebPage *web_page = webkit_web_extension_get_page (web_extension, page_id);
+ if (!web_page) {
+ g_dbus_method_invocation_return_error (
+ invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
+ "Invalid page ID: %" G_GUINT64_FORMAT, page_id);
+ }
+ return web_page;
+}
+
+static void
+element_clicked_cb (WebKitDOMElement *element,
+ WebKitDOMEvent *event,
+ gpointer user_data)
+{
+ EWebExtension *extension = user_data;
+ WebKitDOMElement *offset_parent;
+ WebKitDOMDOMWindow *dom_window = NULL;
+ gchar *attr_class, *attr_value;
+ const guint64 *ppage_id;
+ gdouble with_parents_left, with_parents_top;
+ glong scroll_x = 0, scroll_y = 0;
+ GError *error = NULL;
+
+ g_return_if_fail (E_IS_WEB_EXTENSION (extension));
+ g_return_if_fail (G_IS_OBJECT (element));
+
+ ppage_id = g_object_get_data (G_OBJECT (element), WEB_EXTENSION_PAGE_ID_KEY);
+ g_return_if_fail (ppage_id != NULL);
+
+ with_parents_left = webkit_dom_element_get_offset_left (element);
+ with_parents_top = webkit_dom_element_get_offset_top (element);
+
+ offset_parent = element;
+ while (offset_parent = webkit_dom_element_get_offset_parent (offset_parent), offset_parent) {
+ with_parents_left += webkit_dom_element_get_offset_left (offset_parent);
+ with_parents_top += webkit_dom_element_get_offset_top (offset_parent);
+ }
+
+ dom_window = webkit_dom_document_get_default_view (webkit_dom_node_get_owner_document
(WEBKIT_DOM_NODE (element)));
+ if (WEBKIT_DOM_IS_DOM_WINDOW (dom_window)) {
+ g_object_get (G_OBJECT (dom_window),
+ "scroll-x", &scroll_x,
+ "scroll-y", &scroll_y,
+ NULL);
+ }
+ g_clear_object (&dom_window);
+
+ attr_class = webkit_dom_element_get_class_name (element);
+ attr_value = webkit_dom_element_get_attribute (element, "value");
+
+ g_dbus_connection_emit_signal (
+ extension->priv->dbus_connection,
+ NULL,
+ E_WEB_EXTENSION_OBJECT_PATH,
+ E_WEB_EXTENSION_INTERFACE,
+ "ElementClicked",
+ g_variant_new ("(tssiiii)", *ppage_id, attr_class ? attr_class : "", attr_value ? attr_value
: "",
+ (gint) (with_parents_left - scroll_x),
+ (gint) (with_parents_top - scroll_y),
+ (gint) webkit_dom_element_get_offset_width (element),
+ (gint) webkit_dom_element_get_offset_height (element)),
+ &error);
+
+ if (error) {
+ g_warning ("Error emitting signal ElementClicked: %s\n", error->message);
+ g_error_free (error);
+ }
+
+ g_free (attr_class);
+ g_free (attr_value);
+}
+
+static void
+web_extension_register_element_clicked_in_document (EWebExtension *extension,
+ guint64 page_id,
+ WebKitDOMDocument *document,
+ const gchar *element_class)
+{
+ WebKitDOMHTMLCollection *collection = NULL;
+ gulong ii, len;
+
+ g_return_if_fail (E_IS_WEB_EXTENSION (extension));
+ g_return_if_fail (WEBKIT_DOM_IS_DOCUMENT (document));
+ g_return_if_fail (element_class && *element_class);
+
+ collection = webkit_dom_document_get_elements_by_class_name_as_html_collection (document,
element_class);
+ if (collection) {
+ len = webkit_dom_html_collection_get_length (collection);
+ for (ii = 0; ii < len; ii++) {
+ WebKitDOMNode *node;
+
+ node = webkit_dom_html_collection_item (collection, ii);
+ if (WEBKIT_DOM_IS_EVENT_TARGET (node)) {
+ guint64 *ppage_id;
+
+ ppage_id = g_new0 (guint64, 1);
+ *ppage_id = page_id;
+
+ g_object_set_data_full (G_OBJECT (node), WEB_EXTENSION_PAGE_ID_KEY, ppage_id,
g_free);
+
+ /* Remove first, in case there was a listener already (it's when
+ the page is dynamically filled and not all the elements are
+ available in time of the first call. */
+ webkit_dom_event_target_remove_event_listener (
+ WEBKIT_DOM_EVENT_TARGET (node), "click",
+ G_CALLBACK (element_clicked_cb), FALSE);
+
+ webkit_dom_event_target_add_event_listener (
+ WEBKIT_DOM_EVENT_TARGET (node), "click",
+ G_CALLBACK (element_clicked_cb), FALSE, extension);
+ }
+ }
+ }
+ g_clear_object (&collection);
+
+ /* Traverse also iframe-s */
+ collection = webkit_dom_document_get_elements_by_tag_name_as_html_collection (document, "iframe");
+ if (collection) {
+ len = webkit_dom_html_collection_get_length (collection);
+ for (ii = 0; ii < len; ii++) {
+ WebKitDOMNode *node;
+
+ node = webkit_dom_html_collection_item (collection, ii);
+ if (WEBKIT_DOM_IS_HTML_IFRAME_ELEMENT (node)) {
+ WebKitDOMDocument *content;
+
+ content = webkit_dom_html_iframe_element_get_content_document
(WEBKIT_DOM_HTML_IFRAME_ELEMENT (node));
+ if (content)
+ web_extension_register_element_clicked_in_document (extension,
page_id, content, element_class);
+ }
+ }
+ }
+ g_clear_object (&collection);
+}
+
+static void
+handle_method_call (GDBusConnection *connection,
+ const char *sender,
+ const char *object_path,
+ const char *interface_name,
+ const char *method_name,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation,
+ gpointer user_data)
+{
+ guint64 page_id;
+ EWebExtension *extension = E_WEB_EXTENSION (user_data);
+ WebKitDOMDocument *document;
+ WebKitWebExtension *web_extension = extension->priv->wk_extension;
+ WebKitWebPage *web_page;
+
+ if (g_strcmp0 (interface_name, E_WEB_EXTENSION_INTERFACE) != 0)
+ return;
+
+ if (camel_debug ("wex"))
+ printf ("EWebExtension - %s - %s\n", G_STRFUNC, method_name);
+ if (g_strcmp0 (method_name, "RegisterElementClicked") == 0) {
+ const gchar *element_class = NULL;
+
+ g_variant_get (parameters, "(t&s)", &page_id, &element_class);
+
+ web_page = get_webkit_web_page_or_return_dbus_error (invocation, web_extension, page_id);
+ if (!web_page)
+ return;
+
+ if (!element_class || !*element_class) {
+ g_warn_if_fail (element_class && *element_class);
+ } else {
+ document = webkit_web_page_get_dom_document (web_page);
+ web_extension_register_element_clicked_in_document (extension, page_id, document,
element_class);
+ }
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "SetElementHidden") == 0) {
+ const gchar *element_id = NULL;
+ gboolean hidden = FALSE;
+
+ g_variant_get (parameters, "(t&sb)", &page_id, &element_id, &hidden);
+
+ web_page = get_webkit_web_page_or_return_dbus_error (invocation, web_extension, page_id);
+ if (!web_page)
+ return;
+
+ if (!element_id || !*element_id) {
+ g_warn_if_fail (element_id && *element_id);
+ } else {
+ document = webkit_web_page_get_dom_document (web_page);
+
+ /* A secret short-cut, to not have two functions for basically the same thing ("hide
attachment" and "hide element") */
+ if (!hidden && g_str_has_prefix (element_id, "attachment-wrapper-")) {
+ WebKitDOMElement *element;
+
+ element = e_dom_utils_find_element_by_id (document, element_id);
+
+ if (WEBKIT_DOM_IS_HTML_ELEMENT (element) &&
+ webkit_dom_element_get_child_element_count (element) == 0) {
+ gchar *inner_html_data;
+
+ inner_html_data = webkit_dom_element_get_attribute (element,
"inner-html-data");
+ if (inner_html_data && *inner_html_data) {
+ webkit_dom_element_set_inner_html (element, inner_html_data,
NULL);
+ webkit_dom_element_remove_attribute (element,
"inner-html-data");
+ }
+
+ g_free (inner_html_data);
+ }
+ }
+
+ e_dom_utils_hide_element (document, element_id, hidden);
+ }
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "SetElementStyleProperty") == 0) {
+ const gchar *element_id = NULL, *property_name = NULL, *value = NULL, *priority = NULL;
+
+ g_variant_get (parameters, "(t&s&s&s&s)", &page_id, &element_id, &property_name, &value,
&priority);
+
+ web_page = get_webkit_web_page_or_return_dbus_error (invocation, web_extension, page_id);
+ if (!web_page)
+ return;
+
+ if (!element_id || !*element_id || !property_name || !*property_name) {
+ g_warn_if_fail (element_id && *element_id);
+ g_warn_if_fail (property_name && *property_name);
+ } else {
+ WebKitDOMElement *element;
+ gboolean use_child = FALSE;
+ gchar *tmp = NULL;
+
+ /* element_id can be also of the form: "id::child", where the change will
+ be done on the first child of it */
+ use_child = g_str_has_suffix (element_id, "::child");
+ if (use_child) {
+ tmp = g_strdup (element_id);
+ tmp[strlen (tmp) - 7] = '\0';
+
+ element_id = tmp;
+ }
+
+ document = webkit_web_page_get_dom_document (web_page);
+ element = e_dom_utils_find_element_by_id (document, element_id);
+
+ if (use_child && element)
+ element = webkit_dom_element_get_first_element_child (element);
+
+ if (element) {
+ WebKitDOMCSSStyleDeclaration *css;
+
+ css = webkit_dom_element_get_style (element);
+
+ if (value && *value)
+ webkit_dom_css_style_declaration_set_property (css, property_name,
value, priority, NULL);
+ else
+ g_free (webkit_dom_css_style_declaration_remove_property (css,
property_name, NULL));
+
+ g_clear_object (&css);
+ }
+
+ g_free (tmp);
+ }
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "SetElementAttribute") == 0) {
+ const gchar *element_id = NULL, *namespace_uri = NULL, *qualified_name = NULL, *value = NULL;
+
+ g_variant_get (parameters, "(t&s&s&s&s)", &page_id, &element_id, &namespace_uri,
&qualified_name, &value);
+
+ web_page = get_webkit_web_page_or_return_dbus_error (invocation, web_extension, page_id);
+ if (!web_page)
+ return;
+
+ if (!element_id || !*element_id || !qualified_name || !*qualified_name) {
+ g_warn_if_fail (element_id && *element_id);
+ g_warn_if_fail (qualified_name && *qualified_name);
+ } else {
+ WebKitDOMElement *element;
+ gboolean use_child = FALSE;
+ gchar *tmp = NULL;
+
+ /* element_id can be also of the form: "id::child", where the change will
+ be done on the first child of it */
+ use_child = g_str_has_suffix (element_id, "::child");
+ if (use_child) {
+ tmp = g_strdup (element_id);
+ tmp[strlen (tmp) - 7] = '\0';
+
+ element_id = tmp;
+ }
+
+ if (namespace_uri && !*namespace_uri)
+ namespace_uri = NULL;
+
+ document = webkit_web_page_get_dom_document (web_page);
+ element = e_dom_utils_find_element_by_id (document, element_id);
+
+ if (use_child && element)
+ element = webkit_dom_element_get_first_element_child (element);
+
+ if (element) {
+ if (value && *value)
+ webkit_dom_element_set_attribute_ns (element, namespace_uri,
qualified_name, value, NULL);
+ else
+ webkit_dom_element_remove_attribute_ns (element, namespace_uri,
qualified_name);
+ }
+
+ g_free (tmp);
+ }
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "DocumentHasSelection") == 0) {
+ gboolean has_selection;
+
+ g_variant_get (parameters, "(t)", &page_id);
+ web_page = get_webkit_web_page_or_return_dbus_error (
+ invocation, web_extension, page_id);
+ if (!web_page)
+ return;
+
+ document = webkit_web_page_get_dom_document (web_page);
+ has_selection = e_dom_utils_document_has_selection (document);
+
+ g_dbus_method_invocation_return_value (
+ invocation, g_variant_new ("(b)", has_selection));
+ } else if (g_strcmp0 (method_name, "GetDocumentContentHTML") == 0) {
+ gchar *html_content;
+
+ g_variant_get (parameters, "(t)", &page_id);
+ web_page = get_webkit_web_page_or_return_dbus_error (
+ invocation, web_extension, page_id);
+ if (!web_page)
+ return;
+
+ document = webkit_web_page_get_dom_document (web_page);
+ html_content = e_dom_utils_get_document_content_html (document);
+
+ g_dbus_method_invocation_return_value (
+ invocation,
+ g_variant_new (
+ "(@s)",
+ g_variant_new_take_string (
+ html_content ? html_content : g_strdup (""))));
+ } else if (g_strcmp0 (method_name, "GetSelectionContentHTML") == 0) {
+ gchar *html_content;
+
+ g_variant_get (parameters, "(t)", &page_id);
+ web_page = get_webkit_web_page_or_return_dbus_error (
+ invocation, web_extension, page_id);
+ if (!web_page)
+ return;
+
+ document = webkit_web_page_get_dom_document (web_page);
+ html_content = e_dom_utils_get_selection_content_html (document);
+
+ g_dbus_method_invocation_return_value (
+ invocation,
+ g_variant_new (
+ "(@s)",
+ g_variant_new_take_string (
+ html_content ? html_content : g_strdup (""))));
+ } else if (g_strcmp0 (method_name, "GetSelectionContentText") == 0) {
+ gchar *text_content;
+
+ g_variant_get (parameters, "(t)", &page_id);
+ web_page = get_webkit_web_page_or_return_dbus_error (
+ invocation, web_extension, page_id);
+ if (!web_page)
+ return;
+
+ document = webkit_web_page_get_dom_document (web_page);
+ text_content = e_dom_utils_get_selection_content_text (document);
+
+ g_dbus_method_invocation_return_value (
+ invocation, g_variant_new_take_string (text_content));
+ } else if (g_strcmp0 (method_name, "AddCSSRuleIntoStyleSheet") == 0) {
+ const gchar *style_sheet_id, *selector, *style;
+
+ g_variant_get (
+ parameters,
+ "(t&s&s&s)",
+ &page_id, &style_sheet_id, &selector, &style);
+
+ web_page = get_webkit_web_page_or_return_dbus_error (
+ invocation, web_extension, page_id);
+ if (!web_page)
+ return;
+
+ document = webkit_web_page_get_dom_document (web_page);
+ e_dom_utils_add_css_rule_into_style_sheet (document, style_sheet_id, selector, style);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "CreateAndAddCSSStyleSheet") == 0) {
+ const gchar *style_sheet_id;
+
+ g_variant_get (parameters, "(t&s)", &page_id, &style_sheet_id);
+ web_page = get_webkit_web_page_or_return_dbus_error (
+ invocation, web_extension, page_id);
+ if (!web_page)
+ return;
+
+ document = webkit_web_page_get_dom_document (web_page);
+ e_dom_utils_create_and_add_css_style_sheet (document, style_sheet_id);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "EABContactFormatterBindDOM") == 0) {
+ g_variant_get (parameters, "(t)", &page_id);
+ web_page = get_webkit_web_page_or_return_dbus_error (
+ invocation, web_extension, page_id);
+ if (!web_page)
+ return;
+
+ document = webkit_web_page_get_dom_document (web_page);
+ e_dom_utils_eab_contact_formatter_bind_dom (document);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "EMailDisplayBindDOM") == 0) {
+ g_variant_get (parameters, "(t)", &page_id);
+ web_page = get_webkit_web_page_or_return_dbus_error (
+ invocation, web_extension, page_id);
+ if (!web_page)
+ return;
+
+ document = webkit_web_page_get_dom_document (web_page);
+ e_dom_utils_e_mail_display_bind_dom (document, connection);
+ e_dom_utils_bind_focus_on_elements (document, connection);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "ElementExists") == 0) {
+ const gchar *element_id;
+ gboolean element_exists;
+
+ g_variant_get (parameters, "(t&s)", &page_id, &element_id);
+ web_page = get_webkit_web_page_or_return_dbus_error (
+ invocation, web_extension, page_id);
+ if (!web_page)
+ return;
+
+ document = webkit_web_page_get_dom_document (web_page);
+ element_exists = e_dom_utils_element_exists (document, element_id);
+
+ g_dbus_method_invocation_return_value (
+ invocation, g_variant_new ("(bt)", element_exists, page_id));
+ } else if (g_strcmp0 (method_name, "GetActiveElementName") == 0) {
+ gchar *element_name;
+
+ g_variant_get (parameters, "(t)", &page_id);
+ web_page = get_webkit_web_page_or_return_dbus_error (
+ invocation, web_extension, page_id);
+ if (!web_page)
+ return;
+
+ document = webkit_web_page_get_dom_document (web_page);
+ element_name = e_dom_utils_get_active_element_name (document);
+
+ g_dbus_method_invocation_return_value (
+ invocation,
+ g_variant_new (
+ "(@s)",
+ g_variant_new_take_string (
+ element_name ? element_name : g_strdup (""))));
+ } else if (g_strcmp0 (method_name, "EMailPartHeadersBindDOMElement") == 0) {
+ const gchar *element_id;
+
+ g_variant_get (parameters, "(t&s)", &page_id, &element_id);
+ web_page = get_webkit_web_page_or_return_dbus_error (
+ invocation, web_extension, page_id);
+ if (!web_page)
+ return;
+
+ document = webkit_web_page_get_dom_document (web_page);
+ e_dom_utils_e_mail_part_headers_bind_dom_element (document, element_id);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "VCardInlineBindDOM") == 0) {
+ const gchar *element_id;
+
+ g_variant_get (parameters, "(t&s)", &page_id, &element_id);
+ web_page = get_webkit_web_page_or_return_dbus_error (
+ invocation, web_extension, page_id);
+ if (!web_page)
+ return;
+
+ document = webkit_web_page_get_dom_document (web_page);
+ e_dom_utils_module_vcard_inline_bind_dom (
+ document, element_id, connection);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "VCardInlineUpdateButton") == 0) {
+ const gchar *button_id, *html_label, *access_key;
+
+ g_variant_get (
+ parameters,
+ "(t&s&s&s)",
+ &page_id, &button_id, &html_label, &access_key);
+
+ web_page = get_webkit_web_page_or_return_dbus_error (
+ invocation, web_extension, page_id);
+ if (!web_page)
+ return;
+
+ document = webkit_web_page_get_dom_document (web_page);
+ e_dom_utils_module_vcard_inline_update_button (
+ document, button_id, html_label, access_key);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "VCardInlineSetIFrameSrc") == 0) {
+ const gchar *src, *button_id;
+
+ g_variant_get (parameters, "(t&s&s)", &page_id, &button_id, &src);
+ web_page = get_webkit_web_page_or_return_dbus_error (
+ invocation, web_extension, page_id);
+ if (!web_page)
+ return;
+
+ document = webkit_web_page_get_dom_document (web_page);
+ e_dom_utils_module_vcard_inline_set_iframe_src (document, button_id, src);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "GetDocumentURIFromPoint") == 0) {
+ WebKitDOMDocument *document_at_point;
+ gchar *document_uri = NULL;
+ gint32 xx = 0, yy = 0;
+
+ g_variant_get (parameters, "(tii)", &page_id, &xx, &yy);
+ web_page = get_webkit_web_page_or_return_dbus_error (invocation, web_extension, page_id);
+ if (!web_page)
+ return;
+
+ document = webkit_web_page_get_dom_document (web_page);
+ document_at_point = e_dom_utils_get_document_from_point (document, xx, yy);
+
+ if (document_at_point)
+ document_uri = webkit_dom_document_get_document_uri (document_at_point);
+
+ g_dbus_method_invocation_return_value (
+ invocation,
+ g_variant_new ("(@s)", g_variant_new_take_string (document_uri ? document_uri :
g_strdup (""))));
+ } else if (g_strcmp0 (method_name, "SetDocumentIFrameSrc") == 0) {
+ const gchar *document_uri = NULL, *new_iframe_src = NULL;
+ WebKitDOMDocument *iframe_document;
+
+ g_variant_get (parameters, "(t&s&s)", &page_id, &document_uri, &new_iframe_src);
+ web_page = get_webkit_web_page_or_return_dbus_error (invocation, web_extension, page_id);
+ if (!web_page)
+ return;
+
+ document = webkit_web_page_get_dom_document (web_page);
+ iframe_document = e_dom_utils_find_document_with_uri (document, document_uri);
+
+ if (iframe_document) {
+ WebKitDOMDOMWindow *dom_window;
+ WebKitDOMElement *frame_element;
+
+ /* Get frame's window and from the window the actual <iframe> element */
+ dom_window = webkit_dom_document_get_default_view (iframe_document);
+ frame_element = webkit_dom_dom_window_get_frame_element (dom_window);
+ webkit_dom_html_iframe_element_set_src (
+ WEBKIT_DOM_HTML_IFRAME_ELEMENT (frame_element), new_iframe_src);
+ g_clear_object (&dom_window);
+ }
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ }
+}
+
+static GVariant *
+handle_get_property (GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *property_name,
+ GError **error,
+ gpointer user_data)
+{
+ EWebExtension *extension = E_WEB_EXTENSION (user_data);
+ GVariant *variant = NULL;
+
+ if (g_strcmp0 (property_name, "NeedInput") == 0) {
+ variant = g_variant_new_boolean (extension->priv->need_input);
+ }
+
+ return variant;
+}
+
+static gboolean
+handle_set_property (GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *property_name,
+ GVariant *variant,
+ GError **error,
+ gpointer user_data)
+{
+ EWebExtension *extension = E_WEB_EXTENSION (user_data);
+ GError *local_error = NULL;
+ GVariantBuilder *builder;
+
+ builder = g_variant_builder_new (G_VARIANT_TYPE_ARRAY);
+
+ if (g_strcmp0 (property_name, "NeedInput") == 0) {
+ gboolean value = g_variant_get_boolean (variant);
+
+ if (value == extension->priv->need_input)
+ goto exit;
+
+ extension->priv->need_input = value;
+
+ g_variant_builder_add (builder,
+ "{sv}",
+ "NeedInput",
+ g_variant_new_boolean (value));
+ }
+
+ g_dbus_connection_emit_signal (connection,
+ NULL,
+ object_path,
+ "org.freedesktop.DBus.Properties",
+ "PropertiesChanged",
+ g_variant_new (
+ "(sa{sv}as)",
+ interface_name,
+ builder,
+ NULL),
+ &local_error);
+
+ g_assert_no_error (local_error);
+
+ exit:
+ g_variant_builder_unref (builder);
+
+ return TRUE;
+}
+
+static const GDBusInterfaceVTable interface_vtable = {
+ handle_method_call,
+ handle_get_property,
+ handle_set_property
+};
+
+static void
+e_web_extension_dispose (GObject *object)
+{
+ EWebExtension *extension = E_WEB_EXTENSION (object);
+
+ if (extension->priv->dbus_connection) {
+ g_dbus_connection_unregister_object (
+ extension->priv->dbus_connection,
+ extension->priv->registration_id);
+ extension->priv->registration_id = 0;
+ extension->priv->dbus_connection = NULL;
+ }
+
+ g_clear_object (&extension->priv->wk_extension);
+
+ G_OBJECT_CLASS (e_web_extension_parent_class)->dispose (object);
+}
+
+static void
+e_web_extension_class_init (EWebExtensionClass *class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+ object_class->dispose = e_web_extension_dispose;
+
+ g_type_class_add_private (object_class, sizeof(EWebExtensionPrivate));
+}
+
+static void
+e_web_extension_init (EWebExtension *extension)
+{
+ extension->priv = G_TYPE_INSTANCE_GET_PRIVATE (extension, E_TYPE_WEB_EXTENSION, EWebExtensionPrivate);
+
+ extension->priv->initialized = FALSE;
+ extension->priv->need_input = FALSE;
+}
+
+static gpointer
+e_web_extension_create_instance(gpointer data)
+{
+ return g_object_new (E_TYPE_WEB_EXTENSION, NULL);
+}
+
+EWebExtension *
+e_web_extension_get (void)
+{
+ static GOnce once_init = G_ONCE_INIT;
+ return E_WEB_EXTENSION (g_once (&once_init, e_web_extension_create_instance, NULL));
+}
+
+static gboolean
+web_page_send_request_cb (WebKitWebPage *web_page,
+ WebKitURIRequest *request,
+ WebKitURIResponse *redirected_response,
+ EWebExtension *extension)
+{
+ const gchar *request_uri;
+ const gchar *page_uri;
+
+ request_uri = webkit_uri_request_get_uri (request);
+ page_uri = webkit_web_page_get_uri (web_page);
+
+ /* Always load the main resource. */
+ if (g_strcmp0 (request_uri, page_uri) == 0 ||
+ /* Do not influence real pages, like those with eds OAuth sign-in */
+ g_str_has_prefix (page_uri, "http:") ||
+ g_str_has_prefix (page_uri, "https:"))
+ return FALSE;
+
+ if (g_str_has_prefix (request_uri, "http:") ||
+ g_str_has_prefix (request_uri, "https:")) {
+ gchar *new_uri;
+
+ new_uri = g_strconcat ("evo-", request_uri, NULL);
+
+ webkit_uri_request_set_uri (request, new_uri);
+
+ g_free (new_uri);
+ }
+
+ return FALSE;
+}
+
+static void
+web_page_document_loaded_cb (WebKitWebPage *web_page,
+ gpointer user_data)
+{
+ WebKitDOMDocument *document;
+
+ document = webkit_web_page_get_dom_document (web_page);
+
+ e_dom_utils_replace_local_image_links (document);
+
+ if ((webkit_dom_document_query_selector (
+ document, "[data-evo-signature-plain-text-mode]", NULL))) {
+
+ WebKitDOMHTMLElement *body;
+
+ body = webkit_dom_document_get_body (document);
+
+ webkit_dom_element_set_attribute (
+ WEBKIT_DOM_ELEMENT (body),
+ "style",
+ "font-family: Monospace;",
+ NULL);
+ }
+}
+
+static void
+web_page_created_cb (WebKitWebExtension *wk_extension,
+ WebKitWebPage *web_page,
+ EWebExtension *extension)
+{
+ g_signal_connect_object (
+ web_page, "send-request",
+ G_CALLBACK (web_page_send_request_cb),
+ extension, 0);
+
+ g_signal_connect_object (
+ web_page, "document-loaded",
+ G_CALLBACK (web_page_document_loaded_cb),
+ extension, 0);
+
+}
+
+void
+e_web_extension_initialize (EWebExtension *extension,
+ WebKitWebExtension *wk_extension)
+{
+ g_return_if_fail (E_IS_WEB_EXTENSION (extension));
+
+ if (extension->priv->initialized)
+ return;
+
+ extension->priv->initialized = TRUE;
+
+ extension->priv->wk_extension = g_object_ref (wk_extension);
+
+ g_signal_connect (
+ wk_extension, "page-created",
+ G_CALLBACK (web_page_created_cb), extension);
+}
+
+void
+e_web_extension_dbus_register (EWebExtension *extension,
+ GDBusConnection *connection)
+{
+ GError *error = NULL;
+ static GDBusNodeInfo *introspection_data = NULL;
+
+ g_return_if_fail (E_IS_WEB_EXTENSION (extension));
+ g_return_if_fail (G_IS_DBUS_CONNECTION (connection));
+
+ if (!introspection_data) {
+ introspection_data =
+ g_dbus_node_info_new_for_xml (introspection_xml, NULL);
+
+ extension->priv->registration_id =
+ g_dbus_connection_register_object (
+ connection,
+ E_WEB_EXTENSION_OBJECT_PATH,
+ introspection_data->interfaces[0],
+ &interface_vtable,
+ extension,
+ NULL,
+ &error);
+
+ if (!extension->priv->registration_id) {
+ g_warning ("Failed to register object: %s\n", error->message);
+ g_error_free (error);
+ } else {
+ extension->priv->dbus_connection = connection;
+ g_object_add_weak_pointer (
+ G_OBJECT (connection),
+ (gpointer *)&extension->priv->dbus_connection);
+ }
+ }
+}
diff --git a/web-extensions/e-web-extension.h b/web-extensions/e-web-extension.h
new file mode 100644
index 0000000..a1f5837
--- /dev/null
+++ b/web-extensions/e-web-extension.h
@@ -0,0 +1,72 @@
+/*
+ * e-web-extension.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/>
+ *
+ */
+
+#ifndef E_WEB_EXTENSION_H
+#define E_WEB_EXTENSION_H
+
+#include <webkit2/webkit-web-extension.h>
+#include <glib-object.h>
+
+/* Standard GObject macros */
+#define E_TYPE_WEB_EXTENSION \
+ (e_web_extension_get_type ())
+#define E_WEB_EXTENSION(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_WEB_EXTENSION, EWebExtension))
+#define E_WEB_EXTENSION_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_WEB_EXTENSION, EWebExtensionClass))
+#define E_IS_WEB_EXTENSION(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_WEB_EXTENSION))
+#define E_IS_WEB_EXTENSION_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_WEB_EXTENSION))
+#define E_WEB_EXTENSION_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_WEB_EXTENSION, EWebExtensionClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EWebExtension EWebExtension;
+typedef struct _EWebExtensionClass EWebExtensionClass;
+typedef struct _EWebExtensionPrivate EWebExtensionPrivate;
+
+struct _EWebExtension {
+ GObject parent;
+ EWebExtensionPrivate *priv;
+};
+
+struct _EWebExtensionClass
+{
+ GObjectClass parent_class;
+};
+
+GType e_web_extension_get_type (void) G_GNUC_CONST;
+
+EWebExtension * e_web_extension_get (void);
+
+void e_web_extension_initialize (EWebExtension *extension,
+ WebKitWebExtension *wk_extension);
+
+void e_web_extension_dbus_register (EWebExtension *extension,
+ GDBusConnection *connection);
+
+G_END_DECLS
+
+#endif /* E_WEB_EXTENSION_H */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]