[evolution/wip/webkit-composer: 128/372] Move spell-checking parts to e-util
- From: Tomas Popela <tpopela src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution/wip/webkit-composer: 128/372] Move spell-checking parts to e-util
- Date: Thu, 6 Feb 2014 11:34:16 +0000 (UTC)
commit 468b9878adbf9541bcbc68c24d165265d70f4c64
Author: Dan Vrátil <dvratil redhat com>
Date: Mon Aug 27 11:46:46 2012 +0200
Move spell-checking parts to e-util
e-util/Makefile.am | 10 +-
e-util/e-editor-actions.c | 61 ++--
e-util/e-editor-spell-check-dialog.c | 9 +-
e-util/e-editor-spell-checker.c | 708 ----------------------------------
e-util/e-editor-spell-checker.h | 85 ----
e-util/e-editor-widget.c | 12 +-
e-util/e-editor-widget.h | 4 +
e-util/e-editor.c | 45 +--
e-util/e-spell-checker.c | 521 +++++++++++++++++++++++++
e-util/e-spell-checker.h | 86 ++++
e-util/e-spell-dictionary.c | 651 +++++++++++++++++++++++++++++++
e-util/e-spell-dictionary.h | 104 +++++
e-util/e-util.h | 1 -
13 files changed, 1433 insertions(+), 864 deletions(-)
---
diff --git a/e-util/Makefile.am b/e-util/Makefile.am
index 1facc83..2ce4f09 100644
--- a/e-util/Makefile.am
+++ b/e-util/Makefile.am
@@ -102,7 +102,7 @@ libevolution_util_la_CPPFLAGS = \
$(GNOME_PLATFORM_CFLAGS) \
$(GEO_CFLAGS) \
$(GTKHTML_CFLAGS) \
- $(GTKSPELL_CFLAGS) \
+ $(ENCHANT_CFLAGS) \
$(NULL)
evolution_util_include_HEADERS = \
@@ -188,7 +188,6 @@ evolution_util_include_HEADERS = \
e-editor-replace-dialog.h \
e-editor-selection.h \
e-editor-spell-check-dialog.h \
- e-editor-spell-checker.h \
e-editor-table-dialog.h \
e-editor-text-dialog.h \
e-editor-utils.h \
@@ -279,6 +278,8 @@ evolution_util_include_HEADERS = \
e-source-selector-dialog.h \
e-source-selector.h \
e-source-util.h \
+ e-spell-checker.h \
+ e-spell-dictionary.h \
e-spell-entry.h \
e-spell-text-view.h \
e-stock-request.h \
@@ -460,7 +461,6 @@ libevolution_util_la_SOURCES = \
e-editor-replace-dialog.c \
e-editor-selection.c \
e-editor-spell-check-dialog.c \
- e-editor-spell-checker.c \
e-editor-table-dialog.c \
e-editor-text-dialog.c \
e-editor-utils.c \
@@ -551,6 +551,8 @@ libevolution_util_la_SOURCES = \
e-source-selector-dialog.c \
e-source-selector.c \
e-source-util.c \
+ e-spell-checker.c \
+ e-spell-dictionary.c \
e-spell-entry.c \
e-spell-text-view.c \
e-stock-request.c \
@@ -645,7 +647,7 @@ libevolution_util_la_LIBADD = \
$(GNOME_PLATFORM_LIBS) \
$(GEO_LIBS) \
$(GTKHTML_LIBS) \
- $(GTKSPELL_LIBS) \
+ $(ENCHANT_LIBS) \
$(INTLLIBS) \
$(MATH_LIB) \
$(NULL)
diff --git a/e-util/e-editor-actions.c b/e-util/e-editor-actions.c
index c8b239d..8121c59 100644
--- a/e-util/e-editor-actions.c
+++ b/e-util/e-editor-actions.c
@@ -22,15 +22,16 @@
#include <gio/gio.h>
#include <glib/gi18n-lib.h>
#include <string.h>
+#include <enchant/enchant.h>
#include "e-editor.h"
#include "e-editor-private.h"
#include "e-editor-actions.h"
-#include "e-editor-spell-checker.h"
#include "e-editor-utils.h"
#include "e-emoticon-action.h"
#include "e-emoticon-chooser.h"
#include "e-image-chooser-dialog.h"
+#include "e-spell-checker.h"
static void
insert_html_file_ready_cb (GFile *file,
@@ -367,16 +368,16 @@ static void
action_context_spell_add_cb (GtkAction *action,
EEditor *editor)
{
- WebKitSpellChecker *spell_checker;
+ ESpellChecker *spell_checker;
EEditorSelection *selection;
gchar *word;
- spell_checker = WEBKIT_SPELL_CHECKER (webkit_get_text_checker ());
+ spell_checker = e_editor_widget_get_spell_checker (editor->priv->editor_widget);
selection = e_editor_widget_get_selection (editor->priv->editor_widget);
word = e_editor_selection_get_caret_word (selection);
if (word && *word) {
- webkit_spell_checker_learn_word (spell_checker, word);
+ e_spell_checker_learn_word (spell_checker, word);
}
}
@@ -384,16 +385,16 @@ static void
action_context_spell_ignore_cb (GtkAction *action,
EEditor *editor)
{
- WebKitSpellChecker *spell_checker;
+ ESpellChecker *spell_checker;
EEditorSelection *selection;
gchar *word;
- spell_checker = WEBKIT_SPELL_CHECKER (webkit_get_text_checker ());
+ spell_checker = e_editor_widget_get_spell_checker (editor->priv->editor_widget);
selection = e_editor_widget_get_selection (editor->priv->editor_widget);
word = e_editor_selection_get_caret_word (selection);
if (word && *word) {
- webkit_spell_checker_ignore_word (spell_checker, word);
+ e_spell_checker_ignore_word (spell_checker, word);
}
}
@@ -574,8 +575,8 @@ static void
action_language_cb (GtkToggleAction *action,
EEditor *editor)
{
- EEditorSpellChecker *checker;
- EnchantDict *dictionary;
+ ESpellChecker *checker;
+ ESpellDictionary *dictionary;
const gchar *language_code;
GtkAction *add_action;
GList *list;
@@ -583,23 +584,23 @@ action_language_cb (GtkToggleAction *action,
gchar *action_name;
gboolean active;
- checker = E_EDITOR_SPELL_CHECKER (webkit_get_text_checker ());
+ checker = e_editor_widget_get_spell_checker (editor->priv->editor_widget);
active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
language_code = gtk_action_get_name (GTK_ACTION (action));
- dictionary = e_editor_spell_checker_lookup_dict (checker, language_code);
+ dictionary = e_spell_checker_lookup_dictionary (checker, language_code);
/* Update the list of active dictionaries */
list = editor->priv->active_dictionaries;
if (active)
list = g_list_insert_sorted (
list, (EnchantDict *) dictionary,
- (GCompareFunc) e_editor_spell_checker_dict_compare);
+ (GCompareFunc) e_spell_dictionary_compare);
else {
GList *link;
link = g_list_find (list, dictionary);
g_return_if_fail (link != NULL);
- e_editor_spell_checker_free_dict (checker, link->data);
+ g_object_unref (link->data);
list = g_list_delete_link (list, link);
}
editor->priv->active_dictionaries = list;
@@ -619,7 +620,7 @@ action_language_cb (GtkToggleAction *action,
e_editor_emit_spell_languages_changed (editor);
- e_editor_spell_checker_free_dict (checker, dictionary);
+ g_object_unref (dictionary);
}
struct _ModeChanged {
@@ -1677,7 +1678,7 @@ static GtkActionEntry spell_context_entries[] = {
static void
editor_actions_setup_languages_menu (EEditor *editor)
{
- EEditorSpellChecker *checker;
+ ESpellChecker *checker;
GtkUIManager *manager;
GtkActionGroup *action_group;
GList *available_dicts, *iter;
@@ -1685,17 +1686,17 @@ editor_actions_setup_languages_menu (EEditor *editor)
manager = editor->priv->manager;
action_group = editor->priv->language_actions;
- checker = E_EDITOR_SPELL_CHECKER (webkit_get_text_checker ());
- available_dicts = e_editor_spell_checker_get_available_dicts (checker);
+ checker = e_editor_widget_get_spell_checker (editor->priv->editor_widget);
+ available_dicts = e_spell_checker_list_available_dicts (checker);
merge_id = gtk_ui_manager_new_merge_id (manager);
for (iter = available_dicts; iter; iter = iter->next) {
- EnchantDict *dictionary = iter->data;
+ ESpellDictionary *dictionary = iter->data;
GtkToggleAction *action;
action = gtk_toggle_action_new (
- e_editor_spell_checker_get_dict_code (dictionary),
- e_editor_spell_checker_get_dict_name (dictionary),
+ e_spell_dictionary_get_code (dictionary),
+ e_spell_dictionary_get_name (dictionary),
NULL, NULL);
g_signal_connect (
@@ -1710,11 +1711,11 @@ editor_actions_setup_languages_menu (EEditor *editor)
gtk_ui_manager_add_ui (
manager, merge_id,
"/main-menu/edit-menu/language-menu",
- e_editor_spell_checker_get_dict_code (dictionary),
- e_editor_spell_checker_get_dict_code (dictionary),
+ e_spell_dictionary_get_code (dictionary),
+ e_spell_dictionary_get_code (dictionary),
GTK_UI_MANAGER_AUTO, FALSE);
- e_editor_spell_checker_free_dict (checker, dictionary);
+ g_object_unref (dictionary);
}
g_list_free (available_dicts);
@@ -1723,7 +1724,7 @@ editor_actions_setup_languages_menu (EEditor *editor)
static void
editor_actions_setup_spell_check_menu (EEditor *editor)
{
- EEditorSpellChecker *checker;
+ ESpellChecker *checker;
GtkUIManager *manager;
GtkActionGroup *action_group;
GList *available_dicts, *iter;
@@ -1731,20 +1732,20 @@ editor_actions_setup_spell_check_menu (EEditor *editor)
manager = editor->priv->manager;
action_group = editor->priv->spell_check_actions;;
- checker = E_EDITOR_SPELL_CHECKER (webkit_get_text_checker ());
- available_dicts = e_editor_spell_checker_get_available_dicts (checker);
+ checker = e_editor_widget_get_spell_checker (editor->priv->editor_widget);
+ available_dicts = e_spell_checker_list_available_dicts (checker);
merge_id = gtk_ui_manager_new_merge_id (manager);
for (iter = available_dicts; iter; iter = iter->next) {
- EnchantDict *dictionary = iter->data;
+ ESpellDictionary *dictionary = iter->data;
GtkAction *action;
const gchar *code;
const gchar *name;
gchar *action_label;
gchar *action_name;
- code = e_editor_spell_checker_get_dict_code (dictionary);
- name = e_editor_spell_checker_get_dict_name (dictionary);
+ code = e_spell_dictionary_get_code (dictionary);
+ name = e_spell_dictionary_get_name (dictionary);
/* Add a suggestion menu. */
action_name = g_strdup_printf (
@@ -1790,7 +1791,7 @@ editor_actions_setup_spell_check_menu (EEditor *editor)
action_name, action_name,
GTK_UI_MANAGER_AUTO, FALSE);
- e_editor_spell_checker_free_dict (checker, dictionary);
+ g_object_unref (dictionary);
g_free (action_label);
g_free (action_name);
}
diff --git a/e-util/e-editor-spell-check-dialog.c b/e-util/e-editor-spell-check-dialog.c
index 0b2594a..cf1dc22 100644
--- a/e-util/e-editor-spell-check-dialog.c
+++ b/e-util/e-editor-spell-check-dialog.c
@@ -24,8 +24,9 @@
#include <glib/gi18n-lib.h>
#include <enchant/enchant.h>
-#include "e-editor-spell-checker.h"
#include "e-editor-widget.h"
+#include "e-spell-checker.h"
+#include "e-spell-dictionary.h"
G_DEFINE_TYPE (
EEditorSpellCheckDialog,
@@ -636,20 +637,20 @@ e_editor_spell_check_dialog_set_dictionaries (EEditorSpellCheckDialog *dialog,
/* Copy and sort the new list of spell checkers. */
list = g_list_sort (
g_list_copy (dictionaries),
- (GCompareFunc) e_editor_spell_checker_dict_compare);
+ (GCompareFunc) e_spell_dictionary_compare);
dialog->priv->dictionaries = list;
/* Populate a list store for the combo box. */
store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_POINTER);
while (list != NULL) {
- EnchantDict *dictionary = list->data;
+ ESpellDictionary *dictionary = list->data;
GtkTreeIter iter;
gtk_list_store_append (store, &iter);
gtk_list_store_set (
store, &iter,
- 0, e_editor_spell_checker_get_dict_name (dictionary),
+ 0, e_spell_dictionary_get_name (dictionary),
1, dictionary, -1);
list = g_list_next (list);
diff --git a/e-util/e-editor-widget.c b/e-util/e-editor-widget.c
index cc9acfd..23f8143 100644
--- a/e-util/e-editor-widget.c
+++ b/e-util/e-editor-widget.c
@@ -23,7 +23,6 @@
#include "e-editor-widget.h"
#include "e-editor.h"
#include "e-emoticon-chooser.h"
-#include "e-editor-spell-checker.h"
#include <e-util/e-util.h>
#include <e-util/e-marshal.h>
@@ -825,7 +824,7 @@ e_editor_widget_init (EEditorWidget *editor)
WebKitDOMDocument *document;
GSettings *g_settings;
GSettingsSchema *settings_schema;
- EEditorSpellChecker *checker;
+ ESpellChecker *checker;
editor->priv = G_TYPE_INSTANCE_GET_PRIVATE (
editor, E_TYPE_EDITOR_WIDGET, EEditorWidgetPrivate);
@@ -846,7 +845,7 @@ e_editor_widget_init (EEditorWidget *editor)
webkit_web_view_set_settings (WEBKIT_WEB_VIEW (editor), settings);
/* Override the spell-checker, use our own */
- checker = g_object_new (E_TYPE_EDITOR_SPELL_CHECKER, NULL);
+ checker = g_object_new (E_TYPE_SPELL_CHECKER, NULL);
webkit_set_text_checker (G_OBJECT (checker));
g_object_unref (checker);
@@ -1083,6 +1082,13 @@ e_editor_widget_set_spell_languages (EEditorWidget *widget,
g_object_notify (G_OBJECT (widget), "spell-languages");
}
+ESpellChecker *
+e_editor_widget_get_spell_checker (EEditorWidget *widget)
+{
+ return E_SPELL_CHECKER (webkit_get_text_checker ());
+}
+
+
gchar *
e_editor_widget_get_text_html (EEditorWidget *widget)
{
diff --git a/e-util/e-editor-widget.h b/e-util/e-editor-widget.h
index dcdf549..59a5b9e 100644
--- a/e-util/e-editor-widget.h
+++ b/e-util/e-editor-widget.h
@@ -26,6 +26,7 @@
#include <webkit/webkit.h>
#include <e-util/e-editor-selection.h>
+#include <e-util/e-spell-checker.h>
/* Standard GObject macros */
#define E_TYPE_EDITOR_WIDGET \
@@ -116,6 +117,9 @@ void e_editor_widget_set_spell_languages
(EEditorWidget *widget,
GList *spell_languages);
+ESpellChecker * e_editor_widget_get_spell_checker
+ (EEditorWidget *widget);
+
gchar * e_editor_widget_get_text_html (EEditorWidget *widget);
gchar * e_editor_widget_get_text_plain (EEditorWidget *widget);
void e_editor_widget_set_text_html (EEditorWidget *widget,
diff --git a/e-util/e-editor.c b/e-util/e-editor.c
index 92916ad..fcf6d8e 100644
--- a/e-util/e-editor.c
+++ b/e-util/e-editor.c
@@ -23,7 +23,6 @@
#include "e-editor-private.h"
#include "e-editor-utils.h"
#include "e-editor-selection.h"
-#include "e-editor-spell-checker.h"
#include <glib/gi18n-lib.h>
#include <enchant/enchant.h>
@@ -191,33 +190,30 @@ editor_inline_spelling_suggestions (EEditor *editor,
/* Helper for editor_update_actions() */
static void
-editor_spell_checkers_foreach (EnchantDict *dictionary,
+editor_spell_checkers_foreach (ESpellDictionary *dictionary,
EEditor *editor)
{
- EEditorSpellChecker *checker;
EEditorWidget *widget;
EEditorSelection *selection;
const gchar *language_code;
GtkActionGroup *action_group;
GtkUIManager *manager;
- gchar **suggestions;
+ GList *suggestions, *iter;
gchar *path;
gchar *word;
gint ii = 0;
guint merge_id;
- language_code = e_editor_spell_checker_get_dict_code (dictionary);
+ language_code = e_spell_dictionary_get_code (dictionary);
widget = e_editor_get_editor_widget (editor);
selection = e_editor_widget_get_selection (widget);
- checker = E_EDITOR_SPELL_CHECKER (webkit_get_text_checker ());
word = e_editor_selection_get_caret_word (selection);
if (!word || !*word) {
return;
}
- suggestions = webkit_spell_checker_get_guesses_for_word (
- WEBKIT_SPELL_CHECKER (checker), word, NULL);
+ suggestions = e_spell_dictionary_get_suggestions (dictionary, word, -1);
manager = e_editor_get_ui_manager (editor);
action_group = editor->priv->suggestion_actions;
@@ -227,8 +223,8 @@ editor_spell_checkers_foreach (EnchantDict *dictionary,
"/context-menu/context-spell-suggest/"
"context-spell-suggest-%s-menu", language_code);
- for (ii = 0; suggestions && suggestions[ii]; ii++) {
- gchar *suggestion = suggestions[ii];
+ for (iter = suggestions; iter; iter = iter->next) {
+ gchar *suggestion = iter->data;
gchar *action_name;
gchar *action_label;
GtkAction *action;
@@ -272,9 +268,10 @@ editor_spell_checkers_foreach (EnchantDict *dictionary,
g_free (action_label);
}
+ e_spell_dictionary_free_suggestions (suggestions);
+
g_free (path);
g_free (word);
- g_strfreev (suggestions);
}
static void
@@ -426,16 +423,20 @@ static void
editor_spell_languages_changed (EEditor *editor,
GList *dictionaries)
{
- WebKitSpellChecker *checker;
+ ESpellChecker *checker;
WebKitWebSettings *settings;
GString *languages;
const GList *iter;
+ /* Set the languages for spell-checker to use for suggestions etc. */
+ checker = e_editor_widget_get_spell_checker (editor->priv->editor_widget);
+ e_spell_checker_set_active_dictionaries (checker, dictionaries);
+
languages = g_string_new ("");
/* Join the languages codes to comma-separated list */
for (iter = dictionaries; iter; iter = iter->next) {
- EnchantDict *dictionary = iter->data;
+ ESpellDictionary *dictionary = iter->data;
if (iter != dictionaries) {
g_string_append (languages, ",");
@@ -443,13 +444,9 @@ editor_spell_languages_changed (EEditor *editor,
g_string_append (
languages,
- e_editor_spell_checker_get_dict_code (dictionary));
+ e_spell_dictionary_get_code (dictionary));
}
- /* Set the languages for spell-checker to use for suggestions etc. */
- checker = WEBKIT_SPELL_CHECKER (webkit_get_text_checker());
- webkit_spell_checker_update_spell_checking_languages (checker, languages->str);
-
/* Set the languages for webview to highlight misspelled words */
settings = webkit_web_view_get_settings (
WEBKIT_WEB_VIEW (editor->priv->editor_widget));
@@ -687,13 +684,6 @@ editor_constructed (GObject *object)
}
static void
-free_dict (gpointer dict,
- gpointer checker)
-{
- e_editor_spell_checker_free_dict (checker, dict);
-}
-
-static void
editor_dispose (GObject *object)
{
EEditor *editor = E_EDITOR (object);
@@ -708,10 +698,7 @@ editor_dispose (GObject *object)
g_clear_object (&priv->spell_check_actions);
g_clear_object (&priv->suggestion_actions);
- g_list_foreach (
- priv->active_dictionaries, free_dict,
- webkit_get_text_checker());
- g_list_free (priv->active_dictionaries);
+ g_list_free_full (priv->active_dictionaries, g_object_unref);
priv->active_dictionaries = NULL;
g_clear_object (&priv->main_menu);
diff --git a/e-util/e-spell-checker.c b/e-util/e-spell-checker.c
new file mode 100644
index 0000000..4fd6849
--- /dev/null
+++ b/e-util/e-spell-checker.c
@@ -0,0 +1,521 @@
+/*
+ * 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 <webkit/webkitspellchecker.h>
+#include <pango/pango.h>
+#include <gtk/gtk.h>
+
+static void e_spell_checker_init_webkit_checker (WebKitSpellCheckerInterface *iface);
+
+G_DEFINE_TYPE_EXTENDED (
+ ESpellChecker,
+ e_spell_checker,
+ G_TYPE_OBJECT,
+ 0,
+ G_IMPLEMENT_INTERFACE (
+ WEBKIT_TYPE_SPELL_CHECKER,
+ e_spell_checker_init_webkit_checker))
+
+struct _ESpellCheckerPrivate {
+ GList *active;
+
+ EnchantBroker *broker;
+};
+
+enum {
+ PROP_ACTIVE_DICTIONARIES
+};
+
+/**
+ * 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 void
+wksc_check_spelling (WebKitSpellChecker *webkit_checker,
+ const char *word,
+ int *misspelling_location,
+ int *misspelling_length)
+{
+ ESpellChecker *checker = E_SPELL_CHECKER (webkit_checker);
+ PangoLanguage *language;
+ PangoLogAttr *attrs;
+ GList *dicts;
+ gint length, ii;
+
+ dicts = checker->priv->active;
+ if (!dicts)
+ 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) {
+ int start = ii;
+ int end = ii;
+ int word_length;
+ gchar *cstart;
+ gint bytes;
+ gchar *new_word;
+ GList *iter;
+
+ 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);
+
+ for (iter = dicts; iter; iter = iter->next) {
+ ESpellDictionary *dict = iter->data;
+
+ if (e_spell_dictionary_check (dict, new_word, word_length)) {
+ if (misspelling_location)
+ *misspelling_location = start;
+ if (misspelling_length)
+ *misspelling_length = word_length;
+ } else {
+ /* Stop checking, this word is ok in at
+ * least one dict. */
+ if (misspelling_location)
+ *misspelling_location = -1;
+ if (misspelling_length)
+ *misspelling_length = 0;
+ break;
+ }
+ }
+
+ 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);
+ GList *dicts;
+ char** guesses;
+ gint ii;
+
+ guesses = g_malloc0_n (sizeof (gchar *), 11);
+ ii = 0;
+ for (dicts = checker->priv->active; dicts && ii < 10; dicts = dicts->next) {
+ ESpellDictionary *dict;
+ GList *suggestions, *iter;
+ gint suggestions_count;
+
+ dict = dicts->data;
+ suggestions = e_spell_dictionary_get_suggestions (dict, word, -1);
+
+ suggestions_count = g_list_length (suggestions);
+ if (suggestions_count > 0) {
+ if (suggestions_count > 10) {
+ suggestions_count = 10;
+ }
+
+ for (iter = suggestions; iter && ii < 10; iter = iter->next, ii++) {
+ guesses[ii] = g_strdup (iter->data);
+ }
+
+ guesses[ii] = 0;
+
+ e_spell_dictionary_free_suggestions (suggestions);
+ }
+ }
+
+ 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;
+ GList *iter;
+
+ checker = E_SPELL_CHECKER (webkit_checker);
+ for (iter = checker->priv->active; iter; iter = iter->next) {
+ ESpellDictionary *dict = iter->data;
+
+ e_spell_dictionary_learn_word (dict, word, -1);
+ }
+}
+
+static void
+spell_checker_ignore_word (WebKitSpellChecker *webkit_checker,
+ const gchar *word)
+{
+ /* Carefully, this will add the word to all active dictionaries */
+
+ ESpellChecker *checker;
+ GList *iter;
+
+ checker = E_SPELL_CHECKER (webkit_checker);
+ for (iter = checker->priv->active; iter; iter = iter->next) {
+ ESpellDictionary *dict = iter->data;
+
+ e_spell_dictionary_ignore_word (dict, word, -1);
+ }
+}
+
+static void
+wksc_update_languages (WebKitSpellChecker *webkit_checker,
+ const char *languages)
+{
+ ESpellChecker *checker;
+ GList *dictionaries = NULL;
+ gchar **langs;
+ gint ii;
+
+ checker = E_SPELL_CHECKER (webkit_checker);
+ if (languages) {
+ langs = g_strsplit (languages, ",", -1);
+ for (ii = 0; langs[ii] != NULL; ii++) {
+ ESpellDictionary *dict;
+
+ dict = e_spell_checker_lookup_dictionary (checker, langs[ii]);
+ dictionaries = g_list_append (dictionaries, dict);
+ }
+ g_strfreev (langs);
+ } else {
+ const gchar *language;
+ ESpellDictionary *dict;
+
+ language = pango_language_to_string (gtk_get_default_language ());
+ dict = e_spell_checker_lookup_dictionary (checker, language);
+ if (dict) {
+ dictionaries = g_list_append (dictionaries, dict);
+ } else {
+ dictionaries = e_spell_checker_list_available_dicts (checker);
+ }
+ }
+
+ e_spell_checker_set_active_dictionaries (checker, dictionaries);
+ g_list_free_full (dictionaries, g_object_unref);
+}
+
+
+static void
+spell_checker_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_ACTIVE_DICTIONARIES:
+ e_spell_checker_set_active_dictionaries (
+ E_SPELL_CHECKER (object),
+ g_value_get_pointer (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+spell_checker_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_ACTIVE_DICTIONARIES:
+ g_value_set_pointer (
+ value,
+ e_spell_checker_get_active_dictionaries (
+ E_SPELL_CHECKER (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+spell_checker_dispose (GObject *object)
+{
+ ESpellCheckerPrivate *priv = E_SPELL_CHECKER (object)->priv;
+
+ g_list_free_full (priv->active, g_object_unref);
+ priv->active = NULL;
+
+ enchant_broker_free (priv->broker);
+ priv->broker = NULL;
+
+ /* Chain up to parent implementation */
+ G_OBJECT_CLASS (e_spell_checker_parent_class)->dispose (object);
+}
+
+static void
+e_spell_checker_class_init (ESpellCheckerClass *klass)
+{
+ GObjectClass *object_class;
+
+ e_spell_checker_parent_class = g_type_class_peek_parent (klass);
+ g_type_class_add_private (klass, sizeof (ESpellCheckerPrivate));
+
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->set_property = spell_checker_set_property;
+ object_class->get_property = spell_checker_get_property;
+ object_class->dispose = spell_checker_dispose;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_ACTIVE_DICTIONARIES,
+ g_param_spec_pointer (
+ "active-dictionaries",
+ NULL,
+ "List of active dictionaries to use for spell-checking",
+ G_PARAM_READWRITE));
+}
+
+static void
+e_spell_checker_init_webkit_checker (WebKitSpellCheckerInterface *iface)
+{
+ iface->check_spelling_of_string = wksc_check_spelling;
+ iface->get_autocorrect_suggestions_for_misspelled_word = wksc_get_autocorrect_suggestions;
+ iface->get_guesses_for_word = wksc_get_guesses;
+ iface->ignore_word = spell_checker_ignore_word;
+ iface->learn_word = spell_checker_learn_word;
+ iface->update_spell_checking_languages = wksc_update_languages;
+}
+
+
+static void
+e_spell_checker_init (ESpellChecker *checker)
+{
+ checker->priv = G_TYPE_INSTANCE_GET_PRIVATE (
+ checker, E_TYPE_SPELL_CHECKER, ESpellCheckerPrivate);
+}
+
+typedef struct {
+ ESpellChecker *checker;
+ GList *dicts;
+} ListAvailDictsData;
+
+static void
+list_enchant_dicts (const char * const lang_tag,
+ const char * const provider_name,
+ const char * const provider_desc,
+ const char * const provider_file,
+ void * user_data)
+{
+ ListAvailDictsData *data = user_data;
+ EnchantDict *dict;
+
+ dict = enchant_broker_request_dict (data->checker->priv->broker, lang_tag);
+ if (dict) {
+ ESpellDictionary *e_dict;
+
+ e_dict = e_spell_dictionary_new (data->checker, dict);
+
+ data->dicts = g_list_prepend (data->dicts, e_dict);
+ }
+}
+
+
+/**
+ * e_spell_checker_list_available_dicts:
+ * @checker: An #ESpellChecker
+ *
+ * Returns list of all dictionaries available to the actual
+ * spell-checking backend.
+ *
+ * Return value: a #GList of #ESpellDictionary. Free the list using g_list_free()
+ * when not needed anymore.
+ */
+GList *
+e_spell_checker_list_available_dicts (ESpellChecker *checker)
+{
+ ESpellChecker *e_checker;
+ ListAvailDictsData data;
+
+ e_checker = E_SPELL_CHECKER (checker);
+
+ data.checker = e_checker;
+ enchant_broker_list_dicts (
+ e_checker->priv->broker, list_enchant_dicts, &data);
+
+ return g_list_reverse (data.dicts);
+}
+
+/**
+ * e_spell_checker_lookup_dictionary:
+ * @checker: an #ESpellChecker
+ * @language_code: (allow-none) language code for which to lookup the dictionary
+ *
+ * Tries to find an #ESpellDictionary for given @language_code. When @language_code
+ * is #NULL, this function will return a default #ESpellDictionary.
+ *
+ * Return value: an #ESpellDictionary for @language_code
+ */
+ESpellDictionary *
+e_spell_checker_lookup_dictionary (ESpellChecker *checker,
+ const gchar *language_code)
+{
+ ESpellChecker *e_checker;
+ ESpellDictionary *e_dict;
+
+ e_checker = E_SPELL_CHECKER (checker);
+
+ e_dict = NULL;
+
+ if (!language_code) {
+ GList *dicts = e_spell_checker_list_available_dicts (checker);
+
+ if (dicts) {
+ e_dict = g_object_ref (dicts->data);
+ g_list_free_full (dicts, g_object_unref);
+ }
+ } else {
+ EnchantDict *dict;
+ dict = enchant_broker_request_dict (
+ e_checker->priv->broker, language_code);
+ if (dict) {
+ e_dict = e_spell_dictionary_new (checker, dict);
+ }
+ }
+
+ return e_dict;
+}
+
+/**
+ * e_spell_checker_get_active_dictionaries:
+ * @checker: an #ESpellChecker
+ *
+ * Returns a list of #ESpellDictionary that are to be used for spell-checking.
+ *
+ * Return value: a #GList of #ESpellDictionary. Free the list using g_list_fre()
+ * when no longer needed.
+ */
+GList *
+e_spell_checker_get_active_dictionaries (ESpellChecker *checker)
+{
+ g_return_val_if_fail (E_IS_SPELL_CHECKER (checker), NULL);
+
+ return g_list_copy (checker->priv->active);
+}
+
+/**
+ * e_spell_checker_set_active_dictionaries:
+ * @checker: an #ESpellChecker
+ * @active_dict: a #GList of #ESpellDictionary to use for spell-checking
+ *
+ * Set dictionaries to be actively used for spell-checking.
+ */
+void
+e_spell_checker_set_active_dictionaries (ESpellChecker *checker,
+ GList *active_dicts)
+{
+ g_return_if_fail (E_IS_SPELL_CHECKER (checker));
+
+ g_list_free_full (checker->priv->active, (GDestroyNotify) g_object_unref);
+
+ checker->priv->active = g_list_copy (active_dicts);
+ g_list_foreach (checker->priv->active, (GFunc) g_object_ref, NULL);
+}
+
+void
+e_spell_checker_free_dict (ESpellChecker *checker,
+ EnchantDict *dict)
+{
+ g_return_if_fail (E_IS_SPELL_CHECKER (checker));
+ g_return_if_fail (dict != NULL);
+
+ enchant_broker_free_dict (checker->priv->broker, dict);
+}
+
+/**
+ * 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 *webkit_checker_iface;
+
+ g_return_if_fail (E_IS_SPELL_CHECKER (checker));
+
+ webkit_checker_iface = WEBKIT_SPELL_CHECKER_GET_IFACE (checker);
+ webkit_checker_iface->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 *webkit_checker_iface;
+
+ g_return_if_fail (E_IS_SPELL_CHECKER (checker));
+
+ webkit_checker_iface = WEBKIT_SPELL_CHECKER_GET_IFACE (checker);
+ webkit_checker_iface->learn_word (WEBKIT_SPELL_CHECKER (checker), word);
+}
diff --git a/e-util/e-spell-checker.h b/e-util/e-spell-checker.h
new file mode 100644
index 0000000..c403ea1
--- /dev/null
+++ b/e-util/e-spell-checker.h
@@ -0,0 +1,86 @@
+/*
+ * e-spell-checker.h
+ *
+ * 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.
+ */
+
+#ifndef E_SPELL_CHECKER_H
+#define E_SPELL_CHECKER_H
+
+#include <glib-object.h>
+#include <e-util/e-spell-dictionary.h>
+
+/* Standard GObject macros */
+#define E_TYPE_SPELL_CHECKER \
+ (e_spell_checker_get_type ())
+#define E_SPELL_CHECKER(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_SPELL_CHECKER, ESpellChecker))
+#define E_SPELL_CHECKER_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_SPELL_CHECKER, ESpellCheckerClass))
+#define E_IS_SPELL_CHECKER(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_SPELL_CHECKER))
+#define E_IS_SPELL_CHECKER_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_SPELL_CHECKER))
+#define E_SPELL_CHECKER_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_SPELL_CHECKER, ESpellCheckerClass))
+
+
+G_BEGIN_DECLS
+
+typedef struct _ESpellChecker ESpellChecker;
+typedef struct _ESpellCheckerPrivate ESpellCheckerPrivate;
+typedef struct _ESpellCheckerClass ESpellCheckerClass;
+
+struct _ESpellChecker {
+ GObject parent;
+
+ ESpellCheckerPrivate *priv;
+};
+
+struct _ESpellCheckerClass {
+ GObjectClass parent_class;
+};
+
+GType e_spell_checker_get_type (void);
+
+GList * e_spell_checker_list_available_dicts
+ (ESpellChecker *checker);
+ESpellDictionary * e_spell_checker_lookup_dictionary
+ (ESpellChecker *checker,
+ const gchar *language_code);
+
+void e_spell_checker_set_active_dictionaries
+ (ESpellChecker *checker,
+ GList *active_dicts);
+GList * e_spell_checker_get_active_dictionaries
+ (ESpellChecker *checker);
+
+void e_spell_checker_free_dict (ESpellChecker *checker,
+ EnchantDict *dict);
+
+void e_spell_checker_learn_word (ESpellChecker *checker,
+ const gchar *word);
+void e_spell_checker_ignore_word (ESpellChecker *checker,
+ const gchar *word);
+
+G_END_DECLS
+
+
+#endif /* E_SPELL_CHECKER_H */
\ No newline at end of file
diff --git a/e-util/e-spell-dictionary.c b/e-util/e-spell-dictionary.c
new file mode 100644
index 0000000..aed60ce
--- /dev/null
+++ b/e-util/e-spell-dictionary.c
@@ -0,0 +1,651 @@
+/*
+ * e-spell-dictionary.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-dictionary.h"
+#include "e-spell-checker.h"
+
+#include <glib/gi18n-lib.h>
+#include <string.h>
+
+G_DEFINE_TYPE (
+ ESpellDictionary,
+ e_spell_dictionary,
+ G_TYPE_OBJECT);
+
+/**
+ * ESpellDictionary:
+ *
+ * The #ESpellDictionary is a wrapper around #EnchantDict.
+ */
+
+
+enum {
+ PROP_SPELLCHECKER
+};
+
+struct _ESpellDictionaryPrivate {
+ ESpellChecker *spell_checker;
+ EnchantDict *dict;
+
+ gchar *name;
+ gchar *code;
+ gchar *collate_key;
+};
+
+#define ISO_639_DOMAIN "iso_639"
+#define ISO_3166_DOMAIN "iso_3166"
+
+static GHashTable *iso_639_table = NULL;
+static GHashTable *iso_3166_table = NULL;
+
+#ifdef HAVE_ISO_CODES
+
+#define ISOCODESLOCALEDIR ISO_CODES_PREFIX "/share/locale"
+
+#ifdef G_OS_WIN32
+#ifdef DATADIR
+#undef DATADIR
+#endif
+#include <shlobj.h>
+static HMODULE hmodule;
+
+BOOL WINAPI
+DllMain (HINSTANCE hinstDLL,
+ DWORD fdwReason,
+ LPVOID lpvReserved);
+
+BOOL WINAPI
+DllMain (HINSTANCE hinstDLL,
+ DWORD fdwReason,
+ LPVOID lpvReserved)
+{
+ switch (fdwReason)
+ {
+ case DLL_PROCESS_ATTACH:
+ hmodule = hinstDLL;
+ break;
+ }
+
+ return TRUE;
+}
+
+static gchar *
+_get_iso_codes_prefix (void)
+{
+ static gchar retval[1000];
+ static gint beenhere = 0;
+ gchar *temp_dir = 0;
+
+ if (beenhere)
+ return retval;
+
+ if (!(temp_dir = g_win32_get_package_installation_directory_of_module ((gpointer) hmodule))) {
+ strcpy (retval, ISO_CODES_PREFIX);
+ return retval;
+ }
+
+ strcpy (retval, temp_dir);
+ g_free (temp_dir);
+ beenhere = 1;
+ return retval;
+}
+
+static gchar *
+_get_isocodeslocaledir (void)
+{
+ static gchar retval[1000];
+ static gint beenhere = 0;
+
+ if (beenhere)
+ return retval;
+
+ strcpy (retval, _get_iso_codes_prefix ());
+ strcat (retval, "\\share\\locale" );
+ beenhere = 1;
+ return retval;
+}
+
+#undef ISO_CODES_PREFIX
+#define ISO_CODES_PREFIX _get_iso_codes_prefix ()
+
+#undef ISOCODESLOCALEDIR
+#define ISOCODESLOCALEDIR _get_isocodeslocaledir ()
+
+#endif
+
+static void
+iso_639_start_element (GMarkupParseContext *context,
+ const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ gpointer data,
+ GError **error)
+{
+ GHashTable *hash_table = data;
+ const gchar *iso_639_1_code = NULL;
+ const gchar *iso_639_2_code = NULL;
+ const gchar *name = NULL;
+ const gchar *code = NULL;
+ gint ii;
+
+ if (g_strcmp0 (element_name, "iso_639_entry") != 0) {
+ return;
+ }
+
+ for (ii = 0; attribute_names[ii] != NULL; ii++) {
+ if (strcmp (attribute_names[ii], "name") == 0)
+ name = attribute_values[ii];
+ else if (strcmp (attribute_names[ii], "iso_639_1_code") == 0)
+ iso_639_1_code = attribute_values[ii];
+ else if (strcmp (attribute_names[ii], "iso_639_2T_code") == 0)
+ iso_639_2_code = attribute_values[ii];
+ }
+
+ code = (iso_639_1_code != NULL) ? iso_639_1_code : iso_639_2_code;
+
+ if (code != NULL && *code != '\0' && name != NULL && *name != '\0')
+ g_hash_table_insert (
+ hash_table, g_strdup (code),
+ g_strdup (dgettext (ISO_639_DOMAIN, name)));
+}
+
+static void
+iso_3166_start_element (GMarkupParseContext *context,
+ const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ gpointer data,
+ GError **error)
+{
+ GHashTable *hash_table = data;
+ const gchar *name = NULL;
+ const gchar *code = NULL;
+ gint ii;
+
+ if (strcmp (element_name, "iso_3166_entry") != 0)
+ return;
+
+ for (ii = 0; attribute_names[ii] != NULL; ii++) {
+ if (strcmp (attribute_names[ii], "name") == 0)
+ name = attribute_values[ii];
+ else if (strcmp (attribute_names[ii], "alpha_2_code") == 0)
+ code = attribute_values[ii];
+ }
+
+ if (code != NULL && *code != '\0' && name != NULL && *name != '\0')
+ g_hash_table_insert (
+ hash_table, g_ascii_strdown (code, -1),
+ g_strdup (dgettext (ISO_3166_DOMAIN, name)));
+}
+
+static GMarkupParser iso_639_parser = {
+ iso_639_start_element,
+ NULL, NULL, NULL, NULL
+};
+
+static GMarkupParser iso_3166_parser = {
+ iso_3166_start_element,
+ NULL, NULL, NULL, NULL
+};
+
+static void
+iso_codes_parse (const GMarkupParser *parser,
+ const gchar *basename,
+ GHashTable *hash_table)
+{
+ GMappedFile *mapped_file;
+ gchar *filename;
+ GError *error = NULL;
+
+ filename = g_build_filename (
+ ISO_CODES_PREFIX, "share", "xml",
+ "iso-codes", basename, NULL);
+ mapped_file = g_mapped_file_new (filename, FALSE, &error);
+ g_free (filename);
+
+ if (mapped_file != NULL) {
+ GMarkupParseContext *context;
+ const gchar *contents;
+ gsize length;
+
+ context = g_markup_parse_context_new (
+ parser, 0, hash_table, NULL);
+ contents = g_mapped_file_get_contents (mapped_file);
+ length = g_mapped_file_get_length (mapped_file);
+ g_markup_parse_context_parse (
+ context, contents, length, &error);
+ g_markup_parse_context_free (context);
+#if GLIB_CHECK_VERSION(2,21,3)
+ g_mapped_file_unref (mapped_file);
+#else
+ g_mapped_file_free (mapped_file);
+#endif
+ }
+
+ if (error != NULL) {
+ g_warning ("%s: %s", basename, error->message);
+ g_error_free (error);
+ }
+}
+
+#endif /* HAVE_ISO_CODES */
+
+struct _enchant_dict_description_data {
+ gchar *language_tag;
+ gchar *dict_name;
+};
+
+static void
+describe_dictionary (const gchar *language_tag,
+ const gchar *provider_name,
+ const gchar *provider_desc,
+ const gchar *provider_file,
+ gpointer user_data)
+{
+ struct _enchant_dict_description_data *data = user_data;
+ const gchar *iso_639_name;
+ const gchar *iso_3166_name;
+ gchar *language_name;
+ gchar *lowercase;
+ gchar **tokens;
+
+ /* Split language code into lowercase tokens. */
+ lowercase = g_ascii_strdown (language_tag, -1);
+ tokens = g_strsplit (lowercase, "_", -1);
+ g_free (lowercase);
+
+ g_return_if_fail (tokens != NULL);
+
+ iso_639_name = g_hash_table_lookup (iso_639_table, tokens[0]);
+
+ if (iso_639_name == NULL) {
+ language_name = g_strdup_printf (
+ /* Translators: %s is the language ISO code. */
+ C_("language", "Unknown (%s)"), language_tag);
+ goto exit;
+ }
+
+ if (g_strv_length (tokens) < 2) {
+ language_name = g_strdup (iso_639_name);
+ goto exit;
+ }
+
+ iso_3166_name = g_hash_table_lookup (iso_3166_table, tokens[1]);
+
+ if (iso_3166_name != NULL)
+ language_name = g_strdup_printf (
+ /* Translators: The first %s is the language name, and the
+ * second is the country name. Example: "French (France)" */
+ C_("language", "%s (%s)"), iso_639_name, iso_3166_name);
+ else
+ language_name = g_strdup_printf (
+ /* Translators: The first %s is the language name, and the
+ * second is the country name. Example: "French (France)" */
+ C_("language", "%s (%s)"), iso_639_name, tokens[1]);
+
+exit:
+ g_strfreev (tokens);
+
+ data->language_tag = g_strdup (language_tag);
+ data->dict_name = language_name;
+}
+
+static void
+spell_dictionary_set_enchant_dict (ESpellDictionary *dictionary,
+ EnchantDict *enchant_dict)
+{
+ struct _enchant_dict_description_data data;
+
+ enchant_dict_describe (enchant_dict, describe_dictionary, &data);
+
+ dictionary->priv->code = data.language_tag;
+ dictionary->priv->name = data.dict_name;
+ dictionary->priv->collate_key = g_utf8_collate_key (data.dict_name, -1);
+}
+
+static void
+spell_dictionary_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ ESpellDictionary *dict = E_SPELL_DICTIONARY (object);
+
+ switch (property_id) {
+ case PROP_SPELLCHECKER:
+ dict->priv->spell_checker =
+ g_object_ref (g_value_get_object (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+spell_dictionary_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ ESpellDictionary *dict = E_SPELL_DICTIONARY (object);
+
+ switch (property_id) {
+ case PROP_SPELLCHECKER:
+ g_value_set_object (
+ value,
+ e_spell_dictionary_get_parent_checker (dict));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+spell_dictionary_dispose (GObject *object)
+{
+ ESpellDictionaryPrivate *priv = E_SPELL_DICTIONARY (object)->priv;
+
+ e_spell_checker_free_dict (
+ e_spell_dictionary_get_parent_checker (E_SPELL_DICTIONARY (object)),
+ priv->dict);
+ priv->dict = NULL;
+
+ g_free (priv->name);
+ priv->name = NULL;
+
+ g_free (priv->code);
+ priv->code = NULL;
+
+ g_free (priv->collate_key);
+ priv->collate_key = NULL;
+
+ g_clear_object (&priv->spell_checker);
+
+ /* Chain up to parent implementation */
+ G_OBJECT_CLASS (e_spell_dictionary_parent_class)->dispose (object);
+}
+
+static void
+e_spell_dictionary_class_init (ESpellDictionaryClass *klass)
+{
+ GObjectClass *object_class;
+
+ e_spell_dictionary_parent_class = g_type_class_peek_parent (klass);
+ g_type_class_add_private (klass, sizeof (ESpellDictionaryPrivate));
+
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->set_property = spell_dictionary_set_property;
+ object_class->get_property = spell_dictionary_get_property;
+ object_class->dispose = spell_dictionary_dispose;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_SPELLCHECKER,
+ g_param_spec_object (
+ "spell-checker",
+ NULL,
+ "Parent spell checker",
+ E_TYPE_SPELL_CHECKER,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+e_spell_dictionary_init (ESpellDictionary *dict)
+{
+ dict->priv = G_TYPE_INSTANCE_GET_PRIVATE (
+ dict, E_TYPE_SPELL_DICTIONARY, ESpellDictionaryPrivate);
+
+ if (!iso_639_table && !iso_3166_table) {
+ #if defined (ENABLE_NLS) && defined (HAVE_ISO_CODES)
+ bindtextdomain (ISO_639_DOMAIN, ISOCODESLOCALEDIR);
+ bind_textdomain_codeset (ISO_639_DOMAIN, "UTF-8");
+
+ bindtextdomain (ISO_3166_DOMAIN, ISOCODESLOCALEDIR);
+ bind_textdomain_codeset (ISO_3166_DOMAIN, "UTF-8");
+ #endif
+
+ iso_639_table = g_hash_table_new_full (
+ g_str_hash, g_str_equal,
+ (GDestroyNotify) g_free,
+ (GDestroyNotify) g_free);
+
+ iso_3166_table = g_hash_table_new_full (
+ g_str_hash, g_str_equal,
+ (GDestroyNotify) g_free,
+ (GDestroyNotify) g_free);
+
+ #ifdef HAVE_ISO_CODES
+ iso_codes_parse (
+ &iso_639_parser, "iso_639.xml", iso_639_table);
+ iso_codes_parse (
+ &iso_3166_parser, "iso_3166.xml", iso_3166_table);
+ #endif
+ }
+}
+
+ESpellDictionary *
+e_spell_dictionary_new (ESpellChecker *parent_checker,
+ EnchantDict *dict)
+{
+ ESpellDictionary *e_dict;
+
+ e_dict = g_object_new (E_TYPE_SPELL_DICTIONARY,
+ "spell-checker", parent_checker, NULL);
+
+ spell_dictionary_set_enchant_dict (e_dict, dict);
+
+ return e_dict;
+}
+
+
+/**
+ * e_spell_dictionary_get_name:
+ * @dictionary: an #ESpellDictionary
+ *
+ * Provides a user-friendly name of the dictionary (for example
+ * "English (British)")
+ *
+ * Return value: a name of the @dictionary
+ */
+const gchar *
+e_spell_dictionary_get_name (ESpellDictionary *dictionary)
+{
+ g_return_val_if_fail (E_IS_SPELL_DICTIONARY (dictionary), NULL);
+
+ return dictionary->priv->name;
+}
+
+/**
+ * e_spell_dictionary_get_code:
+ * @dictionary: an #ESpellDictionary
+ *
+ * Provides an ISO code of spell-checking language of the
+ * @dictionary (for example "en_US").
+ *
+ * Return value: language code of the @dictionary
+ */
+const gchar *
+e_spell_dictionary_get_code (ESpellDictionary *dictionary)
+{
+ g_return_val_if_fail (E_IS_SPELL_DICTIONARY (dictionary), NULL);
+
+ return dictionary->priv->code;
+}
+
+/**
+ * e_spell_dictionary_check:
+ * @dictionary: an #ESpellDictionary
+ * @word: a word whose spelling to checking
+ * @len: size of @word in bytes or -1 when NULL-terminated
+ *
+ * Tries to lookup the @word in the @dictionary to check whether
+ * it's spelled correctly or not.
+ *
+ * Return value: #TRUE when the word is spelled correctly, FALSE otherwise
+ */
+gboolean
+e_spell_dictionary_check (ESpellDictionary *dictionary,
+ const gchar *word,
+ gsize len)
+{
+ g_return_val_if_fail (E_IS_SPELL_DICTIONARY (dictionary), TRUE);
+ g_return_val_if_fail (word && *word, TRUE);
+
+ return enchant_dict_check (dictionary->priv->dict, word, len);
+}
+
+/**
+ * e_spell_dictionary_learn_word:
+ * @dictionary: an #ESpellDictionary
+ * @word: a word to add to @dictionary
+ * @len: size of @word in bytes or -1 when NULL-terminated
+ *
+ * Permanently adds @word to @dictionary so that next time calling
+ * e_spell_dictionary_check() on the @word will return #TRUE.
+ */
+void
+e_spell_dictionary_learn_word (ESpellDictionary *dictionary,
+ const gchar *word,
+ gsize len)
+{
+ g_return_if_fail (E_IS_SPELL_DICTIONARY (dictionary));
+ g_return_if_fail (word && *word);
+
+ enchant_dict_add_to_personal (dictionary->priv->dict, word, len);
+}
+
+/**
+ * e_spell_dictionary_ignore_word:
+ * @dictionary: an #ESpellDictionary
+ * @word: a word to add to ignore list
+ * @len: size of @word in bytes or -1 when NULL-terminated
+ *
+ * Adds @word to temporary ignore list of the @dictionary, so that
+ * e_spell_dictionary_check() on the @word will return #TRUE. The
+ * list is cleared when the dictionary is free'd.
+ */
+void
+e_spell_dictionary_ignore_word (ESpellDictionary *dictionary,
+ const gchar *word,
+ gsize len)
+{
+ g_return_if_fail (E_IS_SPELL_DICTIONARY (dictionary));
+ g_return_if_fail (word && *word);
+
+ enchant_dict_add_to_session (dictionary->priv->dict, word, len);
+}
+
+/**
+ * e_spell_dictionary_get_suggestions:
+ * @dictionary: an #ESpellDictionary
+ * @word: a word to which to find suggestions
+ * @len: size of @word in bytes or -1 when NULL-terminated
+ *
+ * Provides list of alternative spellings of @word.
+ *
+ * Return value: a list of strings that has to be free'd by
+ * e_spell_dictionary_free_suggestions().
+ */
+GList *
+e_spell_dictionary_get_suggestions (ESpellDictionary *dictionary,
+ const gchar *word,
+ gsize len)
+{
+ gchar **s;
+ GList *list;
+ gsize ii, cnt;
+
+ g_return_val_if_fail (E_IS_SPELL_DICTIONARY (dictionary), NULL);
+ g_return_val_if_fail (word && *word, NULL);
+
+ s = enchant_dict_suggest (dictionary->priv->dict, word, len, &cnt);
+ list = NULL;
+ for (ii = 0; ii < len; ii++) {
+ list = g_list_prepend (list, g_strdup (s[ii]));
+ }
+ enchant_dict_free_suggestions (dictionary->priv->dict, s);
+
+ return g_list_reverse (list);
+}
+
+/**
+ * e_spell_dictionary_free_suggestions:
+ * @suggestions: (allow-none) a list of suggestions obtained from
+ * e_spell_dictionary_get_suggestions()
+ *
+ * Frees the @suggestions list.
+ */
+void
+e_spell_dictionary_free_suggestions (GList *suggestions)
+{
+ g_list_foreach (suggestions, (GFunc) g_free, NULL);
+}
+
+/**
+ * e_spell_dictionary_add_correction
+ * @dictionary: an #ESpellDictionary
+ * @misspelled: a word to which add a correction
+ * @misspelled_len: size of @misspelled (in bytes) or -1 when string NULL-terminated
+ * @correction: a correct word
+ * @correction_len: size of @correction (in bytes) or -1 when string NULL-terminated
+ *
+ * Learns a new @correction of @misspelled word
+ */
+void
+e_spell_dictionary_store_correction (ESpellDictionary *dictionary,
+ const gchar *misspelled,
+ gsize misspelled_len,
+ const gchar *correction,
+ gsize correction_len)
+{
+ g_return_if_fail (E_IS_SPELL_DICTIONARY (dictionary));
+ g_return_if_fail (misspelled && *misspelled);
+ g_return_if_fail (correction && *correction);
+
+ enchant_dict_store_replacement (
+ dictionary->priv->dict, misspelled, misspelled_len,
+ correction, correction_len);
+}
+
+/**
+ * e_spell_dictionary_get_parent_checker:
+ * @dictionary: an #ESpellDictionary
+ *
+ * Returns an #ESpellChecker which is parent (and the original owner) of
+ * the @dictionary.
+ *
+ * Return value: an #ESpellChecker
+ */
+ESpellChecker *
+e_spell_dictionary_get_parent_checker (ESpellDictionary *dictionary)
+{
+ g_return_val_if_fail (E_IS_SPELL_DICTIONARY (dictionary), NULL);
+
+ return dictionary->priv->spell_checker;
+}
+
+gint
+e_spell_dictionary_compare (ESpellDictionary *dict1,
+ ESpellDictionary *dict2)
+{
+ return strcmp (dict1->priv->collate_key, dict2->priv->collate_key);
+}
diff --git a/e-util/e-spell-dictionary.h b/e-util/e-spell-dictionary.h
new file mode 100644
index 0000000..fd4e307
--- /dev/null
+++ b/e-util/e-spell-dictionary.h
@@ -0,0 +1,104 @@
+/*
+ * e-spell-dictionary.h
+ *
+ * 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.
+ */
+
+#ifndef E_SPELL_DICTIONARY_H
+#define E_SPELL_DICTIONARY_H
+
+#include <glib-object.h>
+#include <enchant/enchant.h>
+
+/* Standard GObject macros */
+#define E_TYPE_SPELL_DICTIONARY \
+ (e_spell_dictionary_get_type ())
+#define E_SPELL_DICTIONARY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_SPELL_DICTIONARY, ESpellDictionary))
+#define E_SPELL_DICTIONARY_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_SPELL_DICTIONARY, ESpellDictionaryClass))
+#define E_IS_SPELL_DICTIONARY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_SPELL_DICTIONARY))
+#define E_IS_SPELL_DICTIONARY_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_SPELL_DICTIONARY))
+#define E_SPELL_DICTIONARY_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_SPELL_DICTIONARY, ESpellDictionaryClass))
+
+
+G_BEGIN_DECLS
+
+typedef struct _ESpellDictionary ESpellDictionary;
+typedef struct _ESpellDictionaryPrivate ESpellDictionaryPrivate;
+typedef struct _ESpellDictionaryClass ESpellDictionaryClass;
+typedef struct _ESpellChecker ESpellChecker;
+
+struct _ESpellDictionary {
+ GObject parent;
+
+ ESpellDictionaryPrivate *priv;
+};
+
+struct _ESpellDictionaryClass {
+ GObjectClass parent_class;
+
+};
+
+GType e_spell_dictionary_get_type (void);
+
+ESpellDictionary * e_spell_dictionary_new (ESpellChecker *parent_checker,
+ EnchantDict *dict);
+
+const gchar * e_spell_dictionary_get_name (ESpellDictionary *dict);
+const gchar * e_spell_dictionary_get_code (ESpellDictionary *dict);
+
+
+gboolean e_spell_dictionary_check (ESpellDictionary *dict,
+ const gchar *word,
+ gsize len);
+
+void e_spell_dictionary_learn_word (ESpellDictionary *dict,
+ const gchar *word,
+ gsize len);
+void e_spell_dictionary_ignore_word (ESpellDictionary *dict,
+ const gchar *word,
+ gsize len);
+GList * e_spell_dictionary_get_suggestions
+ (ESpellDictionary *dict,
+ const gchar *word,
+ gsize len);
+void e_spell_dictionary_free_suggestions
+ (GList *suggestions);
+void e_spell_dictionary_store_correction
+ (ESpellDictionary *dict,
+ const gchar *misspelled,
+ gsize misspelled_len,
+ const gchar *correction,
+ gsize correction_len);
+
+ESpellChecker * e_spell_dictionary_get_parent_checker
+ (ESpellDictionary *dict);
+
+gint e_spell_dictionary_compare (ESpellDictionary *dict1,
+ ESpellDictionary *dict2);
+
+G_END_DECLS
+
+
+#endif /* E_SPELL_DICTIONARY_H */
\ No newline at end of file
diff --git a/e-util/e-util.h b/e-util/e-util.h
index 05f9709..1633702 100644
--- a/e-util/e-util.h
+++ b/e-util/e-util.h
@@ -103,7 +103,6 @@
#include <e-util/e-editor-replace-dialog.h>
#include <e-util/e-editor-selection.h>
#include <e-util/e-editor-spell-check-dialog.h>
-#include <e-util/e-editor-spell-checker.h>
#include <e-util/e-editor-table-dialog.h>
#include <e-util/e-editor-text-dialog.h>
#include <e-util/e-editor-utils.h>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]