diff options
Diffstat (limited to 'e-util/e-spell-entry.c')
-rw-r--r-- | e-util/e-spell-entry.c | 373 |
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); +} + |