[evolution/webkit-composer: 30/147] Make inserting a auto-replacing emoticons work



commit bed0b60e0712139246c763d746636318a3566d03
Author: Dan VrÃtil <dvratil redhat com>
Date:   Thu Aug 9 10:28:59 2012 +0200

    Make inserting a auto-replacing emoticons work
    
    The algorithm for magic smileys is taken from GtkHTML
    (I admit I don't 100% understand how it works), because
    it's quick and known to work quite well.
    
    TODO: It would be nice to automagically replace emoticons
    in pasted and inserted text as well.

 e-util/e-editor-actions.c        |   46 +++-------
 e-util/e-editor-widget.c         |  175 +++++++++++++++++++++++++++++++++++++-
 e-util/e-emoticon-chooser-menu.c |    2 +-
 e-util/e-emoticon-chooser.c      |    2 +-
 e-util/e-emoticon-chooser.h      |    4 +-
 e-util/e-emoticon-tool-button.c  |    2 +-
 e-util/e-emoticon.c              |   25 ++++++
 e-util/e-emoticon.h              |    2 +
 8 files changed, 219 insertions(+), 39 deletions(-)
---
diff --git a/e-util/e-editor-actions.c b/e-util/e-editor-actions.c
index 0e6fdee..c09c63d 100644
--- a/e-util/e-editor-actions.c
+++ b/e-util/e-editor-actions.c
@@ -30,6 +30,7 @@
 #include "e-editor-private.h"
 #include "e-editor-widgets.h"
 #include "e-emoticon-action.h"
+#include "e-emoticon-chooser.h"
 #include "e-image-chooser-dialog.h"
 
 static void
@@ -569,45 +570,24 @@ action_indent_cb (GtkAction *action,
 
 static void
 action_insert_emoticon_cb (GtkAction *action,
-      EEditor *editor)
+			   EEditor *editor)
 {
-	/* FIXME WEBKIT
-	GtkHTML *html;
-	HTMLObject *image;
-	GtkIconInfo *icon_info;
-	GtkIconTheme *icon_theme;
-	GtkhtmlFaceChooser *chooser;
-	GtkhtmlFace *face;
-	const gchar *filename;
+	EEditorWidget *widget;
+	EEditorSelection *selection;
+	EEmoticonChooser *chooser;
+	EEmoticon *emoticon;
 	gchar *uri = NULL;
 
-	html = gtkhtml_editor_get_html (editor);
+	chooser = E_EMOTICON_CHOOSER (action);
+	emoticon = e_emoticon_chooser_get_current_emoticon (chooser);
+	g_return_if_fail (emoticon != NULL);
 
-	chooser = GTKHTML_FACE_CHOOSER (action);
-	face = gtkhtml_face_chooser_get_current_face (chooser);
-	g_return_if_fail (face != NULL);
-
-	icon_theme = gtk_icon_theme_get_default ();
-	icon_info = gtk_icon_theme_lookup_icon (
-		icon_theme, face->icon_name, 16, 0);
-	g_return_if_fail (icon_info != NULL);
-
-	filename = gtk_icon_info_get_filename (icon_info);
-	if (filename != NULL)
-		uri = g_filename_to_uri (filename, NULL, NULL);
-	gtk_icon_info_free (icon_info);
-	g_return_if_fail (uri != NULL);
-
-	image = html_image_new (
-		html_engine_get_image_factory (html->engine),
-		uri, NULL, NULL, -1, -1, FALSE, FALSE, 0, NULL,
-		HTML_VALIGN_MIDDLE, FALSE);
-	html_image_set_alt (HTML_IMAGE (image), face->text_face);
-	html_engine_paste_object (
-		html->engine, image, html_object_get_length (image));
+	uri = e_emoticon_get_uri (emoticon);
+	widget = e_editor_get_editor_widget (editor);
+	selection = e_editor_widget_get_selection (widget);
+	e_editor_selection_insert_image (selection, uri);
 
 	g_free (uri);
-	*/
 }
 
 static void
diff --git a/e-util/e-editor-widget.c b/e-util/e-editor-widget.c
index 4b55200..f5fed8c 100644
--- a/e-util/e-editor-widget.c
+++ b/e-util/e-editor-widget.c
@@ -22,8 +22,10 @@
 
 #include "e-editor-widget.h"
 #include "e-editor.h"
+#include "e-emoticon-chooser.h"
 
 #include <glib/gi18n-lib.h>
+#include <gdk/gdkkeysyms.h>
 
 struct _EEditorWidgetPrivate {
 	gint changed		: 1;
@@ -47,8 +49,7 @@ struct _EEditorWidgetPrivate {
 G_DEFINE_TYPE (
 	EEditorWidget,
 	e_editor_widget,
-	WEBKIT_TYPE_WEB_VIEW
-);
+	WEBKIT_TYPE_WEB_VIEW);
 
 enum {
 	PROP_0,
@@ -65,6 +66,24 @@ enum {
 	PROP_CAN_UNDO
 };
 
+static WebKitDOMRange *
+editor_widget_get_dom_range (EEditorWidget *widget)
+{
+	WebKitDOMDocument *document;
+	WebKitDOMDOMWindow *window;
+	WebKitDOMDOMSelection *selection;
+
+	document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (widget));
+	window = webkit_dom_document_get_default_view (document);
+	selection = webkit_dom_dom_window_get_selection (window);
+
+	if (webkit_dom_dom_selection_get_range_count (selection) < 1) {
+		return NULL;
+	}
+
+	return webkit_dom_dom_selection_get_range_at (selection, 0, NULL);
+}
+
 static void
 editor_widget_strip_formatting (EEditorWidget *widget)
 {
@@ -129,6 +148,154 @@ editor_widget_selection_changed_cb (EEditorWidget *widget,
 	}
 }
 
+/* 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"
+};
+
+static void
+editor_widget_check_magic_smileys (EEditorWidget *widget,
+				   WebKitDOMRange *range)
+{
+	gint pos;
+	gint state;
+	gint relative;
+	gint start;
+	gchar *node_text;
+	gunichar uc;
+	WebKitDOMNode *node;
+
+	node = webkit_dom_range_get_end_container (range, NULL);
+	if (!webkit_dom_node_get_node_type (node) == 3) {
+		return;
+	}
+
+	node_text = webkit_dom_text_get_whole_text ((WebKitDOMText *) node);
+	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) {
+		GtkIconInfo *icon_info;
+		const gchar *filename;
+		gchar *filename_uri;
+		WebKitDOMDocument *document;
+		WebKitDOMDOMWindow *window;
+		WebKitDOMDOMSelection *selection;
+
+		if (pos > 0) {
+			uc = g_utf8_get_char (g_utf8_offset_to_pointer (node_text, pos - 1));
+			if (uc != ' ' && uc != '\t')
+				return;
+		}
+
+		/* Select the text-smiley and replace it by <img> */
+		document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (widget));
+		window = webkit_dom_document_get_default_view (document);
+		selection = webkit_dom_dom_window_get_selection (window);
+		webkit_dom_dom_selection_set_base_and_extent (
+			selection, webkit_dom_range_get_end_container (range, NULL),
+			pos, webkit_dom_range_get_end_container (range, NULL),
+			start + 1, NULL);
+
+		/* Convert a named icon to a file URI. */
+		icon_info = gtk_icon_theme_lookup_icon (
+			gtk_icon_theme_get_default (),
+			emoticons_icon_names[-state - 1], 16, 0);
+		g_return_if_fail (icon_info != NULL);
+		filename = gtk_icon_info_get_filename (icon_info);
+		g_return_if_fail (filename != NULL);
+		filename_uri = g_filename_to_uri (filename, NULL, NULL);
+
+		e_editor_selection_insert_image (
+			widget->priv->selection, filename_uri);
+
+		g_free (filename_uri);
+		gtk_icon_info_free (icon_info);
+	}
+}
+
+static gboolean
+editor_widget_key_release_event (GtkWidget *gtk_widget,
+				 GdkEventKey *event)
+{
+	WebKitDOMRange *range;
+	EEditorWidget *widget = E_EDITOR_WIDGET (gtk_widget);
+
+	range = editor_widget_get_dom_range (widget);
+
+	if (widget->priv->magic_smileys) {
+		editor_widget_check_magic_smileys (widget, range);
+	}
+
+	/* Propagate the event to WebKit */
+	return FALSE;
+}
+
 static void
 e_editor_widget_get_property (GObject *object,
 			      guint property_id,
@@ -251,6 +418,7 @@ static void
 e_editor_widget_class_init (EEditorWidgetClass *klass)
 {
 	GObjectClass *object_class;
+	GtkWidgetClass *widget_class;
 
 	g_type_class_add_private (klass, sizeof (EEditorWidgetPrivate));
 
@@ -259,6 +427,9 @@ e_editor_widget_class_init (EEditorWidgetClass *klass)
 	object_class->set_property = e_editor_widget_set_property;
 	object_class->finalize = e_editor_widget_finalize;
 
+	widget_class = GTK_WIDGET_CLASS (klass);
+	widget_class->key_release_event = editor_widget_key_release_event;
+
 	g_object_class_install_property (
 		object_class,
 		PROP_MODE,
diff --git a/e-util/e-emoticon-chooser-menu.c b/e-util/e-emoticon-chooser-menu.c
index 619bd21..7bf6184 100644
--- a/e-util/e-emoticon-chooser-menu.c
+++ b/e-util/e-emoticon-chooser-menu.c
@@ -133,7 +133,7 @@ emoticon_chooser_menu_init (EEmoticonChooserMenu *chooser_menu)
 	GList *list, *iter;
 
 	chooser = E_EMOTICON_CHOOSER (chooser_menu);
-	list = e_emoticon_chooser_get_items (chooser);
+	list = e_emoticon_chooser_get_items ();
 
 	for (iter = list; iter != NULL; iter = iter->next) {
 		EEmoticon *face = iter->data;
diff --git a/e-util/e-emoticon-chooser.c b/e-util/e-emoticon-chooser.c
index c8a92b0..8136f2c 100644
--- a/e-util/e-emoticon-chooser.c
+++ b/e-util/e-emoticon-chooser.c
@@ -168,7 +168,7 @@ e_emoticon_chooser_item_activated (EEmoticonChooser *chooser)
 }
 
 GList *
-e_emoticon_chooser_get_items (EEmoticonChooser *chooser)
+e_emoticon_chooser_get_items (void)
 {
 	GList *list = NULL;
 	gint ii;
diff --git a/e-util/e-emoticon-chooser.h b/e-util/e-emoticon-chooser.h
index 7390da3..a134c7e 100644
--- a/e-util/e-emoticon-chooser.h
+++ b/e-util/e-emoticon-chooser.h
@@ -55,6 +55,7 @@ struct _EEmoticonChooserIface {
 };
 
 GType		e_emoticon_chooser_get_type	(void);
+
 EEmoticon *	e_emoticon_chooser_get_current_emoticon
 						(EEmoticonChooser *chooser);
 void		e_emoticon_chooser_set_current_emoticon
@@ -62,7 +63,8 @@ void		e_emoticon_chooser_set_current_emoticon
 						 EEmoticon *emoticon);
 void		e_emoticon_chooser_item_activated
 						(EEmoticonChooser *chooser);
-GList *		e_emoticon_chooser_get_items	(EEmoticonChooser *chooser);
+
+GList *		e_emoticon_chooser_get_items	(void);
 
 G_END_DECLS
 
diff --git a/e-util/e-emoticon-tool-button.c b/e-util/e-emoticon-tool-button.c
index dc0d0dd..eaf2105 100644
--- a/e-util/e-emoticon-tool-button.c
+++ b/e-util/e-emoticon-tool-button.c
@@ -601,7 +601,7 @@ emoticon_tool_button_init (EEmoticonToolButton *button)
 	container = widget;
 
 	chooser = E_EMOTICON_CHOOSER (button);
-	list = e_emoticon_chooser_get_items (chooser);
+	list = e_emoticon_chooser_get_items ();
 	g_assert (g_list_length (list) <= NUM_ROWS * NUM_COLS);
 
 	for (iter = list, ii = 0; iter != NULL; iter = iter->next, ii++) {
diff --git a/e-util/e-emoticon.c b/e-util/e-emoticon.c
index 1d394e6..d5b69c6 100644
--- a/e-util/e-emoticon.c
+++ b/e-util/e-emoticon.c
@@ -17,6 +17,8 @@
 
 #include "e-emoticon.h"
 
+#include <gtk/gtk.h>
+
 static EEmoticon *
 emoticon_copy (EEmoticon *emoticon)
 {
@@ -87,3 +89,26 @@ e_emoticon_free (EEmoticon *emoticon)
 {
 	g_boxed_free (E_TYPE_EMOTICON, emoticon);
 }
+
+gchar *
+e_emoticon_get_uri(EEmoticon *emoticon)
+{
+	GtkIconInfo *icon_info;
+	GtkIconTheme *icon_theme;
+	const gchar *filename;
+	gchar *uri = NULL;
+
+	icon_theme = gtk_icon_theme_get_default ();
+	icon_info = gtk_icon_theme_lookup_icon (
+		icon_theme, emoticon->icon_name, 16, 0);
+	g_return_val_if_fail (icon_info != NULL, NULL);
+
+	filename = gtk_icon_info_get_filename (icon_info);
+	if (filename != NULL) {
+		uri = g_filename_to_uri (filename, NULL, NULL);
+	}
+	gtk_icon_info_free (icon_info);
+	g_return_val_if_fail (uri != NULL, NULL);
+
+	return uri;
+}
diff --git a/e-util/e-emoticon.h b/e-util/e-emoticon.h
index cf270ef..17995d5 100644
--- a/e-util/e-emoticon.h
+++ b/e-util/e-emoticon.h
@@ -43,6 +43,8 @@ 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);
+
 G_END_DECLS
 
 #endif /* E_EMOTICON_H */



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]