[libgda] New GdauiRtEditor



commit faa52e080ccb7623ba6e300d60c49a9f6bf10ee8
Author: Vivien Malerba <malerba gnome-db org>
Date:   Sat Nov 27 12:13:39 2010 +0100

    New GdauiRtEditor

 doc/C/Makefile.am                               |    2 +-
 doc/C/libgda-4.0-docs.sgml                      |    2 +
 doc/C/libgda-ui-sections.txt                    |   16 +
 doc/C/libgda-ui.types                           |    1 +
 doc/C/tmpl/gdaui-rt-editor.sgml                 |  103 ++
 doc/C/vi-rte.png                                |  Bin 0 -> 13283 bytes
 doc/C/visual_index.xml                          |    3 +
 libgda-ui/Makefile.am                           |    3 +
 libgda-ui/bullet.h                              |   31 +
 libgda-ui/bullet.png                            |  Bin 0 -> 239 bytes
 libgda-ui/bulleth.h                             |   31 +
 libgda-ui/bulleth.png                           |  Bin 0 -> 247 bytes
 libgda-ui/data-entries/plugins/Makefile.am      |    2 +
 libgda-ui/data-entries/plugins/gdaui-entry-rt.c |  304 ++++
 libgda-ui/data-entries/plugins/gdaui-entry-rt.h |   59 +
 libgda-ui/data-entries/plugins/libmain.c        |   25 +-
 libgda-ui/gdaui-rt-editor.c                     | 1904 +++++++++++++++++++++++
 libgda-ui/gdaui-rt-editor.h                     |   70 +
 libgda-ui/libgda-ui.h                           |    3 +-
 libgda-ui/libgda-ui.symbols                     |    5 +
 testing/.gitignore                              |    1 +
 testing/Makefile.am                             |   11 +-
 testing/gdaui-test-rt-editor.c                  |  178 +++
 23 files changed, 2750 insertions(+), 4 deletions(-)
---
diff --git a/doc/C/Makefile.am b/doc/C/Makefile.am
index 7d43fab..779d873 100644
--- a/doc/C/Makefile.am
+++ b/doc/C/Makefile.am
@@ -67,7 +67,7 @@ HTML_IMAGES = DataModels.png \
 	SqlIdentifiers.png thread-wrapper.png \
 	vi-basic-form.png vi-combo.png vi-data-entry.png \
 	vi-login.png vi-cloud.png vi-provider-selector.png vi-raw-grid.png \
-	vi-info.png vi-filter.png vi-server-op.png
+	vi-info.png vi-filter.png vi-server-op.png vi-rte.png
 
 # Extra options to supply to gtkdoc-fixref
 FIXXREF_OPTIONS=
diff --git a/doc/C/libgda-4.0-docs.sgml b/doc/C/libgda-4.0-docs.sgml
index 820f439..7f4499c 100644
--- a/doc/C/libgda-4.0-docs.sgml
+++ b/doc/C/libgda-4.0-docs.sgml
@@ -152,6 +152,7 @@
 <!ENTITY libgdaui-GdauiTreeStore SYSTEM "xml/gdaui-tree-store.xml">
 <!ENTITY libgdaui-GdauiCloud SYSTEM "xml/gdaui-cloud.xml">
 <!ENTITY libgdaui-GdauiDataSelector SYSTEM "xml/gdaui-data-selector.xml">
+<!ENTITY libgdaui-GdauiRtEditor SYSTEM "xml/gdaui-rt-editor.xml">
 ]>
 
 <book id="index">
@@ -1277,6 +1278,7 @@ g_object_unref (store);
       &libgdaui-GdauiRawGrid;
       &libgdaui-GdauiCombo;
       &libgdaui-GdauiCloud;
+      &libgdaui-GdauiRtEditor;
 
       &libgdaui-gdaui-plugins;
 
diff --git a/doc/C/libgda-ui-sections.txt b/doc/C/libgda-ui-sections.txt
index d0d83b9..2fa2538 100644
--- a/doc/C/libgda-ui-sections.txt
+++ b/doc/C/libgda-ui-sections.txt
@@ -326,3 +326,19 @@ GDAUI_IS_DATA_SELECTOR
 GDAUI_TYPE_DATA_SELECTOR
 gdaui_data_selector_get_type
 </SECTION>
+
+<SECTION>
+<FILE>gdaui-rt-editor</FILE>
+<TITLE>GdauiRtEditor</TITLE>
+GdauiRtEditor
+gdaui_rt_editor_new
+gdaui_rt_editor_get_contents
+gdaui_rt_editor_set_contents
+gdaui_rt_editor_set_editable
+<SUBSECTION Standard>
+GDAUI_RT_EDITOR
+GDAUI_RT_EDITOR_CLASS
+GDAUI_IS_RT_EDITOR
+GDAUI_TYPE_RT_EDITOR
+gdaui_rt_editor_get_type
+</SECTION>
diff --git a/doc/C/libgda-ui.types b/doc/C/libgda-ui.types
index e2bec78..8031ee0 100644
--- a/doc/C/libgda-ui.types
+++ b/doc/C/libgda-ui.types
@@ -16,3 +16,4 @@ gdaui_raw_grid_get_type
 gdaui_server_operation_get_type
 gdaui_tree_store_get_type
 gdaui_cloud_get_type
