aboutsummaryrefslogtreecommitdiffstats
path: root/e-util/e-spell-entry.c
diff options
context:
space:
mode:
Diffstat (limited to 'e-util/e-spell-entry.c')
-rw-r--r--e-util/e-spell-entry.c373
1 files changed, 201 insertions, 172 deletions
diff --git a/e-util/e-spell-entry.c b/e-util/e-spell-entry.c
index 75c7a6a9c8..4993612a7a 100644
--- a/e-util/e-spell-entry.c
+++ b/e-util/e-spell-entry.c
@@ -23,8 +23,7 @@
#include <libebackend/libebackend.h>
-#include <editor/gtkhtml-spell-language.h>
-#include <editor/gtkhtml-spell-checker.h>
+#include <e-util/e-spell-checker.h>
#include "e-misc-utils.h"
#include "e-spell-entry.h"
@@ -37,18 +36,20 @@ struct _ESpellEntryPrivate {
PangoAttrList *attr_list;
gint mark_character;
gint entry_scroll_offset;
- GSettings *settings;
gboolean custom_checkers;
gboolean checking_enabled;
- GSList *checkers;
gchar **words;
gint *word_starts;
gint *word_ends;
+
+ ESpellChecker *spell_checker;
+ guint active_languages_handler_id;
};
enum {
PROP_0,
- PROP_CHECKING_ENABLED
+ PROP_CHECKING_ENABLED,
+ PROP_SPELL_CHECKER
};
G_DEFINE_TYPE_WITH_CODE (
@@ -76,16 +77,12 @@ word_misspelled (ESpellEntry *entry,
g_strlcpy (word, text + start, end - start + 1);
if (g_unichar_isalpha (*word)) {
- GSList *li;
+ ESpellChecker *spell_checker;
gssize wlen = strlen (word);
- for (li = entry->priv->checkers; li; li = g_slist_next (li)) {
- GtkhtmlSpellChecker *checker = li->data;
- if (gtkhtml_spell_checker_check_word (checker, word, wlen)) {
- result = FALSE;
- break;
- }
- }
+ spell_checker = e_spell_entry_get_spell_checker (entry);
+ if (e_spell_checker_check_word (spell_checker, word, wlen))
+ result = FALSE;
}
g_free (word);
@@ -160,8 +157,13 @@ spell_entry_recheck_all (ESpellEntry *entry)
pango_attr_list_unref (entry->priv->attr_list);
entry->priv->attr_list = pango_attr_list_new ();
- if (e_spell_entry_get_checking_enabled (entry))
- check_words = (entry->priv->checkers != NULL);
+ if (e_spell_entry_get_checking_enabled (entry)) {
+ ESpellChecker *spell_checker;
+
+ spell_checker = e_spell_entry_get_spell_checker (entry);
+ if (e_spell_checker_count_active_languages (spell_checker) > 0)
+ check_words = TRUE;
+ }
if (check_words) {
/* Loop through words */
@@ -269,15 +271,15 @@ add_to_dictionary (GtkWidget *menuitem,
{
gchar *word;
gint start, end;
- GtkhtmlSpellChecker *checker;
+ ESpellDictionary *dict;
get_word_extents_from_position (
entry, &start, &end, entry->priv->mark_character);
word = gtk_editable_get_chars (GTK_EDITABLE (entry), start, end);
- checker = g_object_get_data (G_OBJECT (menuitem), "spell-entry-checker");
- if (checker != NULL)
- gtkhtml_spell_checker_add_word (checker, word, -1);
+ dict = g_object_get_data (G_OBJECT (menuitem), "spell-entry-checker");
+ if (dict != NULL)
+ e_spell_dictionary_learn_word (dict, word, -1);
g_free (word);
@@ -300,18 +302,16 @@ static void
ignore_all (GtkWidget *menuitem,
ESpellEntry *entry)
{
+ ESpellChecker *spell_checker;
gchar *word;
gint start, end;
- GSList *li;
get_word_extents_from_position (
entry, &start, &end, entry->priv->mark_character);
word = gtk_editable_get_chars (GTK_EDITABLE (entry), start, end);
- for (li = entry->priv->checkers; li; li = g_slist_next (li)) {
- GtkhtmlSpellChecker *checker = li->data;
- gtkhtml_spell_checker_add_word_to_session (checker, word, -1);
- }
+ spell_checker = e_spell_entry_get_spell_checker (entry);
+ e_spell_checker_ignore_word (spell_checker, word);
g_free (word);
@@ -338,7 +338,7 @@ replace_word (GtkWidget *menuitem,
const gchar *newword;
gint start, end;
gint cursor;
- GtkhtmlSpellChecker *checker;
+ ESpellDictionary *dict;
get_word_extents_from_position (
entry, &start, &end, entry->priv->mark_character);
@@ -359,11 +359,11 @@ replace_word (GtkWidget *menuitem,
GTK_EDITABLE (entry), newword, strlen (newword), &start);
gtk_editable_set_position (GTK_EDITABLE (entry), cursor);
- checker = g_object_get_data (G_OBJECT (menuitem), "spell-entry-checker");
+ dict = g_object_get_data (G_OBJECT (menuitem), "spell-entry-checker");
- if (checker != NULL)
- gtkhtml_spell_checker_store_replacement (
- checker, oldword, -1, newword, -1);
+ if (dict != NULL)
+ e_spell_dictionary_store_correction (
+ dict, oldword, -1, newword, -1);
g_free (oldword);
}
@@ -371,13 +371,13 @@ replace_word (GtkWidget *menuitem,
static void
build_suggestion_menu (ESpellEntry *entry,
GtkWidget *menu,
- GtkhtmlSpellChecker *checker,
+ ESpellDictionary *dict,
const gchar *word)
{
GtkWidget *mi;
GList *suggestions, *iter;
- suggestions = gtkhtml_spell_checker_get_suggestions (checker, word, -1);
+ suggestions = e_spell_dictionary_get_suggestions (dict, word, -1);
if (suggestions == NULL) {
/* no suggestions. Put something in the menu anyway... */
@@ -414,7 +414,7 @@ build_suggestion_menu (ESpellEntry *entry,
}
mi = gtk_menu_item_new_with_label (iter->data);
- g_object_set_data (G_OBJECT (mi), "spell-entry-checker", checker);
+ g_object_set_data (G_OBJECT (mi), "spell-entry-checker", dict);
g_signal_connect (mi, "activate", G_CALLBACK (replace_word), entry);
gtk_widget_show (mi);
gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi);
@@ -428,35 +428,49 @@ static GtkWidget *
build_spelling_menu (ESpellEntry *entry,
const gchar *word)
{
- GtkhtmlSpellChecker *checker;
+ ESpellChecker *spell_checker;
+ ESpellDictionary *dict;
GtkWidget *topmenu, *mi;
+ GQueue queue = G_QUEUE_INIT;
+ gchar **active_languages;
+ guint ii, n_active_languages;
gchar *label;
topmenu = gtk_menu_new ();
- if (entry->priv->checkers == NULL)
- return topmenu;
+ spell_checker = e_spell_entry_get_spell_checker (entry);
+
+ active_languages = e_spell_checker_list_active_languages (
+ spell_checker, &n_active_languages);
+ for (ii = 0; ii < n_active_languages; ii++) {
+ dict = e_spell_checker_ref_dictionary (
+ spell_checker, active_languages[ii]);
+ if (dict != NULL)
+ g_queue_push_tail (&queue, dict);
+ }
+ g_strfreev (active_languages);
+
+ if (g_queue_is_empty (&queue))
+ goto exit;
/* Suggestions */
- if (entry->priv->checkers->next == NULL) {
- checker = entry->priv->checkers->data;
- build_suggestion_menu (entry, topmenu, checker, word);
+ if (n_active_languages == 1) {
+ dict = g_queue_peek_head (&queue);
+ build_suggestion_menu (entry, topmenu, dict, word);
} else {
- GSList *li;
GtkWidget *menu;
- const gchar *lang_name;
+ GList *list, *link;
- for (li = entry->priv->checkers; li; li = g_slist_next (li)) {
- const GtkhtmlSpellLanguage *language;
+ list = g_queue_peek_head_link (&queue);
- checker = li->data;
- language = gtkhtml_spell_checker_get_language (checker);
- if (language == NULL)
- continue;
+ for (link = list; link != NULL; link = g_list_next (link)) {
+ const gchar *lang_name;
- lang_name = gtkhtml_spell_language_get_name (language);
+ dict = E_SPELL_DICTIONARY (link->data);
+
+ lang_name = e_spell_dictionary_get_name (dict);
if (lang_name == NULL)
- lang_name = gtkhtml_spell_language_get_code (language);
+ lang_name = e_spell_dictionary_get_code (dict);
if (lang_name == NULL)
lang_name = "???";
@@ -466,7 +480,7 @@ build_spelling_menu (ESpellEntry *entry,
gtk_menu_shell_append (GTK_MENU_SHELL (topmenu), mi);
menu = gtk_menu_new ();
gtk_menu_item_set_submenu (GTK_MENU_ITEM (mi), menu);
- build_suggestion_menu (entry, menu, checker, word);
+ build_suggestion_menu (entry, menu, dict, word);
}
}
@@ -484,36 +498,34 @@ build_spelling_menu (ESpellEntry *entry,
GTK_IMAGE_MENU_ITEM (mi),
gtk_image_new_from_icon_name ("list-add", GTK_ICON_SIZE_MENU));
- if (entry->priv->checkers->next == NULL) {
- checker = entry->priv->checkers->data;
- g_object_set_data (G_OBJECT (mi), "spell-entry-checker", checker);
+ if (n_active_languages == 1) {
+ dict = g_queue_peek_head (&queue);
+ g_object_set_data (G_OBJECT (mi), "spell-entry-checker", dict);
g_signal_connect (
mi, "activate",
G_CALLBACK (add_to_dictionary), entry);
} else {
- GSList *li;
GtkWidget *menu, *submi;
- const gchar *lang_name;
+ GList *list, *link;
menu = gtk_menu_new ();
gtk_menu_item_set_submenu (GTK_MENU_ITEM (mi), menu);
- for (li = entry->priv->checkers; li; li = g_slist_next (li)) {
- const GtkhtmlSpellLanguage *language;
+ list = g_queue_peek_head_link (&queue);
- checker = li->data;
- language = gtkhtml_spell_checker_get_language (checker);
- if (language == NULL)
- continue;
+ for (link = list; link != NULL; link = g_list_next (link)) {
+ const gchar *lang_name;
+
+ dict = E_SPELL_DICTIONARY (link->data);
- lang_name = gtkhtml_spell_language_get_name (language);
+ lang_name = e_spell_dictionary_get_name (dict);
if (lang_name == NULL)
- lang_name = gtkhtml_spell_language_get_code (language);
+ lang_name = e_spell_dictionary_get_code (dict);
if (lang_name == NULL)
lang_name = "???";
submi = gtk_menu_item_new_with_label (lang_name);
- g_object_set_data (G_OBJECT (submi), "spell-entry-checker", checker);
+ g_object_set_data (G_OBJECT (submi), "spell-entry-checker", dict);
g_signal_connect (
submi, "activate",
G_CALLBACK (add_to_dictionary), entry);
@@ -535,6 +547,10 @@ build_spelling_menu (ESpellEntry *entry,
gtk_widget_show_all (mi);
gtk_menu_shell_append (GTK_MENU_SHELL (topmenu), mi);
+exit:
+ while (!g_queue_is_empty (&queue))
+ g_object_unref (g_queue_pop_head (&queue));
+
return topmenu;
}
@@ -580,10 +596,12 @@ spell_entry_populate_popup (ESpellEntry *entry,
GtkMenu *menu,
gpointer data)
{
+ ESpellChecker *spell_checker;
gint start, end;
gchar *word;
- if (entry->priv->checkers == NULL)
+ spell_checker = e_spell_entry_get_spell_checker (entry);
+ if (e_spell_checker_count_active_languages (spell_checker) == 0)
return;
get_word_extents_from_position (
@@ -606,8 +624,10 @@ static void
spell_entry_changed (GtkEditable *editable)
{
ESpellEntry *entry = E_SPELL_ENTRY (editable);
+ ESpellChecker *spell_checker;
- if (entry->priv->checkers == NULL)
+ spell_checker = e_spell_entry_get_spell_checker (entry);
+ if (e_spell_checker_count_active_languages (spell_checker) == 0)
return;
if (entry->priv->words != NULL) {
@@ -633,70 +653,6 @@ spell_entry_notify_scroll_offset (ESpellEntry *spell_entry)
&spell_entry->priv->entry_scroll_offset, NULL);
}
-static GList *
-spell_entry_load_spell_languages (void)
-{
- GSettings *settings;
- GList *spell_languages = NULL;
- gchar **strv;
- gint ii;
-
- /* Ask GSettings for a list of spell check language codes. */
- settings = g_settings_new ("org.gnome.evolution.mail");
- strv = g_settings_get_strv (settings, "composer-spell-languages");
- g_object_unref (settings);
-
- /* Convert the codes to spell language structs. */
- for (ii = 0; strv[ii] != NULL; ii++) {
- gchar *language_code = strv[ii];
- const GtkhtmlSpellLanguage *language;
-
- language = gtkhtml_spell_language_lookup (language_code);
- if (language != NULL)
- spell_languages = g_list_prepend (
- spell_languages, (gpointer) language);
- }
-
- g_strfreev (strv);
-
- spell_languages = g_list_reverse (spell_languages);
-
- /* Pick a default spell language if it came back empty. */
- if (spell_languages == NULL) {
- const GtkhtmlSpellLanguage *language;
-
- language = gtkhtml_spell_language_lookup (NULL);
-
- if (language) {
- spell_languages = g_list_prepend (
- spell_languages, (gpointer) language);
- }
- }
-
- return spell_languages;
-}
-
-static void
-spell_entry_settings_changed (ESpellEntry *spell_entry,
- const gchar *key)
-{
- GList *languages;
-
- g_return_if_fail (spell_entry != NULL);
-
- if (spell_entry->priv->custom_checkers)
- return;
-
- if (key && !g_str_equal (key, "composer-spell-languages"))
- return;
-
- languages = spell_entry_load_spell_languages ();
- e_spell_entry_set_languages (spell_entry, languages);
- g_list_free (languages);
-
- spell_entry->priv->custom_checkers = FALSE;
-}
-
static gint
spell_entry_find_position (ESpellEntry *spell_entry,
gint x)
@@ -722,6 +678,15 @@ spell_entry_find_position (ESpellEntry *spell_entry,
}
static void
+spell_entry_active_languages_cb (ESpellChecker *spell_checker,
+ GParamSpec *pspec,
+ ESpellEntry *spell_entry)
+{
+ if (gtk_widget_get_realized (GTK_WIDGET (spell_entry)))
+ spell_entry_recheck_all (spell_entry);
+}
+
+static void
spell_entry_set_property (GObject *object,
guint property_id,
const GValue *value,
@@ -733,6 +698,12 @@ spell_entry_set_property (GObject *object,
E_SPELL_ENTRY (object),
g_value_get_boolean (value));
return;
+
+ case PROP_SPELL_CHECKER:
+ e_spell_entry_set_spell_checker (
+ E_SPELL_ENTRY (object),
+ g_value_get_object (value));
+ return;
}
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -751,6 +722,13 @@ spell_entry_get_property (GObject *object,
e_spell_entry_get_checking_enabled (
E_SPELL_ENTRY (object)));
return;
+
+ case PROP_SPELL_CHECKER:
+ g_value_set_object (
+ value,
+ e_spell_entry_get_spell_checker (
+ E_SPELL_ENTRY (object)));
+ return;
}
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -763,10 +741,14 @@ spell_entry_dispose (GObject *object)
priv = E_SPELL_ENTRY_GET_PRIVATE (object);
- g_slist_free_full (priv->checkers, (GDestroyNotify) g_object_unref);
- priv->checkers = NULL;
+ if (priv->active_languages_handler_id > 0) {
+ g_signal_handler_disconnect (
+ priv->spell_checker,
+ priv->active_languages_handler_id);
+ priv->active_languages_handler_id = 0;
+ }
- g_clear_object (&priv->settings);
+ g_clear_object (&priv->spell_checker);
if (priv->attr_list != NULL) {
pango_attr_list_unref (priv->attr_list);
@@ -795,9 +777,22 @@ spell_entry_finalize (GObject *object)
static void
spell_entry_constructed (GObject *object)
{
+ ESpellEntry *spell_entry;
+ ESpellChecker *spell_checker;
+
+ spell_entry = E_SPELL_ENTRY (object);
+
/* Chain up to parent's constructed() method. */
G_OBJECT_CLASS (e_spell_entry_parent_class)->constructed (object);
+ /* Install a default spell checker if there is not one already. */
+ spell_checker = e_spell_entry_get_spell_checker (spell_entry);
+ if (spell_checker == NULL) {
+ spell_checker = e_spell_checker_new ();
+ e_spell_entry_set_spell_checker (spell_entry, spell_checker);
+ g_object_unref (spell_checker);
+ }
+
e_extensible_load_extensions (E_EXTENSIBLE (object));
}
@@ -860,6 +855,17 @@ e_spell_entry_class_init (ESpellEntryClass *class)
TRUE,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_SPELL_CHECKER,
+ g_param_spec_object (
+ "spell-checker",
+ "Spell Checker",
+ "The spell checker object",
+ E_TYPE_SPELL_CHECKER,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS));
}
static void
@@ -867,7 +873,6 @@ e_spell_entry_init (ESpellEntry *spell_entry)
{
spell_entry->priv = E_SPELL_ENTRY_GET_PRIVATE (spell_entry);
spell_entry->priv->attr_list = pango_attr_list_new ();
- spell_entry->priv->checkers = NULL;
spell_entry->priv->checking_enabled = TRUE;
g_signal_connect (
@@ -882,15 +887,6 @@ e_spell_entry_init (ESpellEntry *spell_entry)
e_signal_connect_notify (
spell_entry, "notify::scroll-offset",
G_CALLBACK (spell_entry_notify_scroll_offset), NULL);
-
- /* listen for languages changes */
- spell_entry->priv->settings = g_settings_new ("org.gnome.evolution.mail");
- g_signal_connect_swapped (
- spell_entry->priv->settings, "changed",
- G_CALLBACK (spell_entry_settings_changed), spell_entry);
-
- /* load current settings */
- spell_entry_settings_changed (spell_entry, NULL);
}
GtkWidget *
@@ -899,36 +895,6 @@ e_spell_entry_new (void)
return g_object_new (E_TYPE_SPELL_ENTRY, NULL);
}
-/* 'languages' consists of 'const GtkhtmlSpellLanguage *' */
-void
-e_spell_entry_set_languages (ESpellEntry *spell_entry,
- GList *languages)
-{
- GList *iter;
-
- g_return_if_fail (spell_entry != NULL);
-
- spell_entry->priv->custom_checkers = TRUE;
-
- if (spell_entry->priv->checkers)
- g_slist_free_full (spell_entry->priv->checkers, g_object_unref);
- spell_entry->priv->checkers = NULL;
-
- for (iter = languages; iter; iter = g_list_next (iter)) {
- const GtkhtmlSpellLanguage *language = iter->data;
-
- if (language)
- spell_entry->priv->checkers = g_slist_prepend (
- spell_entry->priv->checkers,
- gtkhtml_spell_checker_new (language));
- }
-
- spell_entry->priv->checkers = g_slist_reverse (spell_entry->priv->checkers);
-
- if (gtk_widget_get_realized (GTK_WIDGET (spell_entry)))
- spell_entry_recheck_all (spell_entry);
-}
-
gboolean
e_spell_entry_get_checking_enabled (ESpellEntry *spell_entry)
{
@@ -951,3 +917,66 @@ e_spell_entry_set_checking_enabled (ESpellEntry *spell_entry,
g_object_notify (G_OBJECT (spell_entry), "checking-enabled");
}
+
+/**
+ * e_spell_entry_get_spell_checker:
+ * @spell_entry: an #ESpellEntry
+ *
+ * Returns the #ESpellChecker being used for spell checking. By default,
+ * #ESpellEntry creates its own #ESpellChecker, but this can be overridden
+ * through e_spell_entry_set_spell_checker().
+ *
+ * Returns: an #ESpellChecker
+ **/
+ESpellChecker *
+e_spell_entry_get_spell_checker (ESpellEntry *spell_entry)
+{
+ g_return_val_if_fail (E_IS_SPELL_ENTRY (spell_entry), NULL);
+
+ return spell_entry->priv->spell_checker;
+}
+
+/**
+ * e_spell_entry_set_spell_checker:
+ * @spell_entry: an #ESpellEntry
+ * @spell_checker: an #ESpellChecker
+ *
+ * Sets the #ESpellChecker to use for spell checking. By default,
+ * #ESpellEntry creates its own #ESpellChecker. This function can be
+ * useful for sharing an #ESpellChecker across multiple spell-checking
+ * widgets, so the active spell checking languages stay synchronized.
+ **/
+void
+e_spell_entry_set_spell_checker (ESpellEntry *spell_entry,
+ ESpellChecker *spell_checker)
+{
+ gulong handler_id;
+
+ g_return_if_fail (E_IS_SPELL_ENTRY (spell_entry));
+ g_return_if_fail (E_IS_SPELL_CHECKER (spell_checker));
+
+ if (spell_checker == spell_entry->priv->spell_checker)
+ return;
+
+ if (spell_entry->priv->spell_checker != NULL) {
+ g_signal_handler_disconnect (
+ spell_entry->priv->spell_checker,
+ spell_entry->priv->active_languages_handler_id);
+ g_object_unref (spell_entry->priv->spell_checker);
+ }
+
+ spell_entry->priv->spell_checker = g_object_ref (spell_checker);
+
+ handler_id = g_signal_connect (
+ spell_checker, "notify::active-languages",
+ G_CALLBACK (spell_entry_active_languages_cb),
+ spell_entry);
+
+ spell_entry->priv->active_languages_handler_id = handler_id;
+
+ g_object_notify (G_OBJECT (spell_entry), "spell-checker");
+
+ if (gtk_widget_get_realized (GTK_WIDGET (spell_entry)))
+ spell_entry_recheck_all (spell_entry);
+}
+