aboutsummaryrefslogtreecommitdiffstats
path: root/e-util/e-spell-checker.c
diff options
context:
space:
mode:
Diffstat (limited to 'e-util/e-spell-checker.c')
-rw-r--r--e-util/e-spell-checker.c783
1 files changed, 783 insertions, 0 deletions
diff --git a/e-util/e-spell-checker.c b/e-util/e-spell-checker.c
new file mode 100644
index 0000000000..c781672103
--- /dev/null
+++ b/e-util/e-spell-checker.c
@@ -0,0 +1,783 @@
+/*
+ * e-spell-checker.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-spell-checker.h"
+#include "e-spell-dictionary.h"
+
+#include <libebackend/libebackend.h>
+#include <webkit/webkitspellchecker.h>
+#include <pango/pango.h>
+#include <gtk/gtk.h>
+#include <string.h>
+
+#define E_SPELL_CHECKER_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_SPELL_CHECKER, ESpellCheckerPrivate))
+
+#define MAX_SUGGESTIONS 10
+
+struct _ESpellCheckerPrivate {
+ EnchantBroker *broker;
+ GHashTable *active_dictionaries;
+ GHashTable *dictionaries_cache;
+ gboolean dictionaries_loaded;
+
+ /* We retain ownership of the EnchantDict's since they
+ * have to be freed through enchant_broker_free_dict()
+ * and we also own the EnchantBroker. */
+ GHashTable *enchant_dicts;
+};
+
+enum {
+ PROP_0,
+ PROP_ACTIVE_LANGUAGES
+};
+
+/* Forward Declarations */
+static void e_spell_checker_init_webkit_checker
+ (WebKitSpellCheckerInterface *interface);
+
+G_DEFINE_TYPE_EXTENDED (
+ ESpellChecker,
+ e_spell_checker,
+ G_TYPE_OBJECT,
+ 0,
+ G_IMPLEMENT_INTERFACE (
+ E_TYPE_EXTENSIBLE, NULL)
+ G_IMPLEMENT_INTERFACE (
+ WEBKIT_TYPE_SPELL_CHECKER,
+ e_spell_checker_init_webkit_checker))
+
+/**
+ * ESpellChecker:
+ *
+ * #ESpellChecker represents a spellchecker in Evolution. It can be used as a
+ * provider for dictionaries. It also implements #WebKitSpellCheckerInterface,
+ * so it can be set as a default spell-checker to WebKit editors
+ */
+
+static gboolean
+spell_checker_enchant_dicts_foreach_cb (gpointer key,
+ gpointer value,
+ gpointer user_data)
+{
+ EnchantDict *enchant_dict = value;
+ EnchantBroker *enchant_broker = user_data;
+
+ enchant_broker_free_dict (enchant_broker, enchant_dict);
+
+ return TRUE;
+}
+
+static void
+wksc_check_spelling (WebKitSpellChecker *webkit_checker,
+ const gchar *word,
+ gint *misspelling_location,
+ gint *misspelling_length)
+{
+ ESpellChecker *checker = E_SPELL_CHECKER (webkit_checker);
+ GHashTable *active_dictionaries;
+ PangoLanguage *language;
+ PangoLogAttr *attrs;
+ gint length, ii;
+
+ active_dictionaries = checker->priv->active_dictionaries;
+ if (g_hash_table_size (active_dictionaries) == 0)
+ return;
+
+ length = g_utf8_strlen (word, -1);
+
+ language = pango_language_get_default ();
+ attrs = g_new (PangoLogAttr, length + 1);
+
+ pango_get_log_attrs (word, -1, -1, language, attrs, length + 1);
+
+ for (ii = 0; ii < length + 1; ii++) {
+ /* We go through each character until we find an is_word_start,
+ * then we get into an inner loop to find the is_word_end
+ * corresponding */
+ if (attrs[ii].is_word_start) {
+ gboolean word_recognized;
+ gint start = ii;
+ gint end = ii;
+ gint word_length;
+ gchar *cstart;
+ gint bytes;
+ gchar *new_word;
+
+ while (attrs[end].is_word_end < 1)
+ end++;
+
+ word_length = end - start;
+ /* Set the iterator to be at the current word
+ * end, so we don't check characters twice. */
+ ii = end;
+
+ cstart = g_utf8_offset_to_pointer (word, start);
+ bytes = g_utf8_offset_to_pointer (word, end) - cstart;
+ new_word = g_new0 (gchar, bytes + 1);
+
+ g_utf8_strncpy (new_word, cstart, word_length);
+
+ word_recognized = e_spell_checker_check_word (
+ checker, new_word, strlen (new_word));
+
+ if (word_recognized) {
+ if (misspelling_location != NULL)
+ *misspelling_location = -1;
+ if (misspelling_length != NULL)
+ *misspelling_length = 0;
+ } else {
+ if (misspelling_location != NULL)
+ *misspelling_location = start;
+ if (misspelling_length != NULL)
+ *misspelling_length = word_length;
+ }
+
+ g_free (new_word);
+ }
+ }
+
+ g_free (attrs);
+}
+
+static gchar **
+wksc_get_guesses (WebKitSpellChecker *webkit_checker,
+ const gchar *word,
+ const gchar *context)
+{
+ ESpellChecker *checker = E_SPELL_CHECKER (webkit_checker);
+ GHashTable *active_dictionaries;
+ GList *list, *link;
+ gchar ** guesses;
+ gint ii = 0;
+
+ guesses = g_new0 (gchar *, MAX_SUGGESTIONS + 1);
+
+ active_dictionaries = checker->priv->active_dictionaries;
+ list = g_hash_table_get_keys (active_dictionaries);
+
+ for (link = list; link != NULL; link = g_list_next (link)) {
+ ESpellDictionary *dictionary;
+ GList *suggestions;
+
+ dictionary = E_SPELL_DICTIONARY (link->data);
+ suggestions = e_spell_dictionary_get_suggestions (
+ dictionary, word, -1);
+
+ while (suggestions != NULL && ii < MAX_SUGGESTIONS) {
+ guesses[ii++] = suggestions->data;
+ suggestions->data = NULL;
+
+ suggestions = g_list_delete_link (
+ suggestions, suggestions);
+ }
+
+ g_list_free_full (suggestions, (GDestroyNotify) g_free);
+
+ if (ii >= MAX_SUGGESTIONS)
+ break;
+ }
+
+ g_list_free (list);
+
+ return guesses;
+}
+
+static gchar *
+wksc_get_autocorrect_suggestions (WebKitSpellChecker *webkit_checker,
+ const gchar *word)
+{
+ /* Not supported/needed */
+ return NULL;
+}
+
+static void
+spell_checker_learn_word (WebKitSpellChecker *webkit_checker,
+ const gchar *word)
+{
+ /* Carefully, this will add the word to all active dictionaries! */
+
+ ESpellChecker *checker;
+ GHashTable *active_dictionaries;
+ GList *list, *link;
+
+ checker = E_SPELL_CHECKER (webkit_checker);
+ active_dictionaries = checker->priv->active_dictionaries;
+ list = g_hash_table_get_keys (active_dictionaries);
+
+ for (link = list; link != NULL; link = g_list_next (link)) {
+ ESpellDictionary *dictionary;
+
+ dictionary = E_SPELL_DICTIONARY (link->data);
+ e_spell_dictionary_learn_word (dictionary, word, -1);
+ }
+
+ g_list_free (list);
+}
+
+static void
+spell_checker_ignore_word (WebKitSpellChecker *webkit_checker,
+ const gchar *word)
+{
+ /* Carefully, this will add the word to all active dictionaries */
+
+ ESpellChecker *checker;
+ GHashTable *active_dictionaries;
+ GList *list, *link;
+
+ checker = E_SPELL_CHECKER (webkit_checker);
+ active_dictionaries = checker->priv->active_dictionaries;
+ list = g_hash_table_get_keys (active_dictionaries);
+
+ for (link = list; link != NULL; link = g_list_next (link)) {
+ ESpellDictionary *dictionary;
+
+ dictionary = E_SPELL_DICTIONARY (link->data);
+ e_spell_dictionary_ignore_word (dictionary, word, -1);
+ }
+
+ g_list_free (list);
+}
+
+static void
+wksc_update_languages (WebKitSpellChecker *webkit_checker,
+ const gchar *languages)
+{
+ ESpellChecker *checker;
+ GHashTable *active_dictionaries;
+ GQueue queue = G_QUEUE_INIT;
+
+ checker = E_SPELL_CHECKER (webkit_checker);
+ active_dictionaries = checker->priv->active_dictionaries;
+
+ if (languages != NULL) {
+ gchar **langs;
+ gint ii;
+
+ langs = g_strsplit (languages, ",", -1);
+ for (ii = 0; langs[ii] != NULL; ii++) {
+ ESpellDictionary *dictionary;
+
+ dictionary = e_spell_checker_ref_dictionary (
+ checker, langs[ii]);
+ if (dictionary != NULL)
+ g_queue_push_tail (&queue, dictionary);
+ }
+ g_strfreev (langs);
+ } else {
+ ESpellDictionary *dictionary;
+ PangoLanguage *pango_language;
+ const gchar *language;
+
+ pango_language = gtk_get_default_language ();
+ language = pango_language_to_string (pango_language);
+ dictionary = e_spell_checker_ref_dictionary (checker, language);
+
+ if (dictionary == NULL) {
+ GList *list;
+
+ list = e_spell_checker_list_available_dicts (checker);
+ if (list != NULL) {
+ dictionary = g_object_ref (list->data);
+ g_list_free (list);
+ }
+ }
+
+ if (dictionary != NULL)
+ g_queue_push_tail (&queue, dictionary);
+ }
+
+ g_hash_table_remove_all (active_dictionaries);
+
+ while (!g_queue_is_empty (&queue)) {
+ ESpellDictionary *dictionary;
+
+ dictionary = g_queue_pop_head (&queue);
+ g_hash_table_add (active_dictionaries, dictionary);
+ }
+
+ g_object_notify (G_OBJECT (checker), "active-languages");
+}
+
+static void
+spell_checker_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_ACTIVE_LANGUAGES:
+ g_value_take_boxed (
+ value,
+ e_spell_checker_list_active_languages (
+ E_SPELL_CHECKER (object), NULL));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+spell_checker_dispose (GObject *object)
+{
+ ESpellCheckerPrivate *priv;
+
+ priv = E_SPELL_CHECKER_GET_PRIVATE (object);
+
+ g_hash_table_remove_all (priv->active_dictionaries);
+ g_hash_table_remove_all (priv->dictionaries_cache);
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (e_spell_checker_parent_class)->dispose (object);
+}
+
+static void
+spell_checker_finalize (GObject *object)
+{
+ ESpellCheckerPrivate *priv;
+
+ priv = E_SPELL_CHECKER_GET_PRIVATE (object);
+
+ /* Freeing EnchantDicts requires help from EnchantBroker. */
+ g_hash_table_foreach_remove (
+ priv->enchant_dicts,
+ spell_checker_enchant_dicts_foreach_cb,
+ priv->broker);
+ g_hash_table_destroy (priv->enchant_dicts);
+
+ enchant_broker_free (priv->broker);
+
+ g_hash_table_destroy (priv->active_dictionaries);
+ g_hash_table_destroy (priv->dictionaries_cache);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (e_spell_checker_parent_class)->finalize (object);
+}
+
+static void
+spell_checker_constructed (GObject *object)
+{
+ /* Chain up to parent's constructed() method. */
+ G_OBJECT_CLASS (e_spell_checker_parent_class)->constructed (object);
+
+ e_extensible_load_extensions (E_EXTENSIBLE (object));
+}
+
+static void
+e_spell_checker_class_init (ESpellCheckerClass *class)
+{
+ GObjectClass *object_class;
+
+ g_type_class_add_private (class, sizeof (ESpellCheckerPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->get_property = spell_checker_get_property;
+ object_class->dispose = spell_checker_dispose;
+ object_class->finalize = spell_checker_finalize;
+ object_class->constructed = spell_checker_constructed;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_ACTIVE_LANGUAGES,
+ g_param_spec_boxed (
+ "active-languages",
+ "Active Languages",
+ "Active spell check language codes",
+ G_TYPE_STRV,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+}
+
+static void
+e_spell_checker_init_webkit_checker (WebKitSpellCheckerInterface *interface)
+{
+ interface->check_spelling_of_string = wksc_check_spelling;
+ interface->get_autocorrect_suggestions_for_misspelled_word =
+ wksc_get_autocorrect_suggestions;
+ interface->get_guesses_for_word = wksc_get_guesses;
+ interface->ignore_word = spell_checker_ignore_word;
+ interface->learn_word = spell_checker_learn_word;
+ interface->update_spell_checking_languages = wksc_update_languages;
+}
+
+static void
+e_spell_checker_init (ESpellChecker *checker)
+{
+ GHashTable *active_dictionaries;
+ GHashTable *dictionaries_cache;
+ GHashTable *enchant_dicts;
+
+ active_dictionaries = g_hash_table_new_full (
+ (GHashFunc) e_spell_dictionary_hash,
+ (GEqualFunc) e_spell_dictionary_equal,
+ (GDestroyNotify) g_object_unref,
+ (GDestroyNotify) NULL);
+
+ dictionaries_cache = g_hash_table_new_full (
+ (GHashFunc) g_str_hash,
+ (GEqualFunc) g_str_equal,
+ (GDestroyNotify) NULL,
+ (GDestroyNotify) g_object_unref);
+
+ enchant_dicts = g_hash_table_new_full (
+ (GHashFunc) g_str_hash,
+ (GEqualFunc) g_str_equal,
+ (GDestroyNotify) g_free,
+ (GDestroyNotify) NULL);
+
+ checker->priv = E_SPELL_CHECKER_GET_PRIVATE (checker);
+
+ checker->priv->broker = enchant_broker_init ();
+ checker->priv->active_dictionaries = active_dictionaries;
+ checker->priv->dictionaries_cache = dictionaries_cache;
+ checker->priv->enchant_dicts = enchant_dicts;
+}
+
+/**
+ * e_spell_checker_new:
+ *
+ * Creates a new #ESpellChecker instance.
+ *
+ * Returns: a new #ESpellChecker
+ **/
+ESpellChecker *
+e_spell_checker_new (void)
+{
+ return g_object_new (E_TYPE_SPELL_CHECKER, NULL);
+}
+
+static void
+list_enchant_dicts (const gchar * const lang_tag,
+ const gchar * const provider_name,
+ const gchar * const provider_desc,
+ const gchar * const provider_file,
+ gpointer user_data)
+{
+ ESpellChecker *checker = user_data;
+ EnchantDict *enchant_dict;
+
+ enchant_dict = enchant_broker_request_dict (
+ checker->priv->broker, lang_tag);
+ if (enchant_dict != NULL) {
+ ESpellDictionary *dictionary;
+ const gchar *code;
+
+ /* Note that we retain ownership of the EnchantDict.
+ * Since EnchantDict is not reference counted, we're
+ * merely loaning the pointer to ESpellDictionary. */
+ dictionary = e_spell_dictionary_new (checker, enchant_dict);
+ code = e_spell_dictionary_get_code (dictionary);
+
+ g_hash_table_insert (
+ checker->priv->dictionaries_cache,
+ (gpointer) code, dictionary);
+
+ g_hash_table_insert (
+ checker->priv->enchant_dicts,
+ g_strdup (code), enchant_dict);
+ }
+}
+
+/**
+ * e_spell_checker_list_available_dicts:
+ * @checker: An #ESpellChecker
+ *
+ * Returns list of all dictionaries available to the actual
+ * spell-checking backend.
+ *
+ * Returns: new copy of #GList of #ESpellDictionary. The dictionaries are
+ * owned by the @checker and should not be free'd. The list should be freed
+ * using g_list_free() when not neede anymore. [transfer-list]
+ */
+GList *
+e_spell_checker_list_available_dicts (ESpellChecker *checker)
+{
+ GList *list;
+
+ g_return_val_if_fail (E_IS_SPELL_CHECKER (checker), NULL);
+
+ if (!checker->priv->dictionaries_loaded) {
+ enchant_broker_list_dicts (
+ checker->priv->broker,
+ list_enchant_dicts, checker);
+ checker->priv->dictionaries_loaded = TRUE;
+ }
+
+ list = g_hash_table_get_values (checker->priv->dictionaries_cache);
+
+ return g_list_sort (list, (GCompareFunc) e_spell_dictionary_compare);
+}
+
+/**
+ * e_spell_checker_ref_dictionary:
+ * @checker: an #ESpellChecker
+ * @language_code: (allow-none): language code of a dictionary, or %NULL
+ *
+ * Tries to find an #ESpellDictionary for given @language_code.
+ * If @language_code is %NULL, the function will return a default
+ * #ESpellDictionary.
+ *
+ * Returns: an #ESpellDictionary for @language_code
+ */
+ESpellDictionary *
+e_spell_checker_ref_dictionary (ESpellChecker *checker,
+ const gchar *language_code)
+{
+ ESpellDictionary *dictionary;
+ GList *list;
+
+ g_return_val_if_fail (E_IS_SPELL_CHECKER (checker), NULL);
+
+ /* If the cache has not yet been initialized, do so - we will need
+ * it anyway, Otherwise is this call very cheap */
+ list = e_spell_checker_list_available_dicts (checker);
+
+ if (language_code == NULL) {
+ dictionary = (list != NULL) ? list->data : NULL;
+ } else {
+ dictionary = g_hash_table_lookup (
+ checker->priv->dictionaries_cache,
+ language_code);
+ }
+
+ if (dictionary != NULL)
+ g_object_ref (dictionary);
+
+ g_list_free (list);
+
+ return dictionary;
+}
+
+/**
+ * e_spell_checker_get_enchant_dict:
+ * @checker: an #ESpellChecker
+ * @language_code: language code of a dictionary, or %NULL
+ *
+ * Returns the #EnchantDict for @language_code, or %NULL if there is none.
+ *
+ * Returns: the #EnchantDict for @language_code, or %NULL
+ **/
+EnchantDict *
+e_spell_checker_get_enchant_dict (ESpellChecker *checker,
+ const gchar *language_code)
+{
+ g_return_val_if_fail (E_IS_SPELL_CHECKER (checker), NULL);
+ g_return_val_if_fail (language_code != NULL, NULL);
+
+ return g_hash_table_lookup (
+ checker->priv->enchant_dicts, language_code);
+}
+
+gboolean
+e_spell_checker_get_language_active (ESpellChecker *checker,
+ const gchar *language_code)
+{
+ ESpellDictionary *dictionary;
+ GHashTable *active_dictionaries;
+ gboolean active;
+
+ g_return_val_if_fail (E_IS_SPELL_CHECKER (checker), FALSE);
+ g_return_val_if_fail (language_code != NULL, FALSE);
+
+ dictionary = e_spell_checker_ref_dictionary (checker, language_code);
+ g_return_val_if_fail (dictionary != NULL, FALSE);
+
+ active_dictionaries = checker->priv->active_dictionaries;
+ active = g_hash_table_contains (active_dictionaries, dictionary);
+
+ g_object_unref (dictionary);
+
+ return active;
+}
+
+void
+e_spell_checker_set_language_active (ESpellChecker *checker,
+ const gchar *language_code,
+ gboolean active)
+{
+ ESpellDictionary *dictionary;
+ GHashTable *active_dictionaries;
+ gboolean is_active;
+
+ g_return_if_fail (E_IS_SPELL_CHECKER (checker));
+ g_return_if_fail (language_code != NULL);
+
+ dictionary = e_spell_checker_ref_dictionary (checker, language_code);
+ g_return_if_fail (dictionary != NULL);
+
+ active_dictionaries = checker->priv->active_dictionaries;
+ is_active = g_hash_table_contains (active_dictionaries, dictionary);
+
+ if (active && !is_active) {
+ g_object_ref (dictionary);
+ g_hash_table_add (active_dictionaries, dictionary);
+ g_object_notify (G_OBJECT (checker), "active-languages");
+ } else if (!active && is_active) {
+ g_hash_table_remove (active_dictionaries, dictionary);
+ g_object_notify (G_OBJECT (checker), "active-languages");
+ }
+
+ g_object_unref (dictionary);
+}
+
+/**
+ * e_spell_checker_list_active_languages:
+ * @checker: an #ESpellChecker
+ * @n_languages: return location for the number of active languages, or %NULL
+ *
+ * Returns a %NULL-terminated array of language codes actively being used
+ * for spell checking. Free the returned array with g_strfreev().
+ *
+ * Returns: a %NULL-teriminated array of language codes
+ **/
+gchar **
+e_spell_checker_list_active_languages (ESpellChecker *checker,
+ guint *n_languages)
+{
+ GHashTable *active_dictionaries;
+ GList *list, *link;
+ gchar **active_languages;
+ guint size;
+ gint ii = 0;
+
+ g_return_val_if_fail (E_IS_SPELL_CHECKER (checker), NULL);
+
+ active_dictionaries = checker->priv->active_dictionaries;
+ list = g_hash_table_get_keys (active_dictionaries);
+ size = g_hash_table_size (active_dictionaries);
+
+ active_languages = g_new0 (gchar *, size + 1);
+
+ list = g_list_sort (list, (GCompareFunc) e_spell_dictionary_compare);
+
+ for (link = list; link != NULL; link = g_list_next (link)) {
+ ESpellDictionary *dictionary;
+ const gchar *language_code;
+
+ dictionary = E_SPELL_DICTIONARY (link->data);
+ language_code = e_spell_dictionary_get_code (dictionary);
+ active_languages[ii++] = g_strdup (language_code);
+ }
+
+ if (n_languages != NULL)
+ *n_languages = size;
+
+ g_list_free (list);
+
+ return active_languages;
+}
+
+/**
+ * e_spell_checker_count_active_languages:
+ * @checker: an #ESpellChecker
+ *
+ * Returns the number of languages actively being used for spell checking.
+ *
+ * Returns: number of active spell checking languages
+ **/
+guint
+e_spell_checker_count_active_languages (ESpellChecker *checker)
+{
+ g_return_val_if_fail (E_IS_SPELL_CHECKER (checker), 0);
+
+ return g_hash_table_size (checker->priv->active_dictionaries);
+}
+
+/**
+ * e_spell_checker_check_word:
+ * @checker: an #SpellChecker
+ * @word: a word to spell-check
+ * @length: length of @word in bytes or -1 when %NULL-terminated
+ *
+ * Calls e_spell_dictionary_check_word() on all active dictionaries in
+ * @checker, and returns %TRUE if @word is recognized by any of them.
+ *
+ * Returns: %TRUE if @word is recognized, %FALSE otherwise
+ **/
+gboolean
+e_spell_checker_check_word (ESpellChecker *checker,
+ const gchar *word,
+ gsize length)
+{
+ GList *list, *link;
+ gboolean recognized = FALSE;
+
+ g_return_val_if_fail (E_IS_SPELL_CHECKER (checker), TRUE);
+ g_return_val_if_fail (word != NULL && *word != '\0', TRUE);
+
+ list = g_hash_table_get_keys (checker->priv->active_dictionaries);
+
+ for (link = list; link != NULL; link = g_list_next (link)) {
+ ESpellDictionary *dictionary;
+
+ dictionary = E_SPELL_DICTIONARY (link->data);
+ if (e_spell_dictionary_check_word (dictionary, word, length)) {
+ recognized = TRUE;
+ break;
+ }
+ }
+
+ g_list_free (list);
+
+ return recognized;
+}
+
+/**
+ * e_spell_checker_ignore_word:
+ * @checker: an #ESpellChecker
+ * @word: word to ignore for the rest of session
+ *
+ * Calls e_spell_dictionary_ignore_word() on all active dictionaries in
+ * the @checker.
+ */
+void
+e_spell_checker_ignore_word (ESpellChecker *checker,
+ const gchar *word)
+{
+ WebKitSpellCheckerInterface *interface;
+
+ g_return_if_fail (E_IS_SPELL_CHECKER (checker));
+
+ interface = WEBKIT_SPELL_CHECKER_GET_IFACE (checker);
+ interface->ignore_word (WEBKIT_SPELL_CHECKER (checker), word);
+}
+
+/**
+ * e_spell_checker_learn_word:
+ * @checker: an #ESpellChecker
+ * @word: word to learn
+ *
+ * Calls e_spell_dictionary_learn_word() on all active dictionaries in
+ * the @checker.
+ */
+void
+e_spell_checker_learn_word (ESpellChecker *checker,
+ const gchar *word)
+{
+ WebKitSpellCheckerInterface *interface;
+
+ g_return_if_fail (E_IS_SPELL_CHECKER (checker));
+
+ interface = WEBKIT_SPELL_CHECKER_GET_IFACE (checker);
+ interface->learn_word (WEBKIT_SPELL_CHECKER (checker), word);
+}