+gdaui_rt_editor_get_type
diff --git a/doc/C/tmpl/gdaui-rt-editor.sgml b/doc/C/tmpl/gdaui-rt-editor.sgml
new file mode 100644
index 0000000..185505e
--- /dev/null
+++ b/doc/C/tmpl/gdaui-rt-editor.sgml
@@ -0,0 +1,103 @@
+<!-- ##### SECTION Title ##### -->
+GdauiRtEditor
+
+<!-- ##### SECTION Short_Description ##### -->
+Rich text editor which uses a subset of the <ulink url="http://www.txt2tags.org/markup.html";>txt2tags</ulink> markup.
+
+<!-- ##### SECTION Long_Description ##### -->
+<para>
+  The text entered in the editor can be formatted using bold, underline, title, ... attributes
+  and then extracted using a subset of the <ulink url="http://www.txt2tags.org/markup.html";>txt2tags</ulink>
+  markup. Use this widget to edit textual fields where some markup is desirable to organize the text.
+</para>
+<para>
+  For example the real text used to obtain the formatting in the figure is:
+  <programlisting>
+blah //italic// blah.
+and ** BOLD!//both italic and bold// Bold!**
+Nice Picture: [[[R2RrUAA...y8vLy8tYQwAA]]] Yes
+- List item --One--
+- List item **Two**
+ - sub1
+ - sub2</programlisting>
+  where the picture's serialized data has been truncated here for readability
+  (between the [[[ and ]]] markers). Pictures are usually inserted using the incorporated
+  tollbar and not y hand (even though it's possible).
+</para>
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION Stability_Level ##### -->
+
+
+<!-- ##### SECTION Image ##### -->
+
+
+<!-- ##### STRUCT GdauiRtEditor ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### SIGNAL GdauiRtEditor::changed ##### -->
+<para>
+
+</para>
+
+ gdauirteditor: the object which received the signal.
+
+<!-- ##### ARG GdauiRtEditor:buffer ##### -->
+<para>
+
+</para>
+
+<!-- ##### ARG GdauiRtEditor:no-background ##### -->
+<para>
+
+</para>
+
+<!-- ##### ARG GdauiRtEditor:show-markup ##### -->
+<para>
+
+</para>
+
+<!-- ##### FUNCTION gdaui_rt_editor_new ##### -->
+<para>
+
+</para>
+
+ void: 
+ Returns: 
+
+
+<!-- ##### FUNCTION gdaui_rt_editor_get_contents ##### -->
+<para>
+
+</para>
+
+ editor: 
+ Returns: 
+
+
+<!-- ##### FUNCTION gdaui_rt_editor_set_contents ##### -->
+<para>
+
+</para>
+
+ editor: 
+ markup: 
+ length: 
+
+
+<!-- ##### FUNCTION gdaui_rt_editor_set_editable ##### -->
+<para>
+
+</para>
+
+ editor: 
+ editable: 
+
+
diff --git a/doc/C/vi-rte.png b/doc/C/vi-rte.png
new file mode 100644
index 0000000..0efc663
Binary files /dev/null and b/doc/C/vi-rte.png differ
diff --git a/doc/C/visual_index.xml b/doc/C/visual_index.xml
index ee6e903..42f8035 100644
--- a/doc/C/visual_index.xml
+++ b/doc/C/visual_index.xml
@@ -29,4 +29,7 @@
   <link linkend="GdauiServerOperation">
     <inlinegraphic fileref="vi-server-op.png" format="PNG"></inlinegraphic>
   </link>
+  <link linkend="GdauiRtEditor">
+    <inlinegraphic fileref="vi-rte.png" format="PNG"></inlinegraphic>
+  </link>
 </para>
diff --git a/libgda-ui/Makefile.am b/libgda-ui/Makefile.am
index 6830feb..fbc46d4 100644
--- a/libgda-ui/Makefile.am
+++ b/libgda-ui/Makefile.am
@@ -35,6 +35,7 @@ ui_headers = \
 	gdaui-provider-selector.h \
 	gdaui-raw-form.h \
 	gdaui-raw-grid.h \
+	gdaui-rt-editor.h \
 	gdaui-server-operation.h \
 	gdaui-tree-store.h \
 	gdaui-plugin.h
@@ -56,6 +57,8 @@ ui_sources = \
 	gdaui-provider-selector.c \
 	gdaui-raw-form.c \
 	gdaui-raw-grid.c \
+	bullet.h \
+	gdaui-rt-editor.c \
 	gdaui-server-operation.c \
 	gdaui-set.h \
 	gdaui-set.c \
diff --git a/libgda-ui/bullet.h b/libgda-ui/bullet.h
new file mode 100644
index 0000000..92cd1a3
--- /dev/null
+++ b/libgda-ui/bullet.h
@@ -0,0 +1,31 @@
+/* GdkPixbuf RGBA C-Source image dump 1-byte-run-length-encoded */
+
+#ifdef __SUNPRO_C
+#pragma align 4 (bullet_pixdata)
+#endif
+#ifdef __GNUC__
+static const guint8 bullet_pixdata[] __attribute__ ((__aligned__ (4))) = 
+#else
+static const guint8 bullet_pixdata[] = 
+#endif
+{ ""
+  /* Pixbuf magic (0x47646b50) */
+  "GdkP"
+  /* length: header (24) + pixel_data (136) */
+  "\0\0\0\240"
+  /* pixdata_type (0x2010002) */
+  "\2\1\0\2"
+  /* rowstride (24) */
+  "\0\0\0\30"
+  /* width (6) */
+  "\0\0\0\6"
+  /* height (9) */
+  "\0\0\0\11"
+  /* pixel_data: */
+  "\2\0\0\0\20\0\0\0 \202\0\0\0o\4\0\0\0@\0\0\0\20\0\0\0 \0\0\0\257\202"
+  "\0\0\0\357\4\0\0\0\257\0\0\0 \0\0\0o\0\0\0\357\202\0\0\0\377\1\0\0\0"
+  "\357\202\0\0\0o\1\0\0\0\357\202\0\0\0\377\4\0\0\0\357\0\0\0o\0\0\0 \0"
+  "\0\0\257\202\0\0\0\357\4\0\0\0\257\0\0\0 \0\0\0\20\0\0\0@\202\0\0\0o"
+  "\2\0\0\0 \0\0\0\20\222\0\0\0\0"};
+
+
diff --git a/libgda-ui/bullet.png b/libgda-ui/bullet.png
new file mode 100644
index 0000000..0ccbf5b
Binary files /dev/null and b/libgda-ui/bullet.png differ
diff --git a/libgda-ui/bulleth.h b/libgda-ui/bulleth.h
new file mode 100644
index 0000000..7178c14
--- /dev/null
+++ b/libgda-ui/bulleth.h
@@ -0,0 +1,31 @@
+/* GdkPixbuf RGBA C-Source image dump 1-byte-run-length-encoded */
+
+#ifdef __SUNPRO_C
+#pragma align 4 (bulleth_pixdata)
+#endif
+#ifdef __GNUC__
+static const guint8 bulleth_pixdata[] __attribute__ ((__aligned__ (4))) = 
+#else
+static const guint8 bulleth_pixdata[] = 
+#endif
+{ ""
+  /* Pixbuf magic (0x47646b50) */
+  "GdkP"
+  /* length: header (24) + pixel_data (136) */
+  "\0\0\0\240"
+  /* pixdata_type (0x2010002) */
+  "\2\1\0\2"
+  /* rowstride (24) */
+  "\0\0\0\30"
+  /* width (6) */
+  "\0\0\0\6"
+  /* height (9) */
+  "\0\0\0\11"
+  /* pixel_data: */
+  "\2\0\0\0\20\0\0\0 \202\0\0\0o\4\0\0\0@\0\0\0\20\0\0\0 \0\0\0\231\202"
+  "\0\0\0\225\4\0\0\0\231\0\0\0 \0\0\0o\0\0\0\225\202\0\0\0\40\1\0\0\0\225"
+  "\202\0\0\0o\1\0\0\0\225\202\0\0\0\40\4\0\0\0\225\0\0\0o\0\0\0 \0\0\0"
+  "\231\202\0\0\0\225\4\0\0\0\231\0\0\0 \0\0\0\20\0\0\0@\202\0\0\0o\2\0"
+  "\0\0 \0\0\0\20\222\0\0\0\0"};
+
+
diff --git a/libgda-ui/bulleth.png b/libgda-ui/bulleth.png
new file mode 100644
index 0000000..b38d119
Binary files /dev/null and b/libgda-ui/bulleth.png differ
diff --git a/libgda-ui/data-entries/plugins/Makefile.am b/libgda-ui/data-entries/plugins/Makefile.am
index 2c4c113..344553c 100644
--- a/libgda-ui/data-entries/plugins/Makefile.am
+++ b/libgda-ui/data-entries/plugins/Makefile.am
@@ -30,6 +30,7 @@ plugins_headers = \
 	gdaui-entry-cidr.h \
 	gdaui-entry-text.h \
 	gdaui-entry-pict.h \
+	gdaui-entry-rt.h \
 	$(gcrypt_headers)
 
 libgda_ui_plugins_la_SOURCES = \
@@ -45,6 +46,7 @@ libgda_ui_plugins_la_SOURCES = \
 	gdaui-entry-cidr.c \
 	gdaui-entry-text.c \
 	gdaui-entry-pict.c \
+	gdaui-entry-rt.c \
 	$(gcrypt_sources)
 
 libgda_ui_plugins_la_LDFLAGS = -export-dynamic -module -avoid-version $(NO_UNDEFINED)
diff --git a/libgda-ui/data-entries/plugins/gdaui-entry-rt.c b/libgda-ui/data-entries/plugins/gdaui-entry-rt.c
new file mode 100644
index 0000000..8a248b6
--- /dev/null
+++ b/libgda-ui/data-entries/plugins/gdaui-entry-rt.c
@@ -0,0 +1,304 @@
+/* gdaui-entry-rt.c
+ *
+ * Copyright (C) 2010 Vivien Malerba
+ *
+ * This Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include <string.h>
+#include "gdaui-entry-rt.h"
+#include <libgda-ui/gdaui-rt-editor.h>
+#include <libgda/gda-data-handler.h>
+#include <libgda/gda-blob-op.h>
+
+/* 
+ * Main static functions 
+ */
+static void gdaui_entry_rt_class_init (GdauiEntryRtClass * class);
+static void gdaui_entry_rt_init (GdauiEntryRt * srv);
+static void gdaui_entry_rt_dispose (GObject   * object);
+static void gdaui_entry_rt_finalize (GObject   * object);
+
+/* virtual functions */
+static GtkWidget *create_entry (GdauiEntryWrapper *mgwrap);
+static void       real_set_value (GdauiEntryWrapper *mgwrap, const GValue *value);
+static GValue    *real_get_value (GdauiEntryWrapper *mgwrap);
+static void       connect_signals(GdauiEntryWrapper *mgwrap, GCallback modify_cb, GCallback activate_cb);
+static gboolean   can_expand (GdauiEntryWrapper *mgwrap, gboolean horiz);
+static void       set_editable (GdauiEntryWrapper *mgwrap, gboolean editable);
+
+/* get a pointer to the parents to be able to call their destructor */
+static GObjectClass  *parent_class = NULL;
+
+/* private structure */
+struct _GdauiEntryRtPrivate
+{
+	GtkWidget     *view;
+};
+
+
+GType
+gdaui_entry_rt_get_type (void)
+{
+	static GType type = 0;
+
+	if (G_UNLIKELY (type == 0)) {
+		static const GTypeInfo info = {
+			sizeof (GdauiEntryRtClass),
+			(GBaseInitFunc) NULL,
+			(GBaseFinalizeFunc) NULL,
+			(GClassInitFunc) gdaui_entry_rt_class_init,
+			NULL,
+			NULL,
+			sizeof (GdauiEntryRt),
+			0,
+			(GInstanceInitFunc) gdaui_entry_rt_init,
+			0
+		};
+		
+		type = g_type_register_static (GDAUI_TYPE_ENTRY_WRAPPER, "GdauiEntryRt", &info, 0);
+	}
+	return type;
+}
+
+static void
+gdaui_entry_rt_class_init (GdauiEntryRtClass * class)
+{
+	GObjectClass   *object_class = G_OBJECT_CLASS (class);
+
+	parent_class = g_type_class_peek_parent (class);
+
+	object_class->dispose = gdaui_entry_rt_dispose;
+	object_class->finalize = gdaui_entry_rt_finalize;
+
+	GDAUI_ENTRY_WRAPPER_CLASS (class)->create_entry = create_entry;
+	GDAUI_ENTRY_WRAPPER_CLASS (class)->real_set_value = real_set_value;
+	GDAUI_ENTRY_WRAPPER_CLASS (class)->real_get_value = real_get_value;
+	GDAUI_ENTRY_WRAPPER_CLASS (class)->connect_signals = connect_signals;
+	GDAUI_ENTRY_WRAPPER_CLASS (class)->can_expand = can_expand;
+	GDAUI_ENTRY_WRAPPER_CLASS (class)->set_editable = set_editable;
+}
+
+static void
+gdaui_entry_rt_init (GdauiEntryRt * gdaui_entry_rt)
+{
+	gdaui_entry_rt->priv = g_new0 (GdauiEntryRtPrivate, 1);
+	gdaui_entry_rt->priv->view = NULL;
+}
+
+/**
+ * gdaui_entry_rt_new
+ * @dh: the data handler to be used by the new widget
+ * @type: the requested data type (compatible with @dh)
+ * @options: the options
+ *
+ * Creates a new widget which is mainly a GtkEntry
+ *
+ * Returns: the new widget
+ */
+GtkWidget *
+gdaui_entry_rt_new (GdaDataHandler *dh, GType type, const gchar *options)
+{
+	GObject *obj;
+
+	g_return_val_if_fail (dh && GDA_IS_DATA_HANDLER (dh), NULL);
+	g_return_val_if_fail (type != G_TYPE_INVALID, NULL);
+	g_return_val_if_fail (gda_data_handler_accepts_g_type (dh, type), NULL);
+
+	obj = g_object_new (GDAUI_TYPE_ENTRY_RT, "handler", dh, NULL);
+	gdaui_data_entry_set_value_type (GDAUI_DATA_ENTRY (obj), type);
+
+	return GTK_WIDGET (obj);
+}
+
+
+static void
+gdaui_entry_rt_dispose (GObject   * object)
+{
+	GdauiEntryRt *gdaui_entry_rt;
+
+	g_return_if_fail (object != NULL);
+	g_return_if_fail (GDAUI_IS_ENTRY_RT (object));
+
+	gdaui_entry_rt = GDAUI_ENTRY_RT (object);
+	if (gdaui_entry_rt->priv) {
+	}
+
+	/* parent class */
+	parent_class->dispose (object);
+}
+
+static void
+gdaui_entry_rt_finalize (GObject   * object)
+{
+	GdauiEntryRt *gdaui_entry_rt;
+
+	g_return_if_fail (object != NULL);
+	g_return_if_fail (GDAUI_IS_ENTRY_RT (object));
+
+	gdaui_entry_rt = GDAUI_ENTRY_RT (object);
+	if (gdaui_entry_rt->priv) {
+		g_free (gdaui_entry_rt->priv);
+		gdaui_entry_rt->priv = NULL;
+	}
+
+	/* parent class */
+	parent_class->finalize (object);
+}
+
+static GtkWidget *
+create_entry (GdauiEntryWrapper *mgwrap)
+{
+	GdauiEntryRt *mgtxt;
+
+	g_return_val_if_fail (mgwrap && GDAUI_IS_ENTRY_RT (mgwrap), NULL);
+	mgtxt = GDAUI_ENTRY_RT (mgwrap);
+	g_return_val_if_fail (mgtxt->priv, NULL);
+
+	mgtxt->priv->view = gdaui_rt_editor_new ();
+	
+	return mgtxt->priv->view;
+}
+
+static void
+real_set_value (GdauiEntryWrapper *mgwrap, const GValue *value)
+{
+	GdauiEntryRt *mgtxt;
+
+	g_return_if_fail (mgwrap && GDAUI_IS_ENTRY_RT (mgwrap));
+	mgtxt = GDAUI_ENTRY_RT (mgwrap);
+	g_return_if_fail (mgtxt->priv);
+
+	gdaui_rt_editor_set_contents (GDAUI_RT_EDITOR (mgtxt->priv->view), "", -1);
+	if (value) {
+		if (! gda_value_is_null ((GValue *) value)) {
+			GdaDataHandler *dh;		
+			gchar *str;
+			gboolean done = FALSE;
+
+			if (G_VALUE_TYPE (value) == GDA_TYPE_BLOB) {
+				const GdaBlob *blob;
+				GdaBinary *bin;
+				blob = gda_value_get_blob (value);
+				bin = (GdaBinary *) blob;
+				if (blob->op &&
+				    (bin->binary_length != gda_blob_op_get_length (blob->op)))
+                                        gda_blob_op_read_all (blob->op, (GdaBlob*) blob);
+				if (g_utf8_validate ((gchar*) bin->data, bin->binary_length, NULL)) {
+					gdaui_rt_editor_set_contents (GDAUI_RT_EDITOR (mgtxt->priv->view),
+								      (gchar*) bin->data,
+								      bin->binary_length);
+					done = TRUE;
+				}
+			}
+			else  if (G_VALUE_TYPE (value) == GDA_TYPE_BINARY) {
+				const GdaBinary *bin;
+				bin = gda_value_get_binary (value);
+				if (g_utf8_validate ((gchar*) bin->data, bin->binary_length, NULL)) {
+					gdaui_rt_editor_set_contents (GDAUI_RT_EDITOR (mgtxt->priv->view),
+								      (gchar*) bin->data, 
+								      bin->binary_length);
+					done = TRUE;
+				}
+			}
+
+			if (!done) {
+				dh = gdaui_data_entry_get_handler (GDAUI_DATA_ENTRY (mgwrap));
+				str = gda_data_handler_get_str_from_value (dh, value);
+				if (str) {
+					gdaui_rt_editor_set_contents (GDAUI_RT_EDITOR (mgtxt->priv->view),
+								      str, -1);
+					g_free (str);
+				}
+			}
+		}
+	}
+}
+
+static GValue *
+real_get_value (GdauiEntryWrapper *mgwrap)
+{
+	GValue *value;
+	GdauiEntryRt *mgtxt;
+	GdaDataHandler *dh;
+	gchar *str;
+
+	g_return_val_if_fail (mgwrap && GDAUI_IS_ENTRY_RT (mgwrap), NULL);
+	mgtxt = GDAUI_ENTRY_RT (mgwrap);
+	g_return_val_if_fail (mgtxt->priv, NULL);
+
+	dh = gdaui_data_entry_get_handler (GDAUI_DATA_ENTRY (mgwrap));
+	str = gdaui_rt_editor_get_contents (GDAUI_RT_EDITOR (mgtxt->priv->view));
+	value = gda_data_handler_get_value_from_str (dh, str, 
+						     gdaui_data_entry_get_value_type (GDAUI_DATA_ENTRY (mgwrap)));
+	g_free (str);
+	if (!value) {
+		/* in case the gda_data_handler_get_value_from_sql() returned an error because
+		   the contents of the GtkEntry cannot be interpreted as a GValue */
+		value = gda_value_new_null ();
+	}
+
+	return value;
+}
+
+typedef void (*Callback2) (gpointer, gpointer);
+static gboolean
+focus_out_cb (GtkWidget *widget, GdkEventFocus *event, GdauiEntryRt *mgtxt)
+{
+	GCallback activate_cb;
+	activate_cb = g_object_get_data (G_OBJECT (widget), "_activate_cb");
+	g_assert (activate_cb);
+	((Callback2)activate_cb) (widget, mgtxt);
+
+	return gtk_widget_event (GTK_WIDGET (mgtxt), (GdkEvent*) event);
+}
+
+static void
+connect_signals(GdauiEntryWrapper *mgwrap, GCallback modify_cb, GCallback activate_cb)
+{
+	GdauiEntryRt *mgtxt;
+
+	g_return_if_fail (mgwrap && GDAUI_IS_ENTRY_RT (mgwrap));
+	mgtxt = GDAUI_ENTRY_RT (mgwrap);
+	g_return_if_fail (mgtxt->priv);
+
+	g_object_set_data (G_OBJECT (mgtxt->priv->view), "_activate_cb", activate_cb);
+	g_signal_connect (G_OBJECT (GDAUI_RT_EDITOR (mgtxt->priv->view)), "changed",
+			  modify_cb, mgwrap);
+	g_signal_connect (G_OBJECT (mgtxt->priv->view), "focus-out-event",
+			  G_CALLBACK (focus_out_cb), mgtxt);
+	/* FIXME: how does the user "activates" the GtkRtView widget ? */
+}
+
+static gboolean
+can_expand (G_GNUC_UNUSED GdauiEntryWrapper *mgwrap, gboolean horiz)
+{
+	if (horiz)
+		return FALSE;
+	else
+		return TRUE;
+}
+
+static void
+set_editable (GdauiEntryWrapper *mgwrap, gboolean editable)
+{
+	GdauiEntryRt *mgtxt;
+
+	g_return_if_fail (mgwrap && GDAUI_IS_ENTRY_RT (mgwrap));
+	mgtxt = GDAUI_ENTRY_RT (mgwrap);
+
+	gdaui_rt_editor_set_editable (GDAUI_RT_EDITOR (mgtxt->priv->view), editable);
+}
diff --git a/libgda-ui/data-entries/plugins/gdaui-entry-rt.h b/libgda-ui/data-entries/plugins/gdaui-entry-rt.h
new file mode 100644
index 0000000..afef532
--- /dev/null
+++ b/libgda-ui/data-entries/plugins/gdaui-entry-rt.h
@@ -0,0 +1,59 @@
+/* gdaui-entry-rt.h
+ *
+ * Copyright (C) 2010 Vivien Malerba
+ *
+ * This Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+
+#ifndef __GDAUI_ENTRY_RT_H_
+#define __GDAUI_ENTRY_RT_H_
+
+#include <libgda-ui/data-entries/gdaui-entry-wrapper.h>
+
+G_BEGIN_DECLS
+
+#define GDAUI_TYPE_ENTRY_RT          (gdaui_entry_rt_get_type())
+#define GDAUI_ENTRY_RT(obj)          G_TYPE_CHECK_INSTANCE_CAST (obj, gdaui_entry_rt_get_type(), GdauiEntryRt)
+#define GDAUI_ENTRY_RT_CLASS(klass)  G_TYPE_CHECK_CLASS_CAST (klass, gdaui_entry_rt_get_type (), GdauiEntryRtClass)
+#define GDAUI_IS_ENTRY_RT(obj)       G_TYPE_CHECK_INSTANCE_TYPE (obj, gdaui_entry_rt_get_type ())
+
+
+typedef struct _GdauiEntryRt GdauiEntryRt;
+typedef struct _GdauiEntryRtClass GdauiEntryRtClass;
+typedef struct _GdauiEntryRtPrivate GdauiEntryRtPrivate;
+
+
+/* struct for the object's data */
+struct _GdauiEntryRt
+{
+	GdauiEntryWrapper            object;
+	GdauiEntryRtPrivate         *priv;
+};
+
+/* struct for the object's class */
+struct _GdauiEntryRtClass
+{
+	GdauiEntryWrapperClass       parent_class;
+};
+
+GType        gdaui_entry_rt_get_type        (void) G_GNUC_CONST;
+GtkWidget   *gdaui_entry_rt_new             (GdaDataHandler *dh, GType type, const gchar *options);
+
+
+G_END_DECLS
+
+#endif
diff --git a/libgda-ui/data-entries/plugins/libmain.c b/libgda-ui/data-entries/plugins/libmain.c
index d622c0a..ea3b7af 100644
--- a/libgda-ui/data-entries/plugins/libmain.c
+++ b/libgda-ui/data-entries/plugins/libmain.c
@@ -1,5 +1,5 @@
 /* libmain.c
- * Copyright (C) 2006 - 2009 The GNOME Foundation
+ * Copyright (C) 2006 - 2010 The GNOME Foundation
  *
  * AUTHORS:
  *         Vivien Malerba <malerba gdaui org>
@@ -30,6 +30,7 @@
 #include "gdaui-entry-cidr.h"
 #include "gdaui-entry-text.h"
 #include "gdaui-entry-pict.h"
+#include "gdaui-entry-rt.h"
 #include "gdaui-data-cell-renderer-pict.h"
 
 #ifdef HAVE_LIBGCRYPT
@@ -52,6 +53,7 @@
 static GdauiDataEntry *plugin_entry_filesel_create_func (GdaDataHandler *handler, GType type, const gchar *options);
 static GdauiDataEntry *plugin_entry_cidr_create_func (GdaDataHandler *handler, GType type, const gchar *options);
 static GdauiDataEntry *plugin_entry_text_create_func (GdaDataHandler *handler, GType type, const gchar *options);
+static GdauiDataEntry *plugin_entry_rt_create_func (GdaDataHandler *handler, GType type, const gchar *options);
 static GdauiDataEntry *plugin_entry_pict_create_func (GdaDataHandler *handler, GType type, const gchar *options);
 static GtkCellRenderer  *plugin_cell_renderer_pict_create_func (GdaDataHandler *handler, GType type, const gchar *options);
 
@@ -213,6 +215,21 @@ plugin_init (GError **error)
 	g_free (file);
 #endif
 
+	/* TEXT */
+	plugin = g_new0 (GdauiPlugin, 1);
+	plugin->plugin_name = "rtext";
+	plugin->plugin_descr = "Rich text editor entry";
+	plugin->plugin_file = NULL; /* always leave NULL */
+	plugin->nb_g_types = 3;
+	plugin->valid_g_types = g_new (GType, plugin->nb_g_types);
+	plugin->valid_g_types [0] = G_TYPE_STRING;
+	plugin->valid_g_types [1] = GDA_TYPE_BLOB;
+	plugin->valid_g_types [2] = GDA_TYPE_BINARY;
+	plugin->options_xml_spec = NULL;
+	plugin->entry_create_func = plugin_entry_rt_create_func;
+	plugin->cell_create_func = NULL;
+	retlist = g_slist_append (retlist, plugin);
+
 	/* Picture - binary */
 	plugin = g_new0 (GdauiPlugin, 1);
 	plugin->plugin_name = "picture";
@@ -284,6 +301,12 @@ plugin_entry_text_create_func (GdaDataHandler *handler, GType type, const gchar
 }
 
 static GdauiDataEntry *
+plugin_entry_rt_create_func (GdaDataHandler *handler, GType type, const gchar *options)
+{
+	return (GdauiDataEntry *) gdaui_entry_rt_new (handler, type, options);
+}
+
+static GdauiDataEntry *
 plugin_entry_pict_create_func (GdaDataHandler *handler, GType type, const gchar *options)
 {
 	return (GdauiDataEntry *) gdaui_entry_pict_new (handler, type, options);
diff --git a/libgda-ui/gdaui-rt-editor.c b/libgda-ui/gdaui-rt-editor.c
new file mode 100644
index 0000000..d88450b
--- /dev/null
+++ b/libgda-ui/gdaui-rt-editor.c
@@ -0,0 +1,1904 @@
+/* gdaui-rt-editor.c
+ *
+ * Copyright (C) 2010 Vivien Malerba <malerba gnome-db org>
+ *
+ * This Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include <string.h>
+#include "gdaui-rt-editor.h"
+#include <glib/gi18n-lib.h>
+#include <gdk-pixbuf/gdk-pixdata.h>
+#include "bullet.h"
+#include "bulleth.h"
+
+static void gdaui_rt_editor_class_init (GdauiRtEditorClass *klass);
+static void gdaui_rt_editor_init (GdauiRtEditor *wid);
+static void gdaui_rt_editor_dispose (GObject *object);
+
+static void gdaui_rt_editor_set_property (GObject *object,
+					  guint param_id,
+					  const GValue *value,
+					  GParamSpec *pspec);
+static void gdaui_rt_editor_get_property (GObject *object,
+					  guint param_id,
+					  GValue *value,
+					  GParamSpec *pspec);
+static void gdaui_rt_editor_show_all (GtkWidget *widget);
+
+static void _gdaui_rt_editor_set_show_markup (GdauiRtEditor *editor, gboolean show_markup);
+
+/* tag types */
+enum {
+	TEXT_TAG_ITALIC,
+	TEXT_TAG_BOLD,
+	TEXT_TAG_TT,
+	TEXT_TAG_VERBATIM,
+	TEXT_TAG_UNDERLINE,
+	TEXT_TAG_STRIKE,
+	TEXT_TAG_TITLE1,
+	TEXT_TAG_TITLE2,
+	TEXT_TAG_LIST1,
+	TEXT_TAG_LIST2,
+	TEXT_TAG_BULLET,
+
+	TEXT_TAG_LAST
+};
+
+typedef struct {
+	GtkTextTag *tag;
+	gchar      *action_name;
+} TagData;
+
+struct _GdauiRtEditorPriv
+{
+	GtkTextView    *textview;
+	GtkTextBuffer  *textbuffer;
+	GtkWidget      *toolbar;
+	GtkActionGroup *actions_group;
+	GtkUIManager   *uimanager;
+	TagData         tags[TEXT_TAG_LAST];
+	gboolean        selection_changing;
+	gboolean        show_markup;
+	gchar          *saved_for_help;
+	gboolean        enable_changed_signal;
+	gboolean        no_background;
+	gint            insert_offset;
+};
+
+/* get a pointer to the parents to be able to call their destructor */
+static GObjectClass *parent_class = NULL;
+static gchar *help_str=N_("\"\"\"= Title level 1 =\n"
+			  "== Title level 2 ==\n"
+			  "\"\"\"= Title level 1 =\n"
+			  "== Title level 2 ==\n\n"
+			  "\"\"\""
+			  "For beautifiers we have **bold**\n"
+			  "and //italic//.\n"
+			  "There is also __underline__, --strike--\n"
+			  "and ``monospaced``.\n"
+			  "\"\"\"\n"
+			  "For beautifiers we have **bold**\n"
+			  "and //italic//.\n"
+			  "There is also __underline__, --strike--\n"
+			  "and ``monospaced``.\n\n"
+			  "\"\"\""
+			  "- This is a list of items\n"
+			  "- Just use hyphens\n"
+			  " - And starting space for indenting\n"
+			  "\"\"\"- This is a list of items\n"
+			  "- Just use hyphens\n"
+			  " - And starting space for indenting\n"
+			  "\nRaw areas are enclosed inside three doublequotes and no markup is interpreted");
+
+/* signals */
+enum {
+	CHANGED,
+	LAST_SIGNAL
+};
+
+static gint gdaui_rt_editor_signals[LAST_SIGNAL] = { 0 };
+
+/* properties */
+enum {
+	PROP_0,
+	PROP_NO_BACKGROUND,
+	PROP_SHOW_MARKUP,
+	PROP_TEXTBUFFER
+};
+
+/* global pixbufs */
+static GdkPixbuf *bullet_pix = NULL;
+static GdkPixbuf *bulleth_pix = NULL;
+
+static gint spaces_since_start_of_line (GtkTextIter *iter);
+static gchar *real_gdaui_rt_editor_get_contents (GdauiRtEditor *editor);
+
+static void mark_set_cb (GtkTextBuffer *textbuffer, GtkTextIter *location,
+			 GtkTextMark *mark, GdauiRtEditor *rte);
+static void delete_range_cb (GtkTextBuffer *textbuffer, GtkTextIter *start, GtkTextIter *end, GdauiRtEditor *rte);
+static void insert_text_cb (GtkTextBuffer *textbuffer, GtkTextIter *location, gchar *text, gint len, GdauiRtEditor *rte);
+static void insert_text_after_cb (GtkTextBuffer *textbuffer, GtkTextIter *location, gchar *text, gint len, GdauiRtEditor *rte);
+static void text_buffer_changed_cb (GtkTextBuffer *textbuffer, GdauiRtEditor *rte);
+static void populate_popup_cb (GtkTextView *entry, GtkMenu *menu, GdauiRtEditor *rte);
+
+static void show_hide_toolbar (GdauiRtEditor *editor);
+
+static gchar *add_newlines_to_base64 (gchar *base64);
+static gchar *remove_newlines_from_base64 (gchar *base64);
+
+static void italic_cb (GtkToggleAction *action, GdauiRtEditor *rte);
+static void strike_cb (GtkToggleAction *action, GdauiRtEditor *rte);
+static void underline_cb (GtkToggleAction *action, GdauiRtEditor *rte);
+static void bold_cb (GtkToggleAction *action, GdauiRtEditor *rte);
+static void reset_all_cb (GtkAction *action, GdauiRtEditor *rte);
+static void add_image_cb (GtkAction *action, GdauiRtEditor *rte);
+static void help_cb (GtkToggleAction *action, GdauiRtEditor *rte);
+
+static const GtkToggleActionEntry ui_toggle_actions [] =
+{
+        { "ActionBold", GTK_STOCK_BOLD, N_("_Bold"), NULL, N_("Bold text"), G_CALLBACK (bold_cb), FALSE},
+        { "ActionItalic", GTK_STOCK_ITALIC, N_("_Italic"), NULL, N_("Italic text"), G_CALLBACK (italic_cb), FALSE},
+        { "ActionUnderline", GTK_STOCK_UNDERLINE, N_("_Underline"), NULL, N_("Underline text"), G_CALLBACK (underline_cb), FALSE},
+        { "ActionStrike", GTK_STOCK_STRIKETHROUGH, N_("_Strike through"), NULL, N_("Strike through text"), G_CALLBACK (strike_cb), FALSE},
+        { "ActionHelp", GTK_STOCK_HELP, N_("_Syntax help"), NULL, N_("Show syntax help"), G_CALLBACK (help_cb), FALSE}
+};
+
+/* STOCK_SELECT_COLOR */
+static const GtkActionEntry ui_actions[] = {
+        { "ActionAddImage", "insert-image", N_("_Add image"), NULL, N_("Insert image"), G_CALLBACK (add_image_cb)},
+        { "ActionReset", GTK_STOCK_CLEAR, N_("_Reset"), NULL, N_("Reset to normal text"), G_CALLBACK (reset_all_cb)},
+};
+
+static const gchar *ui_actions_info =
+        "<ui>"
+        "  <toolbar name='ToolBar'>"
+        "    <toolitem action='ActionBold'/>"
+        "    <toolitem action='ActionItalic'/>"
+        "    <toolitem action='ActionUnderline'/>"
+        "    <toolitem action='ActionStrike'/>"
+        "    <toolitem action='ActionAddImage'/>"
+        "    <toolitem action='ActionReset'/>"
+        "    <toolitem action='ActionHelp'/>"
+        "  </toolbar>"
+        "</ui>";
+
+GType
+gdaui_rt_editor_get_type (void)
+{
+	static GType type = 0;
+
+	if (G_UNLIKELY (type == 0)) {
+		static const GTypeInfo info = {
+			sizeof (GdauiRtEditorClass),
+			(GBaseInitFunc) NULL,
+			(GBaseFinalizeFunc) NULL,
+			(GClassInitFunc) gdaui_rt_editor_class_init,
+			NULL,
+			NULL,
+			sizeof (GdauiRtEditor),
+			0,
+			(GInstanceInitFunc) gdaui_rt_editor_init,
+			0
+		};
+
+		type = g_type_register_static (GTK_TYPE_VBOX, "GdauiRtEditor", &info, 0);
+	}
+
+	return type;
+}
+
+static void
+gdaui_rt_editor_class_init (GdauiRtEditorClass *klass)
+{
+	GObjectClass  *object_class = G_OBJECT_CLASS (klass);
+	parent_class = g_type_class_peek_parent (klass);
+
+	object_class->dispose = gdaui_rt_editor_dispose;
+
+	GTK_WIDGET_CLASS (klass)->show_all = gdaui_rt_editor_show_all;
+
+	/* signals */
+	gdaui_rt_editor_signals[CHANGED] =
+                g_signal_new ("changed",
+                              G_TYPE_FROM_CLASS (object_class),
+                              G_SIGNAL_RUN_LAST,
+                              G_STRUCT_OFFSET (GdauiRtEditorClass, changed),
+                              NULL, NULL,
+                              g_cclosure_marshal_VOID__VOID,
+                              G_TYPE_NONE, 0);
+
+	/* Properties */
+        object_class->set_property = gdaui_rt_editor_set_property;
+        object_class->get_property = gdaui_rt_editor_get_property;
+	/**
+	 * GdauiRtEditor:no-background:
+	 *
+	 * If set to %TRUE, then the default text background is removed
+	 * and thus the textbackground is the default widget's background.
+	 *
+	 * This property has to be set before the widget is realized, and is taken into account only
+	 * if the widget is not editable (when it's realized).
+	 **/
+	g_object_class_install_property (object_class, PROP_NO_BACKGROUND,
+                                         g_param_spec_boolean ("no-background",
+                                                               _("Don't display a specific background for the text"),
+                                                               NULL, FALSE,
+                                                               G_PARAM_READABLE | G_PARAM_WRITABLE));
+	/**
+	 * GdauiRtEditor:show-markup:
+	 *
+	 * Instead of showing the formatted text, display the raw text (in the txt2tags syntax)
+	 **/
+	g_object_class_install_property (object_class, PROP_SHOW_MARKUP,
+					 g_param_spec_boolean ("show-markup",
+                                                               _("Display raw markup text instead of formatted text"),
+                                                               NULL, FALSE,
+                                                               G_PARAM_READABLE | G_PARAM_WRITABLE));
+
+	/**
+	 * GdauiRtEditor:buffer:
+	 *
+	 * Get access to the actual #GtkTextBuffer used. Do not modify it!
+	 **/
+	g_object_class_install_property (object_class, PROP_TEXTBUFFER,
+					 g_param_spec_object ("buffer",
+							      _("The buffer which is displayed"),
+							      NULL, GTK_TYPE_TEXT_BUFFER,
+							      G_PARAM_READABLE));
+}
+
+static void
+text_view_realized_cb (GtkWidget *tv, GdauiRtEditor *rte)
+{
+	GdkWindow *win;
+	GtkStyle *style;
+	if (rte->priv->no_background && ! gtk_text_view_get_editable (GTK_TEXT_VIEW (tv))) {
+		win = gtk_text_view_get_window (GTK_TEXT_VIEW (tv), GTK_TEXT_WINDOW_TEXT);
+		style = gtk_widget_get_style (tv);
+		gdk_window_set_background (win, &(style->bg [GTK_STATE_NORMAL]));
+	}
+}
+
+static void
+gdaui_rt_editor_init (GdauiRtEditor *rte)
+{
+	GtkWidget *sw, *textview, *toolbar;
+
+	sw = gtk_scrolled_window_new (NULL, NULL);
+	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
+					GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+	gtk_box_pack_end (GTK_BOX (rte), sw, TRUE, TRUE, 0);
+
+	textview = gtk_text_view_new ();
+	gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (textview), GTK_WRAP_WORD);
+	gtk_container_add (GTK_CONTAINER (sw), textview);
+	g_signal_connect (textview, "realize",
+			  G_CALLBACK (text_view_realized_cb), rte);
+
+	gtk_widget_show_all (sw);
+
+	rte->priv = g_new0 (GdauiRtEditorPriv, 1);
+	rte->priv->saved_for_help = NULL;
+	rte->priv->enable_changed_signal = TRUE;
+	rte->priv->no_background = FALSE;
+	rte->priv->insert_offset = -1;
+	rte->priv->textview = GTK_TEXT_VIEW (textview);
+	rte->priv->textbuffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (textview));
+	g_signal_connect (rte->priv->textbuffer, "changed",
+			  G_CALLBACK (text_buffer_changed_cb), rte);
+	g_signal_connect (rte->priv->textbuffer, "mark-set",
+			  G_CALLBACK (mark_set_cb), rte);
+	g_signal_connect (rte->priv->textbuffer, "insert-text",
+			  G_CALLBACK (insert_text_cb), rte);
+	g_signal_connect_after (rte->priv->textbuffer, "insert-text",
+				G_CALLBACK (insert_text_after_cb), rte);
+	g_signal_connect (rte->priv->textbuffer, "delete-range",
+			  G_CALLBACK (delete_range_cb), rte);
+	g_signal_connect (rte->priv->textview, "populate-popup",
+			  G_CALLBACK (populate_popup_cb), rte);
+
+	/* tags. REM: leave the LIST* and BULLET tags defined 1st as they will be with less priority
+	 * and it affects the result returned by gtk_text_iter_get_tags() */
+	rte->priv->show_markup = FALSE;
+	memset (rte->priv->tags, 0, sizeof (rte->priv->tags));
+
+	rte->priv->tags[TEXT_TAG_LIST1].tag = gtk_text_buffer_create_tag (rte->priv->textbuffer, NULL,
+									  "left_margin", 15,
+									  /*"background", "#cbbcbc",*/
+									  NULL);
+	rte->priv->tags[TEXT_TAG_LIST2].tag = gtk_text_buffer_create_tag (rte->priv->textbuffer, NULL,
+									  "left_margin", 30,
+									  /*"background", "#dcbcbc",*/
+									  NULL);
+	rte->priv->tags[TEXT_TAG_BULLET].tag = gtk_text_buffer_create_tag (rte->priv->textbuffer, NULL,
+									   "indent", -10,
+									   /*"background", "#cbbcbc",*/
+									   NULL);
+	rte->priv->tags[TEXT_TAG_ITALIC].tag = gtk_text_buffer_create_tag (rte->priv->textbuffer, NULL,
+									   "style", PANGO_STYLE_ITALIC, NULL);
+	rte->priv->tags[TEXT_TAG_ITALIC].action_name = "/ToolBar/ActionItalic";
+
+	rte->priv->tags[TEXT_TAG_BOLD].tag = gtk_text_buffer_create_tag (rte->priv->textbuffer, NULL,
+									 "weight", PANGO_WEIGHT_BOLD, NULL);
+	rte->priv->tags[TEXT_TAG_BOLD].action_name = "/ToolBar/ActionBold";
+
+	rte->priv->tags[TEXT_TAG_TT].tag = gtk_text_buffer_create_tag (rte->priv->textbuffer, NULL,
+								       "family", "Monospace", NULL);
+	rte->priv->tags[TEXT_TAG_VERBATIM].tag = gtk_text_buffer_create_tag (rte->priv->textbuffer, NULL,
+									     "background", "#e5e2e2",
+									     NULL);
+	
+	rte->priv->tags[TEXT_TAG_UNDERLINE].tag = gtk_text_buffer_create_tag (rte->priv->textbuffer, NULL,
+									      "underline", PANGO_UNDERLINE_SINGLE, NULL);
+	rte->priv->tags[TEXT_TAG_UNDERLINE].action_name = "/ToolBar/ActionUnderline";
+	
+	rte->priv->tags[TEXT_TAG_STRIKE].tag = gtk_text_buffer_create_tag (rte->priv->textbuffer, NULL,
+									   "strikethrough", TRUE, NULL);
+	rte->priv->tags[TEXT_TAG_STRIKE].action_name = "/ToolBar/ActionStrike";
+	
+	rte->priv->tags[TEXT_TAG_TITLE1].tag = gtk_text_buffer_create_tag (rte->priv->textbuffer, NULL,
+									   "size", 15 * PANGO_SCALE,
+									   "weight", PANGO_WEIGHT_SEMIBOLD,
+									   NULL);
+	rte->priv->tags[TEXT_TAG_TITLE2].tag = gtk_text_buffer_create_tag (rte->priv->textbuffer, NULL,
+									   "size", 13 * PANGO_SCALE,
+									   "weight", PANGO_WEIGHT_SEMIBOLD,
+									   NULL);
+
+	/* action group */
+	rte->priv->actions_group = gtk_action_group_new ("Actions");
+	gtk_action_group_add_toggle_actions (rte->priv->actions_group, ui_toggle_actions,
+					     G_N_ELEMENTS (ui_toggle_actions), rte);
+        gtk_action_group_add_actions (rte->priv->actions_group, ui_actions, G_N_ELEMENTS (ui_actions),
+				      rte);
+
+	/* ui manager */
+	rte->priv->uimanager = gtk_ui_manager_new ();
+        gtk_ui_manager_insert_action_group (rte->priv->uimanager, rte->priv->actions_group, 0);
+        gtk_ui_manager_add_ui_from_string (rte->priv->uimanager, ui_actions_info, -1, NULL);
+
+	/* toolbar */
+	toolbar = gtk_ui_manager_get_widget (rte->priv->uimanager, "/ToolBar");
+	gtk_toolbar_set_icon_size (GTK_TOOLBAR (toolbar), GTK_ICON_SIZE_MENU);
+	rte->priv->toolbar = toolbar;
+	gtk_box_pack_end (GTK_BOX (rte), toolbar, FALSE, FALSE, 0);
+	gtk_widget_show (toolbar);
+}
+
+/**
+ * gdaui_rt_editor_new:
+ *
+ * Creates a new #GdauiRtEditor widget
+ *
+ * Returns: (transfer full): the new widget
+ *
+ * Since: 4.2.2
+ */
+GtkWidget *
+gdaui_rt_editor_new ()
+{
+	GtkWidget *rte;
+
+	rte = (GtkWidget *) g_object_new (GDAUI_TYPE_RT_EDITOR, NULL);
+
+	return rte;
+}
+
+static void
+gdaui_rt_editor_dispose (GObject *object)
+{
+	GdauiRtEditor *rte;
+
+	g_return_if_fail (GDAUI_IS_RT_EDITOR (object));
+	rte = GDAUI_RT_EDITOR (object);
+
+	if (rte->priv) {
+		if (rte->priv->actions_group) {
+			g_object_unref (G_OBJECT (rte->priv->actions_group));
+			rte->priv->actions_group = NULL;
+		}
+
+		if (rte->priv->uimanager)
+			g_object_unref (rte->priv->uimanager);
+
+		g_free (rte->priv->saved_for_help);
+		/* NB: GtkTextTags are owned by the GtkTextBuffer's text tags table */
+
+		/* the private area itself */
+		g_free (rte->priv);
+		rte->priv = NULL;
+	}
+
+	/* for the parent class */
+	parent_class->dispose (object);
+}
+
+static void
+gdaui_rt_editor_show_all (GtkWidget *widget)
+{
+	GdauiRtEditor *editor;
+	editor = GDAUI_RT_EDITOR (widget);
+	GTK_WIDGET_CLASS (parent_class)->show_all (widget);
+	show_hide_toolbar (editor);
+}
+
+static void
+gdaui_rt_editor_set_property (GObject *object,
+			      guint param_id,
+			      const GValue *value,
+			      GParamSpec *pspec)
+{
+	GdauiRtEditor *editor;
+
+        editor = GDAUI_RT_EDITOR (object);
+        if (editor->priv) {
+                switch (param_id) {
+		case PROP_NO_BACKGROUND:
+			editor->priv->no_background = g_value_get_boolean (value);
+			break;
+		case PROP_SHOW_MARKUP:
+			_gdaui_rt_editor_set_show_markup (editor, g_value_get_boolean (value));
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+			break;
+                }
+        }
+}
+
+static void
+gdaui_rt_editor_get_property (GObject *object,
+			     guint param_id,
+			     GValue *value,
+			     GParamSpec *pspec)
+{
+	GdauiRtEditor *editor;
+
+        editor = GDAUI_RT_EDITOR (object);
+        if (editor->priv) {
+                switch (param_id) {
+		case PROP_NO_BACKGROUND:
+			g_value_set_boolean (value, editor->priv->no_background);
+			break;
+		case PROP_SHOW_MARKUP:
+			g_value_set_boolean (value, editor->priv->show_markup);
+			break;
+		case PROP_TEXTBUFFER:
+			g_value_set_object (value, editor->priv->textbuffer);
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+			break;
+                }
+        }
+}
+
+/* tags management */
+static void
+apply_tag (GdauiRtEditor *rte, gboolean reverse, GtkTextTag *tag)
+{
+	GtkTextIter start;
+	GtkTextIter end;
+
+	g_return_if_fail (rte->priv->textbuffer);
+
+	if (rte->priv->selection_changing)
+		return;
+
+	if (gtk_text_buffer_get_selection_bounds (rte->priv->textbuffer, &start, &end)) {
+		if (tag) {
+			if (reverse)
+				gtk_text_buffer_remove_tag (rte->priv->textbuffer, tag, &start, &end);
+			else {
+				/* don't apply tag if there is a LIST tag */
+				gboolean doapply = TRUE;
+				GtkTextIter iter;
+				for (iter = start; gtk_text_iter_compare (&iter, &end) < 0; ) {
+					if (gtk_text_iter_has_tag (&iter, rte->priv->tags[TEXT_TAG_BULLET].tag) ||
+					    gtk_text_iter_has_tag (&iter, rte->priv->tags[TEXT_TAG_LIST1].tag) ||
+					    gtk_text_iter_has_tag (&iter, rte->priv->tags[TEXT_TAG_LIST2].tag)) {
+						doapply = FALSE;
+						break;
+					}
+					if (! gtk_text_iter_forward_char (&iter))
+						break;
+				}
+				if (doapply)
+					gtk_text_buffer_apply_tag (rte->priv->textbuffer, tag, &start, &end);
+			}
+		}
+		else {
+			GtkTextIter iter;
+			for (iter = start; gtk_text_iter_compare (&iter, &end) < 0; ) {
+			
+				GSList *tags, *list;
+				tags = gtk_text_iter_get_tags (&iter);
+				if (tags) {
+					for (list = tags; list; list = list->next) {
+						GtkTextTag *tag = (GtkTextTag *) list->data;
+						if ((tag != rte->priv->tags[TEXT_TAG_BULLET].tag) &&
+						    (tag != rte->priv->tags[TEXT_TAG_LIST1].tag) &&
+						    (tag != rte->priv->tags[TEXT_TAG_LIST2].tag))
+							gtk_text_buffer_remove_tag (rte->priv->textbuffer,
+										    tag, &start, &end);
+					}
+					g_slist_free (tags);
+				}
+				if (! gtk_text_iter_forward_char (&iter))
+					break;
+			}
+		}
+	}
+}
+
+static void
+help_cb (GtkToggleAction *action, GdauiRtEditor *rte)
+{
+	if (gtk_toggle_action_get_active (action)) {
+		rte->priv->enable_changed_signal = FALSE;
+		g_free (rte->priv->saved_for_help);
+		rte->priv->saved_for_help = gdaui_rt_editor_get_contents (rte);
+		gdaui_rt_editor_set_contents (rte, help_str, -1);
+	}
+	else {
+		gdaui_rt_editor_set_contents (rte, rte->priv->saved_for_help, -1);
+		rte->priv->enable_changed_signal = TRUE;
+		g_free (rte->priv->saved_for_help);
+		rte->priv->saved_for_help = NULL;
+	}
+}
+
+static void
+italic_cb (GtkToggleAction *action, GdauiRtEditor *rte)
+{
+	apply_tag (rte, gtk_toggle_action_get_active (action) ? FALSE : TRUE,
+		   rte->priv->tags [TEXT_TAG_ITALIC].tag);
+}
+
+static void
+bold_cb (GtkToggleAction *action, GdauiRtEditor *rte)
+{
+	apply_tag (rte, gtk_toggle_action_get_active (action) ? FALSE : TRUE,
+		   rte->priv->tags [TEXT_TAG_BOLD].tag);
+}
+
+static void
+strike_cb (GtkToggleAction *action, GdauiRtEditor *rte)
+{
+	apply_tag (rte, gtk_toggle_action_get_active (action) ? FALSE : TRUE,
+		   rte->priv->tags [TEXT_TAG_STRIKE].tag);
+}
+
+static void
+underline_cb (GtkToggleAction *action, GdauiRtEditor *rte)
+{
+	apply_tag (rte, gtk_toggle_action_get_active (action) ? FALSE : TRUE,
+		   rte->priv->tags [TEXT_TAG_UNDERLINE].tag);
+}
+
+static void
+reset_all_cb (GtkAction *action, GdauiRtEditor *rte)
+{
+	apply_tag (rte, FALSE, NULL);
+}
+
+static void
+add_image_cb (GtkAction *action, GdauiRtEditor *rte)
+{
+	GtkWidget *dlg;
+        GtkFileFilter *filter;
+
+        dlg = gtk_file_chooser_dialog_new (_("Select image to load"),
+                                           GTK_WINDOW (gtk_widget_get_toplevel ((GtkWidget*) rte)),
+                                           GTK_FILE_CHOOSER_ACTION_OPEN,
+                                           GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+                                           GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
+                                           NULL);
+        filter = gtk_file_filter_new ();
+        gtk_file_filter_add_pixbuf_formats (filter);
+        gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (dlg), filter);
+
+        if (gtk_dialog_run (GTK_DIALOG (dlg)) == GTK_RESPONSE_ACCEPT) {
+                char *filename;
+                GError *error = NULL;
+
+                filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dlg));
+
+		GdkPixbuf *pixbuf;
+		pixbuf = gdk_pixbuf_new_from_file (filename, &error);
+		if (pixbuf) {
+			GtkTextIter start;
+			GtkTextIter end;
+			gboolean ret = FALSE;
+			
+			ret = gtk_text_buffer_get_selection_bounds (rte->priv->textbuffer, &start, &end);
+			if (ret)
+				gtk_text_buffer_delete (rte->priv->textbuffer, &start, &end);
+			
+			gtk_text_buffer_get_iter_at_mark (rte->priv->textbuffer, &start,
+							  gtk_text_buffer_get_insert (rte->priv->textbuffer));
+			gtk_text_buffer_insert_pixbuf (rte->priv->textbuffer, &start, pixbuf);
+			g_object_unref (pixbuf);
+		}
+		else {
+			GtkWidget *msg;
+
+                        msg = gtk_message_dialog_new_with_markup (GTK_WINDOW (gtk_widget_get_toplevel ((GtkWidget*) rte)),
+                                                                  GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR,
+                                                                  GTK_BUTTONS_CLOSE,
+                                                                  _("Could not load the contents of '%s':\n %s"),
+                                                                  filename,
+                                                                  error && error->message ? error->message : _("No detail"));
+			g_clear_error (&error);
+                        gtk_widget_destroy (dlg);
+                        dlg = NULL;
+			
+                        gtk_dialog_run (GTK_DIALOG (msg));
+                        gtk_widget_destroy (msg);
+		}
+	}
+
+	gtk_widget_destroy (dlg);
+}
+
+static void
+mark_set_cb (GtkTextBuffer *textbuffer, GtkTextIter *location, GtkTextMark *mark, GdauiRtEditor *rte)
+{
+	if (mark == gtk_text_buffer_get_insert (textbuffer)) {
+		GtkAction *action;
+		gboolean act;
+		gint i;
+
+		rte->priv->selection_changing = TRUE;
+
+		for (i = 0; i < TEXT_TAG_LAST; i++) {
+			if (! rte->priv->tags[i].action_name)
+				continue;
+
+			action = gtk_ui_manager_get_action (rte->priv->uimanager,
+							    rte->priv->tags[i].action_name);
+			if (gtk_text_buffer_get_has_selection (textbuffer))
+				act = FALSE;
+			else
+				act = gtk_text_iter_has_tag (location, rte->priv->tags [i].tag);
+			gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), act);
+		}
+
+		rte->priv->selection_changing = FALSE;
+	}
+}
+
+static void
+insert_text_cb (GtkTextBuffer *textbuffer, GtkTextIter *location, gchar *text, gint len, GdauiRtEditor *rte)
+{
+	rte->priv->insert_offset = gtk_text_iter_get_offset (location);
+}
+
+static void
+insert_text_after_cb (GtkTextBuffer *textbuffer, GtkTextIter *location, gchar *text, gint len, GdauiRtEditor *rte)
+{
+	GtkTextIter start, end, sol;
+
+	if ((rte->priv->insert_offset < 0) || rte->priv->show_markup)
+		return;
+
+	gtk_text_buffer_get_iter_at_offset (textbuffer, &start, rte->priv->insert_offset);
+	end = *location;
+	if (gtk_text_iter_backward_chars (&end, g_utf8_strlen (text, -1))) {
+		gint i;
+		for (i = 0; i < TEXT_TAG_LAST; i++) {
+			GtkAction *action;
+			if (! rte->priv->tags[i].action_name)
+				continue;
+			action = gtk_ui_manager_get_action (rte->priv->uimanager,
+							    rte->priv->tags[i].action_name);
+			if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
+				gtk_text_buffer_apply_tag (rte->priv->textbuffer,
+							   rte->priv->tags[i].tag, location, &end);
+		}
+	}
+	rte->priv->insert_offset = -1;
+
+	/* check if the start of the line has a list tag */
+	sol = end;
+	gtk_text_iter_set_line_offset (&sol, 0);
+	if (gtk_text_iter_has_tag (&sol, rte->priv->tags [TEXT_TAG_LIST1].tag))
+		gtk_text_buffer_apply_tag (rte->priv->textbuffer,
+					   rte->priv->tags[TEXT_TAG_LIST1].tag, location, &end);
+	else if (gtk_text_iter_has_tag (&sol, rte->priv->tags [TEXT_TAG_LIST2].tag))
+		gtk_text_buffer_apply_tag (rte->priv->textbuffer,
+					   rte->priv->tags[TEXT_TAG_LIST2].tag, location, &end);
+
+	if (*text == '\n') {
+		/* check if we are at a bullet to add another bullet to make a list */
+		if (! gtk_text_iter_ends_tag (&start, rte->priv->tags [TEXT_TAG_BULLET].tag)) {
+			gint line;
+			line = gtk_text_iter_get_line (&start);
+			for (; gtk_text_iter_backward_char (&start) &&
+			      (gtk_text_iter_get_line (&start) == line); ) {
+				if (gtk_text_iter_begins_tag (&start, rte->priv->tags [TEXT_TAG_BULLET].tag)) {
+					gtk_text_iter_forward_char (&end);
+					if (gtk_text_iter_has_tag (&start, rte->priv->tags [TEXT_TAG_LIST1].tag))
+						gtk_text_buffer_insert (textbuffer, &end, "- ", -1);
+					else if (gtk_text_iter_has_tag (&start, rte->priv->tags [TEXT_TAG_LIST2].tag))
+						gtk_text_buffer_insert (textbuffer, &end, " - ", -1);
+					break;
+				}
+			}
+		}
+	}
+}
+
+static void
+delete_range_cb (GtkTextBuffer *textbuffer, GtkTextIter *start, GtkTextIter *end, GdauiRtEditor *rte)
+{
+	GtkTextIter prev;
+
+	/* check if there is a start or end TEXT_TAG_BULLET in the deleted range */
+	prev = *start;
+	do {
+		if (gtk_text_iter_has_tag (&prev, rte->priv->tags[TEXT_TAG_BULLET].tag)) {
+			GtkTextIter iter;
+			iter = prev;
+			if (! gtk_text_iter_begins_tag (&prev, rte->priv->tags[TEXT_TAG_BULLET].tag)) {
+				/* find start of tag */
+				for (; gtk_text_iter_backward_char (&iter); ) {
+					if (gtk_text_iter_begins_tag (&iter,
+								      rte->priv->tags[TEXT_TAG_BULLET].tag)) {
+						if (gtk_text_iter_compare (&iter, start) < 0)
+							*start = iter;
+						break;
+					}
+				}
+			}
+
+			/* find end of tag */
+			for (; gtk_text_iter_forward_char (&prev); ) {
+				if (gtk_text_iter_ends_tag (&prev,
+							    rte->priv->tags[TEXT_TAG_BULLET].tag)) {
+					if (gtk_text_iter_compare (&prev, end) > 0)
+						*end = prev;
+					break;
+				}
+			}
+			gtk_text_buffer_remove_tag (rte->priv->textbuffer,
+						    rte->priv->tags[TEXT_TAG_BULLET].tag,
+						    &iter, &prev);
+		}
+	}
+	while (gtk_text_iter_forward_char (&prev) && (gtk_text_iter_compare (&prev, end) <= 0));
+
+	/* check if TEXT_TAG_LIST1 left opened in range */
+	if (gtk_text_iter_has_tag (end, rte->priv->tags[TEXT_TAG_LIST1].tag)) {
+		GtkTextIter iter;
+		iter = *start;
+		if (gtk_text_iter_backward_char (&iter) &&
+		    ! gtk_text_iter_has_tag (&iter, rte->priv->tags[TEXT_TAG_LIST1].tag)) {
+			    for (iter = *end; gtk_text_iter_forward_char (&iter); ) {
+				    if (gtk_text_iter_ends_tag (&iter, rte->priv->tags[TEXT_TAG_LIST1].tag))
+					    break;
+			    }
+			    gtk_text_buffer_remove_tag (rte->priv->textbuffer,
+							rte->priv->tags[TEXT_TAG_LIST1].tag,
+							start, &iter);
+		    }
+	}
+	/* check if TEXT_TAG_LIST2 left opened in range */
+	if (gtk_text_iter_has_tag (end, rte->priv->tags[TEXT_TAG_LIST2].tag)) {
+		GtkTextIter iter;
+		iter = *start;
+		if (gtk_text_iter_backward_char (&iter) &&
+		    ! gtk_text_iter_has_tag (&iter, rte->priv->tags[TEXT_TAG_LIST2].tag)) {
+			    for (iter = *end; gtk_text_iter_forward_char (&iter); ) {
+				    if (gtk_text_iter_ends_tag (&iter, rte->priv->tags[TEXT_TAG_LIST2].tag))
+					    break;
+			    }
+			    gtk_text_buffer_remove_tag (rte->priv->textbuffer,
+							rte->priv->tags[TEXT_TAG_LIST2].tag,
+							start, &iter);
+		    }
+	}
+}
+
+static void
+show_markup_item_activate_cb (GtkCheckMenuItem *checkmenuitem, GdauiRtEditor *rte)
+{
+	gboolean show;
+	show = gtk_check_menu_item_get_active (checkmenuitem);
+	_gdaui_rt_editor_set_show_markup (rte, show);
+}
+
+static void
+populate_popup_cb (GtkTextView *entry, GtkMenu *menu, GdauiRtEditor *rte)
+{
+	GtkWidget *item;
+
+	item = gtk_separator_menu_item_new ();
+        gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item);
+        gtk_widget_show (item);
+	
+	item = gtk_check_menu_item_new_with_label (_("Show source markup"));
+        gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item);
+	gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), rte->priv->show_markup);
+        g_signal_connect (G_OBJECT (item), "toggled",
+                          G_CALLBACK (show_markup_item_activate_cb), rte);
+        gtk_widget_show (item);
+}
+
+/* RTE markup analysis */
+typedef enum {
+	MARKUP_NONE,      /* 0 */
+	MARKUP_BOLD,
+	MARKUP_TT,
+	MARKUP_VERBATIM,
+	MARKUP_ITALIC,
+	MARKUP_STRIKE,    /* 5 */
+	MARKUP_UNDERLINE,
+
+	MARKUP_TITLE1_S,
+	MARKUP_TITLE1_E,
+	MARKUP_TITLE2_S,
+	MARKUP_TITLE2_E,  /* 10 */
+
+	MARKUP_PICTURE_S,
+	MARKUP_PICTURE_E,
+
+	MARKUP_LIST_S,
+	MARKUP_LIST_E,
+
+	MARKUP_EOF
+} MarkupTag;
+
+typedef struct {
+	GtkTextMark *m_start;
+	GtkTextMark *m_end;
+	gboolean init;
+	MarkupTag markup;
+} TextTag;
+
+
+static MarkupTag get_markup_token (GtkTextIter *iter, gint *out_nb_spaces_before, GtkTextIter *out_end,
+				   TextTag *start_tag, GdauiRtEditor *rte);
+static MarkupTag get_token (GtkTextIter *iter, gint *out_nb_spaces_before, GtkTextIter *out_end,
+			    TextTag *start_tag, GdauiRtEditor *rte);
+static gchar get_char_at_iter (GtkTextIter *iter, gboolean move_forward_first);
+static gboolean markup_tag_match (MarkupTag tag1, gint tagline1, MarkupTag tag2, gint tagline2);
+
+static void
+apply_markup (GdauiRtEditor *rte, GtkTextBuffer *textbuffer, TextTag *current, GtkTextMark *mark_start, GtkTextMark *mark_end)
+{
+	gint ssol;
+	GtkTextIter start, end;
+
+	rte->priv->insert_offset = -1;
+
+	gtk_text_buffer_get_iter_at_mark (textbuffer, &start, mark_start);
+	gtk_text_buffer_get_iter_at_mark (textbuffer, &end, mark_end);
+
+
+	/* apply markup */
+	GtkTextIter astart;
+	gtk_text_buffer_get_iter_at_mark (textbuffer, &astart, current->m_start);
+	switch (current->markup) {
+	case MARKUP_BOLD:
+		gtk_text_buffer_apply_tag (textbuffer,
+					   rte->priv->tags[TEXT_TAG_BOLD].tag,
+					   &astart, &end);
+		break;
+	case MARKUP_VERBATIM:
+		gtk_text_buffer_apply_tag (textbuffer,
+					   rte->priv->tags[TEXT_TAG_VERBATIM].tag,
+					   &astart, &end);
+		break;
+	case MARKUP_TT:
+		gtk_text_buffer_apply_tag (textbuffer,
+					   rte->priv->tags[TEXT_TAG_TT].tag,
+					   &astart, &end);
+		break;
+	case MARKUP_ITALIC:
+		gtk_text_buffer_apply_tag (textbuffer,
+					   rte->priv->tags[TEXT_TAG_ITALIC].tag,
+					   &astart, &end);
+		break;
+	case MARKUP_STRIKE:
+		gtk_text_buffer_apply_tag (textbuffer,
+					   rte->priv->tags[TEXT_TAG_STRIKE].tag,
+					   &astart, &end);
+		break;
+	case MARKUP_UNDERLINE:
+		gtk_text_buffer_apply_tag (textbuffer,
+					   rte->priv->tags[TEXT_TAG_UNDERLINE].tag,
+					   &astart, &end);
+		break;
+	case MARKUP_TITLE1_S:
+		gtk_text_buffer_apply_tag (textbuffer,
+					   rte->priv->tags[TEXT_TAG_TITLE1].tag,
+					   &astart, &end);
+		break;
+	case MARKUP_TITLE2_S:
+		gtk_text_buffer_apply_tag (textbuffer,
+					   rte->priv->tags[TEXT_TAG_TITLE2].tag,
+					   &astart, &end);
+		break;
+	case MARKUP_LIST_S: {
+		if (! bullet_pix)
+			bullet_pix = gdk_pixbuf_new_from_inline (-1, bullet_pixdata,
+								 FALSE, NULL);
+		if (! bulleth_pix)
+			bulleth_pix = gdk_pixbuf_new_from_inline (-1, bulleth_pixdata,
+								  FALSE, NULL);
+		GtkTextIter ps, pe;
+		gtk_text_buffer_get_iter_at_mark (textbuffer, &ps, current->m_start);
+		ssol = spaces_since_start_of_line (&ps);
+		if (ssol > 0) {
+			GtkTextIter diter;
+			diter = ps;
+			if (gtk_text_iter_backward_chars (&diter, ssol))
+				gtk_text_buffer_delete (textbuffer, &diter, &ps);
+		}
+		gtk_text_buffer_get_iter_at_mark (textbuffer, &ps, current->m_end);
+		pe = ps;
+		if (ssol > 0)
+			gtk_text_buffer_insert_pixbuf (textbuffer, &pe, bulleth_pix);
+		else
+			gtk_text_buffer_insert_pixbuf (textbuffer, &pe, bullet_pix);
+		gtk_text_buffer_insert (textbuffer, &pe, " ", -1);
+					
+		gtk_text_buffer_get_iter_at_mark (textbuffer, &ps, current->m_start);
+		gtk_text_buffer_apply_tag (textbuffer,
+					   rte->priv->tags[TEXT_TAG_BULLET].tag,
+					   &ps, &pe);					
+		gtk_text_buffer_get_iter_at_mark (textbuffer, &astart, current->m_start);
+		if (! gtk_text_iter_ends_line (&ps))
+			for (; gtk_text_iter_forward_char (&ps); ) {
+				if (gtk_text_iter_ends_line (&ps))
+					break;
+			}
+		else
+			gtk_text_iter_forward_char (&ps);
+		if (ssol > 0)
+			gtk_text_buffer_apply_tag (textbuffer,
+						   rte->priv->tags[TEXT_TAG_LIST2].tag,
+						   &astart, &ps);
+		else
+			gtk_text_buffer_apply_tag (textbuffer,
+						   rte->priv->tags[TEXT_TAG_LIST1].tag,
+						   &astart, &ps);
+		break;
+	}
+	case MARKUP_PICTURE_S: {
+		gchar *data;
+		GtkTextIter ps, pe;
+		gsize length;
+		GdkPixdata pixdata;
+		gtk_text_buffer_get_iter_at_mark (textbuffer, &ps, current->m_end);
+		pe = start;
+		data = remove_newlines_from_base64 (gtk_text_buffer_get_text (textbuffer, &ps, &pe, FALSE));
+		/*g_print ("{{{%s}}}\n", data);*/
+		g_base64_decode_inplace (data, &length);
+		if (gdk_pixdata_deserialize (&pixdata, length, (guint8*) data, NULL)) {
+			GdkPixbuf *pixbuf;
+			pixbuf = gdk_pixbuf_from_pixdata (&pixdata, TRUE, NULL);
+			if (pixbuf) {
+				gtk_text_buffer_delete (textbuffer, &ps, &pe);
+				gtk_text_buffer_get_iter_at_mark (textbuffer, &ps, mark_end);
+				gtk_text_buffer_insert_pixbuf (textbuffer, &ps, pixbuf);
+				g_object_unref (pixbuf);
+			}
+		}
+		g_free (data);
+		break;
+	}
+	default:
+		g_warning ("Unhandled marker (type %d)", current->markup);
+		break;
+	}
+	/* remove markup text */
+	gtk_text_buffer_get_iter_at_mark (textbuffer, &start, mark_start);
+	gtk_text_buffer_get_iter_at_mark (textbuffer, &end, mark_end);
+	if (! gtk_text_iter_equal (&start, &end))
+		gtk_text_buffer_delete (textbuffer, &start, &end);
+	gtk_text_buffer_get_iter_at_mark (textbuffer, &start, current->m_start);
+	gtk_text_buffer_get_iter_at_mark (textbuffer, &end, current->m_end);
+	if (! gtk_text_iter_equal (&start, &end))
+		gtk_text_buffer_delete (textbuffer, &start, &end);
+}
+
+static void
+text_buffer_changed_cb (GtkTextBuffer *textbuffer, GdauiRtEditor *rte)
+{
+	GSList *queue = NULL;
+	MarkupTag mt;
+	TextTag *current = NULL;
+	GtkTextIter start, end;
+	gint ssol;
+
+	if (rte->priv->show_markup) {
+		if (rte->priv->enable_changed_signal)
+			g_signal_emit (rte, gdaui_rt_editor_signals[CHANGED], 0, NULL);
+		return;
+	}
+
+	gtk_text_buffer_get_start_iter (textbuffer, &start);
+
+	g_signal_handlers_block_by_func (textbuffer,
+					 G_CALLBACK (text_buffer_changed_cb), rte);
+	g_signal_handlers_block_by_func (textbuffer,
+					 G_CALLBACK (delete_range_cb), rte);
+
+	
+	for (mt = get_token (&start, &ssol, &end, current, rte);
+	     mt != MARKUP_EOF;
+	     mt = get_token (&start, &ssol, &end, current, rte)) {
+		gchar *text= gtk_text_iter_get_text (&start, &end);
+		/*g_print ("Token %d [%s] with SSOL %d\n", mt, text, ssol);*/
+		g_free (text);
+
+		if (mt == MARKUP_NONE) {
+			start = end;
+			continue;
+		}
+		if (! current) {
+			current = g_new (TextTag, 1);
+			current->markup = mt;
+			current->m_start = gtk_text_buffer_create_mark (textbuffer, NULL, &start, TRUE);
+			current->m_end = gtk_text_buffer_create_mark (textbuffer, NULL, &end, TRUE);
+
+			queue = g_slist_prepend (queue, current);
+		}
+		else {
+			GtkTextIter liter;
+			gtk_text_buffer_get_iter_at_mark (textbuffer, &liter, current->m_start);
+			if (markup_tag_match (current->markup, gtk_text_iter_get_line (&liter),
+					      mt, gtk_text_iter_get_line (&start))) {
+				/* save iters as marks */
+				GtkTextMark *mark_start, *mark_end;
+				mark_start = gtk_text_buffer_create_mark (textbuffer, NULL, &start, TRUE);
+				mark_end = gtk_text_buffer_create_mark (textbuffer, NULL, &end, TRUE);
+
+				/* apply markup */
+				apply_markup (rte, textbuffer, current, mark_start, mark_end);
+
+				/* get rid of @current */
+				gtk_text_buffer_delete_mark (textbuffer, current->m_start);
+				gtk_text_buffer_delete_mark (textbuffer, current->m_end);
+				g_free (current);
+				queue = g_slist_remove (queue, current);
+				current = NULL;
+
+				if (queue) {
+					current = (TextTag*) queue->data;
+					gtk_text_buffer_get_iter_at_mark (textbuffer, &end, current->m_end);
+				}
+				else {
+					/* restore iter from marks */
+					gtk_text_buffer_get_iter_at_mark (textbuffer, &end, mark_end);
+				}
+
+				/* delete marks */
+				gtk_text_buffer_delete_mark (textbuffer, mark_end);
+				gtk_text_buffer_delete_mark (textbuffer, mark_start);
+			}
+			else {
+				current = g_new (TextTag, 1);
+				current->markup = mt;
+				current->m_start = gtk_text_buffer_create_mark (textbuffer, NULL, &start,
+										TRUE);
+				current->m_end = gtk_text_buffer_create_mark (textbuffer, NULL, &end, TRUE);
+
+				queue = g_slist_prepend (queue, current);
+			}
+		}
+
+		start = end;
+	}
+
+	while (queue) {
+		current = (TextTag*) queue->data;
+		gtk_text_buffer_delete_mark (textbuffer, current->m_start);
+		gtk_text_buffer_delete_mark (textbuffer, current->m_end);
+		g_free (current);
+		queue = g_slist_delete_link (queue, queue);
+	}
+
+	g_signal_handlers_unblock_by_func (textbuffer,
+					   G_CALLBACK (delete_range_cb), rte);
+	g_signal_handlers_unblock_by_func (textbuffer,
+					   G_CALLBACK (text_buffer_changed_cb), rte);
+
+	if (rte->priv->enable_changed_signal)
+		g_signal_emit (rte, gdaui_rt_editor_signals[CHANGED], 0, NULL);
+}
+
+/**
+ * get_token
+ *
+ * returns the token type starting from @iter, and positions @out_end to the last used position
+ * position.
+ */
+static MarkupTag
+get_token (GtkTextIter *iter, gint *out_nb_spaces_before, GtkTextIter *out_end,
+	   TextTag *start_tag, GdauiRtEditor *rte)
+{
+	MarkupTag retval;
+	GtkTextIter inti;
+	inti = *iter;
+
+	retval = get_markup_token (&inti, out_nb_spaces_before, out_end, start_tag, rte);
+	if ((retval != MARKUP_NONE) || (retval == MARKUP_EOF))
+		return retval;
+
+	for (; gtk_text_iter_forward_char (&inti);) {
+		retval = get_markup_token (&inti, NULL, NULL, start_tag, rte);
+		if ((retval != MARKUP_NONE) || (retval == MARKUP_EOF))
+			break;
+	}
+	*out_end = inti;
+	return MARKUP_NONE;
+}
+
+/*
+ * spaces_since_start_of_line
+ * @iter: an iterator, __not modified__
+ *
+ * Computes the number of spaces since start of line in case there is no other
+ * character on the line except for spaces
+ *
+ * Returns: number of spaces, or -1 if there is not only some spaces on the line before @iter
+ */
+static gint
+spaces_since_start_of_line (GtkTextIter *iter)
+{
+	gint i = 0;
+	GtkTextIter inti = *iter;
+	gunichar u;
+	for (; !gtk_text_iter_starts_line (&inti) && gtk_text_iter_backward_char (&inti); i++) {
+		u = gtk_text_iter_get_char (&inti);
+		if (! g_unichar_isspace (u))
+			return -1;
+	}
+	
+#ifdef GDA_DEBUG_NO
+	gchar *data;
+	data = gtk_text_buffer_get_slice (gtk_text_iter_get_buffer (iter), &inti, iter, TRUE);
+	g_print ("FOUND %d spaces for [%s]\n", i, data);
+	g_free (data);
+#endif
+	return i;
+}
+
+/**
+ * get_markup_token
+ * @iter: starting position
+ * @out_nb_spaces_before: a place to set the value returned by spaces_since_start_of_line() if called
+ * @out_end: place to put the last used position, or %NULL
+ * @rte: the #GdauiRtEditor
+ *
+ * Parses marking tokens, nothing else
+ *
+ * Returns: a markup token, or MARKUP_NONE or MARKUP_EOF otherwise
+ */
+static MarkupTag
+get_markup_token (GtkTextIter *iter, gint *out_nb_spaces_before, GtkTextIter *out_end,
+		  TextTag *start_tag, GdauiRtEditor *rte)
+{
+	GtkTextIter inti;
+	gchar c;
+	gint ssol = -1; /* spaces since start of line */
+	MarkupTag start_markup = MARKUP_EOF;
+	gint linestart = 0;
+
+#define SET_OUT \
+	if (out_end) {							\
+		gtk_text_iter_forward_char (&inti);			\
+		*out_end = inti;					\
+	}								\
+	if (out_nb_spaces_before)					\
+		*out_nb_spaces_before = ssol
+
+	if (start_tag) {
+		start_markup = start_tag->markup;
+		gtk_text_buffer_get_iter_at_mark (gtk_text_iter_get_buffer (iter), &inti, start_tag->m_start);
+		linestart = gtk_text_iter_get_line (&inti);
+	}
+
+	inti = *iter;
+	if (out_end)
+		*out_end = inti;
+
+	c = get_char_at_iter (&inti, FALSE);
+
+	/* tests involving starting markup before anything else */
+	if (start_markup == MARKUP_PICTURE_S) {
+		if (c == ']') {
+			c = get_char_at_iter (&inti, TRUE);
+			if (c == ']') {
+				c = get_char_at_iter (&inti, TRUE);
+				if (c == ']') {
+					SET_OUT;
+					return MARKUP_PICTURE_E;
+				}
+			}
+		}
+		if (!c)
+			return MARKUP_EOF;
+		else
+			return MARKUP_NONE;
+	}
+	else if (start_markup == MARKUP_VERBATIM) {
+		if (c == '"') {
+			c = get_char_at_iter (&inti, TRUE);
+			if (c == '"') {
+				c = get_char_at_iter (&inti, TRUE);
+				if (c == '"') {
+					SET_OUT;
+					return MARKUP_VERBATIM;
+				}
+			}
+		}
+		if (!c)
+			return MARKUP_EOF;
+		else
+			return MARKUP_NONE;
+	}
+	else if (gtk_text_iter_has_tag (&inti, rte->priv->tags[TEXT_TAG_VERBATIM].tag)) {
+		if (!c)
+			return MARKUP_EOF;
+		else
+			return MARKUP_NONE;		
+	}
+
+	if (gtk_text_iter_ends_line (&inti) && (start_markup == MARKUP_LIST_S) &&
+	    (linestart == gtk_text_iter_get_line (&inti)))
+		return MARKUP_LIST_E;
+
+	if (!c)
+		return MARKUP_EOF;
+
+	/* other tests */
+	ssol = spaces_since_start_of_line (&inti);
+	if (ssol >= 0) {
+		/* we are on a line with only spaces since its start */
+		if (c == '=') {
+			c = get_char_at_iter (&inti, TRUE);
+			if (c == ' ') {
+				SET_OUT;
+				return MARKUP_TITLE1_S;
+			}
+			else if (c == '=') {
+				c = get_char_at_iter (&inti, TRUE);
+				if (c == ' ') {
+					SET_OUT;
+					return MARKUP_TITLE2_S;
+				}
+			}
+		}
+		else if (c == '-') {
+			c = get_char_at_iter (&inti, TRUE);
+			if (c == ' ') {
+				SET_OUT;
+				return MARKUP_LIST_S;
+			}
+		}
+	}
+
+	if (c == '*') {
+		c = get_char_at_iter (&inti, TRUE);
+		if (c == '*') {
+			SET_OUT;
+			return MARKUP_BOLD;
+		}
+	}
+	else if (c == '/') {
+		c = get_char_at_iter (&inti, TRUE);
+		if (c == '/') {
+			SET_OUT;
+			return MARKUP_ITALIC;
+		}
+	}
+	else if (c == '_') {
+		c = get_char_at_iter (&inti, TRUE);
+		if (c == '_') {
+			SET_OUT;
+			return MARKUP_UNDERLINE;
+		}
+	}
+	else if (c == '-') {
+		c = get_char_at_iter (&inti, TRUE);
+		if (c == '-') {
+			SET_OUT;
+			return MARKUP_STRIKE;
+		}
+	}
+	else if (c == '`') {
+		c = get_char_at_iter (&inti, TRUE);
+		if (c == '`') {
+			SET_OUT;
+			return MARKUP_TT;
+		}
+	}
+	else if (c == '"') {
+		c = get_char_at_iter (&inti, TRUE);
+		if (c == '"') {
+			c = get_char_at_iter (&inti, TRUE);
+			if (c == '"') {
+				SET_OUT;
+				return MARKUP_VERBATIM;
+			}
+		}
+	}
+	else if (c == ' ') {
+		gboolean line;
+		line = gtk_text_iter_starts_line (&inti);
+
+		c = get_char_at_iter (&inti, TRUE);
+		if (c == '=') {
+			if (start_markup == MARKUP_TITLE1_S) {
+				GtkTextIter it = inti;
+				gtk_text_iter_forward_char (&it);
+				if (gtk_text_iter_ends_line (&it) &&
+				    (linestart == gtk_text_iter_get_line (&inti))) {
+					SET_OUT;
+					return MARKUP_TITLE1_E;
+				}
+			}
+			else {
+				c = get_char_at_iter (&inti, TRUE);
+				if (c == '=') {
+					GtkTextIter it = inti;
+					gtk_text_iter_forward_char (&it);
+					if ((start_markup == MARKUP_TITLE2_S) && gtk_text_iter_ends_line (&it) &&
+					    (linestart == gtk_text_iter_get_line (&inti))) {
+						SET_OUT;
+						return MARKUP_TITLE2_E;
+					}
+				}
+			}
+		}
+	}
+	else if (c == '[') {
+		c = get_char_at_iter (&inti, TRUE);
+		if (c == '[') {
+			c = get_char_at_iter (&inti, TRUE);
+			if (c == '[') {
+				SET_OUT;
+				return MARKUP_PICTURE_S;
+			}
+		}
+	}
+	return MARKUP_NONE;
+}
+
+/**
+ * get_char_at_iter
+ * @iter: an iter
+ * @move_forward_first: %TRUE if @iter should be moved forward first
+ *
+ * Returns: 0 for EOF, 1 for the "unknown" unicode char (usually pixbufs) or for chars represented
+ * by more than one byte
+ */
+static gchar
+get_char_at_iter (GtkTextIter *iter, gboolean move_forward_first)
+{
+	if (!move_forward_first || 
+	    (move_forward_first	&& gtk_text_iter_forward_char (iter))) {
+		gunichar uc;
+		gchar buf1[6];
+		uc = gtk_text_iter_get_char (iter);
+		if (!uc)
+			return 0;
+		if (g_unichar_to_utf8 (uc, buf1) == 1)
+			return *buf1;
+		return 1;
+	}
+	return 0;
+}
+
+static gboolean
+markup_tag_match (MarkupTag tag1, gint tagline1, MarkupTag tag2, gint tagline2)
+{
+	gboolean retval;
+	switch (tag1) {
+	case MARKUP_BOLD:
+	case MARKUP_TT:
+	case MARKUP_VERBATIM:
+	case MARKUP_ITALIC:
+	case MARKUP_STRIKE:
+	case MARKUP_UNDERLINE:
+		retval = (tag1 == tag2) ? TRUE : FALSE;
+		break;
+	case MARKUP_TITLE1_S:
+		retval = (tag2 == MARKUP_TITLE1_E) ? TRUE : FALSE;
+		break;
+	case MARKUP_TITLE2_S:
+		retval = (tag2 == MARKUP_TITLE2_E) ? TRUE : FALSE;
+		break;
+	case MARKUP_PICTURE_S:
+		retval = (tag2 == MARKUP_PICTURE_E) ? TRUE : FALSE;
+		break;
+	case MARKUP_LIST_S:
+		retval = (tag2 == MARKUP_LIST_E) ? TRUE : FALSE;
+		break;
+	default:
+		retval = FALSE;
+		break;
+	}
+
+	if (retval) {
+		if (tag1 != MARKUP_PICTURE_S)
+			retval = (tagline1 == tagline2) ? TRUE : FALSE;
+	}
+	return retval;
+}
+
+static guint8 *serialize_as_txt2tag (GtkTextBuffer     *register_buffer,
+				     GtkTextBuffer     *content_buffer,
+				     const GtkTextIter *start,
+				     const GtkTextIter *end,
+				     gsize             *length,
+				     GdauiRtEditor     *editor);
+
+/**
+ * gdaui_rt_editor_get_contents
+ * @editor: a #GdauiRtEditor
+ *
+ * Get the contents of @editor, using the markup syntax
+ *
+ * Returns: (transfer full): a new string, or %NULL if there was an error
+ *
+ * Since: 4.2.2
+ */
+gchar *
+gdaui_rt_editor_get_contents (GdauiRtEditor *editor)
+{
+	g_return_val_if_fail (GDAUI_IS_RT_EDITOR (editor), NULL);
+
+	if (editor->priv->saved_for_help)
+		return g_strdup (editor->priv->saved_for_help);
+	else
+		return real_gdaui_rt_editor_get_contents (editor);
+}
+
+static gchar *
+real_gdaui_rt_editor_get_contents (GdauiRtEditor *editor)
+{
+	GtkTextIter start, end;
+
+	gtk_text_buffer_get_bounds (editor->priv->textbuffer, &start, &end);
+
+	if (editor->priv->show_markup)
+		return gtk_text_buffer_get_text (editor->priv->textbuffer, &start, &end, FALSE);
+	else {
+		GdkAtom format;
+		guint8 *data;
+		gsize length;
+		format = gtk_text_buffer_register_serialize_format (editor->priv->textbuffer, "txt/rte",
+								    (GtkTextBufferSerializeFunc) serialize_as_txt2tag,
+								    editor, NULL);
+		data = gtk_text_buffer_serialize (editor->priv->textbuffer, editor->priv->textbuffer, format,
+						  &start, &end, &length);
+		return (gchar*) data;
+	}
+}
+
+/*
+ * Serialization as txt2tag
+ */
+typedef struct
+{
+	GString *text_str;
+	GHashTable *tags;
+	GtkTextIter start, end;
+
+	gint tag_id;
+	GHashTable *tag_id_tags;
+} SerializationContext;
+
+/*
+ * serialize_tag:
+ * @tag: a #GtkTextTag
+ * @starting: %TRUE if serialization has to be done for the opening part
+ *
+ * Returns: a static string, never %NULL
+ */
+static const gchar *
+serialize_tag (GtkTextTag *tag, gboolean starting, GdauiRtEditor *editor)
+{
+	if (tag == editor->priv->tags[TEXT_TAG_ITALIC].tag)
+		return "//";
+	else if (tag == editor->priv->tags[TEXT_TAG_BOLD].tag)
+		return "**";
+	else if (tag == editor->priv->tags[TEXT_TAG_UNDERLINE].tag)
+		return "__";
+	else if (tag == editor->priv->tags[TEXT_TAG_STRIKE].tag)
+		return "--";
+	else if (tag == editor->priv->tags[TEXT_TAG_TT].tag)
+		return "``";
+	else if (tag == editor->priv->tags[TEXT_TAG_VERBATIM].tag)
+		return "\"\"\"";
+	else if (tag == editor->priv->tags[TEXT_TAG_TITLE1].tag) {
+		if (starting)
+			return "= ";
+		else
+			return " =";
+	}
+	else if (tag == editor->priv->tags[TEXT_TAG_TITLE2].tag) {
+		if (starting)
+			return "== ";
+		else
+			return " ==";
+	}
+	else if (tag == editor->priv->tags[TEXT_TAG_BULLET].tag)
+		return "";
+	else if (tag == editor->priv->tags[TEXT_TAG_LIST1].tag) {
+		if (starting)
+			return "- ";
+		else
+			return "";
+	}
+	else if (tag == editor->priv->tags[TEXT_TAG_LIST2].tag) {
+		if (starting)
+			return " - ";
+		else
+			return "";
+	}
+	else {
+		gchar *tagname;    
+		g_object_get ((GObject*) tag, "name", &tagname, NULL);
+		g_warning ("Unknown tag '%s'\n", tagname);
+		g_free (tagname);
+		return "";
+	}
+}
+
+/**
+ * steals @base64
+ */
+static gchar *
+add_newlines_to_base64 (gchar *base64)
+{
+	GString *string;
+	gint i;
+	gchar *ptr;
+	string = g_string_new ("");
+	for (i = 0, ptr = base64; *ptr; i++, ptr++) {
+		if (i && ! (i % 100))
+			g_string_append_c (string, '\n');
+		g_string_append_c (string, *ptr);
+	}
+	g_free (base64);
+	return g_string_free (string, FALSE);
+}
+
+/**
+ * steals @base64
+ */
+static gchar *
+remove_newlines_from_base64 (gchar *base64)
+{
+	GString *string;
+	gchar *ptr;
+	string = g_string_new ("");
+	for (ptr = base64; *ptr; ptr++) {
+		if (*ptr != '\n')
+			g_string_append_c (string, *ptr);
+	}
+	g_free (base64);
+	return g_string_free (string, FALSE);
+}
+
+static void
+serialize_text (GtkTextBuffer *buffer, SerializationContext *context, GdauiRtEditor *editor)
+{
+	GtkTextIter iter, old_iter;
+	GList *opened_tags = NULL; /* 1st element of the list is the last opened tag (ie. the one
+				    * which should be closed 1st */
+
+	/*g_string_append (context->text_str, "###");*/
+	iter = context->start;
+	do {
+		GSList *new_tag_list, *list;
+		GList *dlist;
+		gboolean tags_needs_reopened = TRUE;
+		new_tag_list = gtk_text_iter_get_tags (&iter);
+
+		/*
+		 * Close tags which need closing
+		 */
+		/* Find the last element in @opened_tags which is not opened anymore */
+		for (dlist = g_list_last (opened_tags); dlist; dlist = dlist->prev) {
+			if (! g_slist_find (new_tag_list, dlist->data))
+				break;
+		}
+
+		if (dlist) {
+			/* close all the tags up to dlist->data and at the same time remove them
+			 from @opened_tags */
+			for (; opened_tags != dlist;
+			     opened_tags = g_list_delete_link (opened_tags, opened_tags)) {
+				g_string_append (context->text_str,
+						 serialize_tag ((GtkTextTag*) opened_tags->data,
+								FALSE, editor));
+			}
+			g_string_append (context->text_str,
+					 serialize_tag ((GtkTextTag*) opened_tags->data,
+							FALSE, editor));
+			opened_tags = g_list_delete_link (opened_tags, opened_tags);
+		}
+
+		/* Now try to go to either the next tag toggle, or if a pixbuf appears */
+		old_iter = iter;
+		while (1) {
+			gunichar ch = gtk_text_iter_get_char (&iter);
+
+			if (ch == 0xFFFC) {
+				GdkPixbuf *pixbuf = gtk_text_iter_get_pixbuf (&iter);
+
+				if (pixbuf) {
+					/* Append the text before the pixbuf */
+					gchar *tmp_text;
+					tmp_text = gtk_text_iter_get_slice (&old_iter, &iter);
+					g_string_append (context->text_str, tmp_text);
+					g_free (tmp_text);
+
+					if ((pixbuf != bullet_pix) && (pixbuf != bulleth_pix)) {
+						GdkPixdata pixdata;
+						guint8 *tmp;
+						guint len;
+						gchar *data;
+						
+						gdk_pixdata_from_pixbuf (&pixdata, pixbuf, FALSE);
+						tmp = gdk_pixdata_serialize (&pixdata, &len);
+						data = add_newlines_to_base64 (g_base64_encode (tmp, len));
+						g_free (tmp);
+						g_string_append (context->text_str, "[[[");
+						g_string_append (context->text_str, data);
+						g_free (data);
+						g_string_append (context->text_str, "]]]");
+					}
+
+					/* Forward so we don't get the 0xfffc char */
+					gtk_text_iter_forward_char (&iter);
+					old_iter = iter;
+				}
+			}
+			else if (ch == 0) {
+				break;
+			}
+			else
+				gtk_text_iter_forward_char (&iter);
+
+			if (gtk_text_iter_toggles_tag (&iter, NULL)) {
+				/*g_print ("Toggle @pos %d:%d\n", gtk_text_iter_get_line (&iter),
+				  gtk_text_iter_get_line_offset (&iter));*/
+				break;
+			}
+		}
+
+		/* We might have moved too far */
+		if (gtk_text_iter_compare (&iter, &context->end) > 0)
+			iter = context->end;
+
+		/* Append the text, except if there is the TEXT_TAG_BULLET tag */
+		if (! gtk_text_iter_has_tag (&old_iter, editor->priv->tags[TEXT_TAG_BULLET].tag)) {
+			gint i;
+			gchar *tmp_text;
+			tmp_text = gtk_text_iter_get_slice (&old_iter, &iter);
+#ifdef NONO
+			g_string_append (context->text_str, tmp_text);
+#endif
+			for (i = 0; tmp_text[i]; i++) {
+				if (tmp_text[i] != '\n') {
+					if (tags_needs_reopened) {
+						/*
+						 * (re)open tags which are still there
+						 */
+						for (list = new_tag_list; list; list = list->next) {
+							if (! g_list_find (opened_tags, list->data)) {
+								opened_tags = g_list_prepend (opened_tags, list->data);
+								g_string_append (context->text_str,
+										 serialize_tag ((GtkTextTag*) opened_tags->data,
+												TRUE, editor));
+							}
+						}
+						tags_needs_reopened = FALSE;
+					}
+
+					g_string_append_c (context->text_str, tmp_text[i]);
+					continue;
+				}
+				/* close all tags and re-open them after the newline */
+				for (dlist = opened_tags; dlist; dlist = dlist->next) {
+					g_string_append (context->text_str,
+							 serialize_tag (GTK_TEXT_TAG (dlist->data),
+									FALSE, editor));
+				}
+				g_string_append_c (context->text_str, '\n');
+				/* re-open tags */
+				for (dlist = g_list_last (opened_tags); dlist; dlist = dlist->prev) {
+					g_string_append (context->text_str,
+							 serialize_tag (GTK_TEXT_TAG (dlist->data),
+									TRUE, editor));
+				}
+			}
+			g_free (tmp_text);
+		}
+
+		if (tags_needs_reopened) {
+			/*
+			 * (re)open tags which are still there
+			 */
+			for (list = new_tag_list; list; list = list->next) {
+				if (! g_list_find (opened_tags, list->data)) {
+					opened_tags = g_list_prepend (opened_tags, list->data);
+					g_string_append (context->text_str,
+							 serialize_tag ((GtkTextTag*) opened_tags->data,
+									TRUE, editor));
+				}
+			}
+			tags_needs_reopened = FALSE;
+		}
+
+
+		g_slist_free (new_tag_list);
+	}
+	while (!gtk_text_iter_equal (&iter, &context->end));
+
+	/* Close any open tags */
+	for (; opened_tags;
+	     opened_tags = g_list_delete_link (opened_tags, opened_tags)) {
+		g_string_append (context->text_str,
+				 serialize_tag ((GtkTextTag*) opened_tags->data,
+						FALSE, editor));
+	}
+
+	/*g_string_append (context->text_str, "###");*/
+}
+
+/*
+ * serialize_as_txt2tag:
+ */
+static guint8 *
+serialize_as_txt2tag (GtkTextBuffer     *register_buffer,
+		      GtkTextBuffer     *content_buffer,
+		      const GtkTextIter *start,
+		      const GtkTextIter *end,
+		      gsize             *length,
+		      GdauiRtEditor     *editor)
+{
+	SerializationContext context;
+	GString *text;
+
+	context.tags = g_hash_table_new (NULL, NULL);
+	context.text_str = g_string_new (NULL);
+	context.start = *start;
+	context.end = *end;
+	context.tag_id = 0;
+	context.tag_id_tags = g_hash_table_new (NULL, NULL);
+
+	serialize_text (content_buffer, &context, editor);
+
+	text = g_string_new (NULL);
+
+	g_string_append_len (text, context.text_str->str, context.text_str->len);
+
+	g_hash_table_destroy (context.tags);
+	g_string_free (context.text_str, TRUE);
+	g_hash_table_destroy (context.tag_id_tags);
+
+	*length = text->len;
+
+	return (guint8 *) g_string_free (text, FALSE);
+}
+
+
+/**
+ * gdaui_rt_editor_set_contents
+ * @editor: a #GdauiRtEditor
+ * @markup: the text to set in @editor, using the markup syntax (must be valid UTF-8)
+ * @length: length of text in bytes.
+ *
+ * Set @editor's contents. If @length is -1, @markup must be nul-terminated
+ *
+ * Since: 4.2.2
+ */
+void
+gdaui_rt_editor_set_contents (GdauiRtEditor *editor, const gchar *markup, gint length)
+{
+	g_return_if_fail (GDAUI_IS_RT_EDITOR (editor));
+
+	gtk_text_buffer_set_text (editor->priv->textbuffer, markup, length);
+}
+
+/**
+ * gdaui_rt_editor_set_editable
+ * @editor: a #GdauiRtEditor
+ * @editable: whether it's editable
+ *
+ * Set @editor's editability
+ *
+ * Since: 4.2.2
+ */
+void
+gdaui_rt_editor_set_editable (GdauiRtEditor *editor, gboolean editable)
+{
+	g_return_if_fail (GDAUI_IS_RT_EDITOR (editor));
+	gtk_text_view_set_editable (editor->priv->textview, editable);
+	show_hide_toolbar (editor);
+}
+
+/*
+ * _gdaui_rt_editor_set_show_markup
+ * @editor: a #GdauiRtEditor
+ * @show_markup: whether @editor shows markup of applies it
+ *
+ * If @show_markup is %FALSE, then @editor displays text with tags applied (bold text, ...); and if it's
+ * %TRUE then it shows markup text instead
+ *
+ * Since: 4.2.2
+ */
+static void
+_gdaui_rt_editor_set_show_markup (GdauiRtEditor *editor, gboolean show_markup)
+{
+	gchar *data;
+	gint cursor_pos;
+	GtkTextIter iter;
+
+	g_return_if_fail (GDAUI_IS_RT_EDITOR (editor));
+	if (editor->priv->show_markup == show_markup)
+		return;
+
+	g_object_get (editor->priv->textbuffer, "cursor-position", &cursor_pos, NULL);
+	data = real_gdaui_rt_editor_get_contents (editor);
+	editor->priv->show_markup = show_markup;
+	gdaui_rt_editor_set_contents (editor, data, -1);
+	g_free (data);
+
+	gtk_text_buffer_get_iter_at_offset (editor->priv->textbuffer, &iter, cursor_pos);
+	gtk_text_buffer_place_cursor (editor->priv->textbuffer, &iter);
+
+	show_hide_toolbar (editor);
+}
+
+static void
+show_hide_toolbar (GdauiRtEditor *editor)
+{
+	gboolean enable_markup = TRUE;
+	GtkAction *action;
+	
+	if (gtk_text_view_get_editable (editor->priv->textview))
+		gtk_widget_show (editor->priv->toolbar);
+	else
+		gtk_widget_hide (editor->priv->toolbar);
+
+	if (editor->priv->show_markup ||
+	    ! gtk_text_view_get_editable (editor->priv->textview))
+		enable_markup = FALSE;
+
+	action = gtk_ui_manager_get_action (editor->priv->uimanager, "/ToolBar/ActionBold");
+	gtk_action_set_sensitive (action, enable_markup);
+	action = gtk_ui_manager_get_action (editor->priv->uimanager, "/ToolBar/ActionItalic");
+	gtk_action_set_sensitive (action, enable_markup);
+	action = gtk_ui_manager_get_action (editor->priv->uimanager, "/ToolBar/ActionUnderline");
+	gtk_action_set_sensitive (action, enable_markup);
+	action = gtk_ui_manager_get_action (editor->priv->uimanager, "/ToolBar/ActionStrike");
+	gtk_action_set_sensitive (action, enable_markup);
+	action = gtk_ui_manager_get_action (editor->priv->uimanager, "/ToolBar/ActionAddImage");
+	gtk_action_set_sensitive (action, enable_markup);
+	action = gtk_ui_manager_get_action (editor->priv->uimanager, "/ToolBar/ActionReset");
+	gtk_action_set_sensitive (action, enable_markup);
+}
diff --git a/libgda-ui/gdaui-rt-editor.h b/libgda-ui/gdaui-rt-editor.h
new file mode 100644
index 0000000..89926cb
--- /dev/null
+++ b/libgda-ui/gdaui-rt-editor.h
@@ -0,0 +1,70 @@
+/* gdaui-rt-editor.h
+ *
+ * Copyright (C) 2010 Vivien Malerba <malerba gnome-db org>
+ *
+ * This Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#ifndef __GDAUI_RT_EDITOR__
+#define __GDAUI_RT_EDITOR__
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GDAUI_TYPE_RT_EDITOR          (gdaui_rt_editor_get_type())
+#define GDAUI_RT_EDITOR(obj)          G_TYPE_CHECK_INSTANCE_CAST (obj, gdaui_rt_editor_get_type(), GdauiRtEditor)
+#define GDAUI_RT_EDITOR_CLASS(klass)  G_TYPE_CHECK_CLASS_CAST (klass, gdaui_rt_editor_get_type (), GdauiRtEditorClass)
+#define GDAUI_IS_RT_EDITOR(obj)       G_TYPE_CHECK_INSTANCE_TYPE (obj, gdaui_rt_editor_get_type ())
+
+
+typedef struct _GdauiRtEditor      GdauiRtEditor;
+typedef struct _GdauiRtEditorClass GdauiRtEditorClass;
+typedef struct _GdauiRtEditorPriv  GdauiRtEditorPriv;
+
+/* struct for the object's data */
+struct _GdauiRtEditor
+{
+	GtkVBox              object;
+
+	GdauiRtEditorPriv   *priv;
+};
+
+/* struct for the object's class */
+struct _GdauiRtEditorClass
+{
+	GtkVBoxClass         parent_class;
+
+	/* signals */
+        void (* changed) (GdauiRtEditor *editor);
+};
+
+/* 
+ * Generic widget's methods 
+ */
+GType      gdaui_rt_editor_get_type              (void) G_GNUC_CONST;
+
+GtkWidget *gdaui_rt_editor_new                   (void);
+gchar     *gdaui_rt_editor_get_contents          (GdauiRtEditor *editor);
+void       gdaui_rt_editor_set_contents          (GdauiRtEditor *editor, const gchar *markup, gint length);
+void       gdaui_rt_editor_set_editable          (GdauiRtEditor *editor, gboolean editable);
+
+G_END_DECLS
+
+#endif
+
+
+
diff --git a/libgda-ui/libgda-ui.h b/libgda-ui/libgda-ui.h
index eb783d7..05cbf64 100644
--- a/libgda-ui/libgda-ui.h
+++ b/libgda-ui/libgda-ui.h
@@ -1,5 +1,5 @@
 /* GDA library
- * Copyright (C) 2009 The GNOME Foundation.
+ * Copyright (C) 2009 - 2010 The GNOME Foundation.
  *
  * AUTHORS:
  *      Vivien Malerba <malerba gnome-db org>
@@ -44,6 +44,7 @@
 #include <libgda-ui/gdaui-tree-store.h>
 #include <libgda-ui/gdaui-cloud.h>
 #include <libgda-ui/gdaui-data-selector.h>
+#include <libgda-ui/gdaui-rt-editor.h>
 
 G_BEGIN_DECLS
 
diff --git a/libgda-ui/libgda-ui.symbols b/libgda-ui/libgda-ui.symbols
index 38f5c3b..fd3fb72 100644
--- a/libgda-ui/libgda-ui.symbols
+++ b/libgda-ui/libgda-ui.symbols
@@ -164,6 +164,11 @@
 	gdaui_raw_grid_set_layout_from_file
 	gdaui_raw_grid_set_sample_size
 	gdaui_raw_grid_set_sample_start
+	gdaui_rt_editor_get_contents
+	gdaui_rt_editor_get_type
+	gdaui_rt_editor_new
+	gdaui_rt_editor_set_contents
+	gdaui_rt_editor_set_editable
 	gdaui_server_operation_get_type
 	gdaui_server_operation_new
 	gdaui_server_operation_new_in_dialog
diff --git a/testing/.gitignore b/testing/.gitignore
index f32ecf8..f2bb3ea 100644
--- a/testing/.gitignore
+++ b/testing/.gitignore
@@ -4,6 +4,7 @@ gda-provider-status
 gdaui-test-data-entries
 gdaui-test-widget-entry
 gdaui-test-errors
+gdaui-test-rt-editor
 virtual-test
 virtual-test-2
 index.html
diff --git a/testing/Makefile.am b/testing/Makefile.am
index 6f0db3b..c6271e8 100644
--- a/testing/Makefile.am
+++ b/testing/Makefile.am
@@ -7,7 +7,7 @@ AM_CPPFLAGS = \
 
 bin_PROGRAMS = gda-test-connection-4.0
 if HAVE_UI
-UI_PROGS=gdaui-test-data-entries gdaui-test-widget-entry gdaui-test-errors
+UI_PROGS=gdaui-test-data-entries gdaui-test-widget-entry gdaui-test-errors gdaui-test-rt-editor
 endif
 noinst_PROGRAMS = gda-test-blob gda-provider-status virtual-test virtual-test-2 $(UI_PROGS)
 
@@ -81,5 +81,14 @@ gdaui_test_errors_LDADD = \
         $(LIBGDA_LIBS) \
 	$(GTK_LIBS)
 
+gdaui_test_rt_editor_CFLAGS = $(GTK_CFLAGS)
+gdaui_test_rt_editor_SOURCES = \
+        gdaui-test-rt-editor.c
+
+gdaui_test_rt_editor_LDADD = \
+        $(top_builddir)/libgda/libgda-4.0.la \
+        $(top_builddir)/libgda-ui/libgda-ui-4.0.la \
+        $(LIBGDA_LIBS) \
+	$(GTK_LIBS)
 
 EXTRA_DIST = 
diff --git a/testing/gdaui-test-rt-editor.c b/testing/gdaui-test-rt-editor.c
new file mode 100644
index 0000000..b4f88a3
--- /dev/null
+++ b/testing/gdaui-test-rt-editor.c
@@ -0,0 +1,178 @@
+#include <gtk/gtk.h>
+#include <gdk-pixbuf/gdk-pixdata.h>
+#include <string.h>
+#include <libgda-ui/gdaui-rt-editor.h>
+
+static gboolean
+texttags_equal (GtkTextTag *tag1, GtkTextTag *tag2)
+{
+	return TRUE;
+}
+
+static gboolean
+textbuffers_equal (GtkTextBuffer *buffer1, GtkTextBuffer *buffer2, GError **error)
+{
+	GtkTextIter iter1, iter2;
+	gunichar ch1, ch2;
+	gtk_text_buffer_get_start_iter (buffer1, &iter1);
+	gtk_text_buffer_get_start_iter (buffer2, &iter2);
+
+	do {
+		ch1 = gtk_text_iter_get_char (&iter1);
+		ch2 = gtk_text_iter_get_char (&iter2);
+		if (ch1 != ch2) {
+			g_set_error (error, 0, 0, "difference at line %d, offset %d",
+				     gtk_text_iter_get_line (&iter1),
+				     gtk_text_iter_get_line_offset (&iter1));
+			return FALSE;
+		}
+		if (ch1 == 0)
+			break;
+		gchar buf1[6];
+		if ((g_unichar_to_utf8 (ch1, buf1) == 1) &&
+		    (*buf1 == '\n')) {
+			gtk_text_iter_forward_char (&iter1);
+			gtk_text_iter_forward_char (&iter2);
+			continue;
+		}
+
+		GSList *list1, *list2, *p1, *p2;
+		list1 = gtk_text_iter_get_tags (&iter1);
+		list2 = gtk_text_iter_get_tags (&iter2);
+		for (p1 = list1; p1; p1 = p1->next) {
+			for (p2 = list2; p2; p2 = p2->next) {
+				if (texttags_equal (GTK_TEXT_TAG (p1->data),
+						    GTK_TEXT_TAG (p2->data))) {
+					list2 = g_slist_remove (list2, p2->data);
+					break;
+				}
+			}
+			if (!p2) {
+				g_set_error (error, 0, 0, "Missing text tag in textbuffer2 "
+					     "at line %d, offset %d",
+					     gtk_text_iter_get_line (&iter1),
+					     gtk_text_iter_get_line_offset (&iter1));
+				return FALSE;
+			}
+		}
+		for (p2 = list2; p2; p2 = p2->next) {
+			for (p1 = list1; p1; p1 = p1->next) {
+				if (texttags_equal (GTK_TEXT_TAG (p1->data), GTK_TEXT_TAG (p2->data)))
+					break;
+			}
+			if (!p1) {
+				g_set_error (error, 0, 0, "Missing text tag in textbuffer1 "
+					     "at line %d, offset %d",
+					     gtk_text_iter_get_line (&iter1),
+					     gtk_text_iter_get_line_offset (&iter1));
+				return FALSE;
+			}
+		}
+		g_slist_free (list1);
+		g_slist_free (list2);
+		gtk_text_iter_forward_char (&iter1);
+		gtk_text_iter_forward_char (&iter2);
+	} while ((ch1 != 0) && (ch2 != 0));
+
+	GtkTextIter end1, end2;
+	gtk_text_buffer_get_end_iter (buffer1, &end1);
+	gtk_text_buffer_get_end_iter (buffer2, &end2);
+	if (gtk_text_iter_compare (&iter1, &end1)) {
+		g_set_error (error, 0, 0, "textbuffer1 is shorter than textbuffer2");
+		return FALSE;
+	}
+	if (gtk_text_iter_compare (&iter2, &end2)) {
+		g_set_error (error, 0, 0, "textbuffer2 is shorter than textbuffer1");
+		return FALSE;
+	}
+	return TRUE;
+}
+
+static void
+copy_cb (GtkButton *button, GdauiRtEditor *from)
+{
+	GdauiRtEditor *rte;
+	gchar *data;
+	rte = g_object_get_data (G_OBJECT (button), "destrte");
+	data = gdaui_rt_editor_get_contents (from);
+	gdaui_rt_editor_set_contents (rte, data, -1);
+	g_free (data);
+
+#ifdef GDA_DEBUG
+	GtkTextBuffer *b1, *b2;
+	GError *lerror = NULL;
+	g_object_get ((GObject*) from, "buffer", &b1, NULL);
+	g_object_get ((GObject*) rte, "buffer", &b2, NULL);
+	if (! textbuffers_equal (b1, b2, &lerror)) {
+		g_warning ("ERROR: %s\n", lerror->message);
+		g_clear_error (&lerror);
+	}
+	g_object_unref ((GObject*) b1);
+	g_object_unref ((GObject*) b2);
+#endif
+}
+
+
+static GtkWidget *
+create_window (void)
+{
+	GtkWidget *p_win = NULL;
+	GtkWidget *vbox = NULL;
+	GtkWidget *rte = NULL;
+	GtkWidget *button;
+
+	/* Window */
+	p_win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+	gtk_window_set_title  (GTK_WINDOW (p_win), "GtkTextView & GtkTextTag");
+	gtk_window_set_default_size (GTK_WINDOW (p_win), 640, 480);
+	gtk_container_set_border_width (GTK_CONTAINER (p_win), 5);
+	gtk_window_set_position (GTK_WINDOW (p_win), GTK_WIN_POS_CENTER);
+	g_signal_connect (G_OBJECT (p_win), "destroy", gtk_main_quit, NULL);
+
+	/* contents */
+	vbox = gtk_vbox_new (FALSE, 5);
+	gtk_container_add (GTK_CONTAINER (p_win), vbox);
+	rte = gdaui_rt_editor_new ();
+	gtk_box_pack_start (GTK_BOX (vbox), rte, TRUE, TRUE, 0);
+	gdaui_rt_editor_set_contents (GDAUI_RT_EDITOR (rte), "No tags here..., ``Monospaced here``\n= Title level 1 =\n\n"
+				  "blah **important**\n\n"
+				  "== title level 2 ==\n\n"
+				  "blah //italic// blah.\n"
+				  "and ** BOLD!//both italic and bold// Bold!**\nNice Picture: [[[R2RrUAAABIwBAQABAAAAPAAAABMAAAAT6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6urqAAAAy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLAAAAy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLyMfJxMnCycnFyMfJyMfJy8vLy8vLy8vLy8vLy8vLy8vLAAAAy8vLy8vLy8vLy8vLy8vLy8vLy8vLwcK8lcOSWMFRQ8I5RLo6YrBcmK+Uv8m+y8vLy8vLy8vLy8vLAAAAwcK8y8vLy8vLy8vLy8vLy8vLsMivN9AuA+gACvMACPcACvMAA+gACLUAPps2tLisy8vLy8vLy8vLAAAAnpVNycnFy8vLy8vLy8vLpcmjE9cGAvsAE/4GE/4GE/4GE/4GE/4GFPQGAsUAHJAWtbOzy8vLy8vLAAAAtagDnZx1y8vLy8vLv8m+L9cmAvsAE/4GE/4GE/4GE/4GE/4GE/4GE/4GFPQGCLUAQo88wcK8y8vLAAAAzsEHlokgwcK8y8vLi8qHAvsAE/4GE/4GE/4GE/4GE/4GE/4GE/4GE/4GE/4GE9cGBpIAiKeEy8vLAAAA3dAEn5ERsLCXxMnCVtJSAvsAFf4IE/4GE/4GE/4GE/4GE/4GE/4GE/4GE/4GE+kGCKUCW5JUy8vLAAAA5NgHo5UGn6BysMivONQyCPcAFf4IE/4GE/4GE/4GE/4GE/4GE/4GE/4GE/4GE+kGCKUCS5FEy8vLAAAA3dAEo5UGnZx1sMivONQyCPcAE/4GE/4GE/4GE/4GE/4GE/4GE/4GE/4GE/4GEeIIC5gAS5FEy8vLAAAAx7kFlok
 gqqqLwcK8TsRKCvMAE/4GE/4GE/4GE/4GE/4GE/4GE/4GE/4GFPQGE9cGBpIAW5JUy8vLAAAAtagDh3oRt8W2y8vLfK53B9YAE/4GE/4GE/4GE/4GE/4GE/4GE/4GE/4GEeIIEbsEBX4BfJ53y8vLAAAAk4YHlIxSy8vLy8vLt8W2GqoPA+gAE/4GE/4GE/4GE/4GE/4GFPQGE+kGFMcHBpIAI3EdqrWoy8vLAAAAhnwtvLq7y8vLy8vLy8vLiKeECKUCB9YAE+kGFPQGFPQGE+kGE9cGEbsEC5gAEnENkaeOy8vLy8vLAAAAtLisy8vLy8vLy8vLy8vLyMfJfJ53LYImCKUCCLUAEbsECLUACKUCBX4BI3EdkaeOy8vLy8vLy8vLAAAAy8vLy8vLy8vLy8vLy8vLy8vLy8vLmK+UYJRaOYUyKnsiKnsiPXw1YYdbqrWoy8vLy8vLy8vLy8vLAAAAy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLtbOzqrWoq6eltLisyMfJy8vLy8vLy8vLy8vLy8vLAAAAy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8tYQwAA]]] Yes\n"
+				      "- List item --One--\n"
+				      "- \n"
+				      "- List item **Two**\n"
+				      " - sub1\n"
+				      " - sub2\n\n"
+				      "multi line markup **starting here\nand ending here**\n"
+				      "multi line markup **starting here**\n**and ending here**\nnot here"
+				      "A Line with **formatting -- error **\n",
+				      -1);
+	button = gtk_button_new_with_label ("Copy");
+	gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 5);
+	g_signal_connect (button, "clicked",
+			  G_CALLBACK (copy_cb), rte);
+
+	rte = gdaui_rt_editor_new ();
+	gtk_box_pack_start (GTK_BOX (vbox), rte, TRUE, TRUE, 0);
+	gdaui_rt_editor_set_editable (GDAUI_RT_EDITOR (rte), FALSE);
+	g_object_set_data (G_OBJECT (button), "destrte", rte);
+
+	return p_win;
+}
+
+/*
+ * Entree du programme:
+ */
+int main (int argc, char ** argv)
+{
+	gtk_init (& argc, & argv);
+
+	/*
+	 * Creation et mise en place de la fenetre:
+	 */
+	gtk_widget_show_all (create_window ());
+	gtk_main ();
+
+	return 0;
+}



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