summaryrefslogtreecommitdiff
path: root/plugins/spell/pluma-spell-checker.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/spell/pluma-spell-checker.c')
-rwxr-xr-xplugins/spell/pluma-spell-checker.c520
1 files changed, 520 insertions, 0 deletions
diff --git a/plugins/spell/pluma-spell-checker.c b/plugins/spell/pluma-spell-checker.c
new file mode 100755
index 00000000..24cfcdd5
--- /dev/null
+++ b/plugins/spell/pluma-spell-checker.c
@@ -0,0 +1,520 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * pluma-spell-checker.c
+ * This file is part of pluma
+ *
+ * Copyright (C) 2002-2006 Paolo Maggi
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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.
+ */
+
+/*
+ * Modified by the pluma Team, 2002-2006. See the AUTHORS file for a
+ * list of people on the pluma Team.
+ * See the ChangeLog files for a list of changes.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include <enchant.h>
+
+#include <glib/gi18n.h>
+#include <glib.h>
+
+#include "pluma-spell-checker.h"
+#include "pluma-spell-utils.h"
+#include "pluma-spell-marshal.h"
+
+struct _PlumaSpellChecker
+{
+ GObject parent_instance;
+
+ EnchantDict *dict;
+ EnchantBroker *broker;
+ const PlumaSpellCheckerLanguage *active_lang;
+};
+
+/* GObject properties */
+enum {
+ PROP_0 = 0,
+ PROP_LANGUAGE,
+ LAST_PROP
+};
+
+/* Signals */
+enum {
+ ADD_WORD_TO_PERSONAL = 0,
+ ADD_WORD_TO_SESSION,
+ SET_LANGUAGE,
+ CLEAR_SESSION,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+G_DEFINE_TYPE(PlumaSpellChecker, pluma_spell_checker, G_TYPE_OBJECT)
+
+static void
+pluma_spell_checker_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ /*
+ PlumaSpellChecker *spell = PLUMA_SPELL_CHECKER (object);
+ */
+
+ switch (prop_id)
+ {
+ case PROP_LANGUAGE:
+ /* TODO */
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+pluma_spell_checker_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ /*
+ PlumaSpellChecker *spell = PLUMA_SPELL_CHECKER (object);
+ */
+
+ switch (prop_id)
+ {
+ case PROP_LANGUAGE:
+ /* TODO */
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+pluma_spell_checker_finalize (GObject *object)
+{
+ PlumaSpellChecker *spell_checker;
+
+ g_return_if_fail (PLUMA_IS_SPELL_CHECKER (object));
+
+ spell_checker = PLUMA_SPELL_CHECKER (object);
+
+ if (spell_checker->dict != NULL)
+ enchant_broker_free_dict (spell_checker->broker, spell_checker->dict);
+
+ if (spell_checker->broker != NULL)
+ enchant_broker_free (spell_checker->broker);
+
+ G_OBJECT_CLASS (pluma_spell_checker_parent_class)->finalize (object);
+}
+
+static void
+pluma_spell_checker_class_init (PlumaSpellCheckerClass * klass)
+{
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (klass);
+
+ object_class->set_property = pluma_spell_checker_set_property;
+ object_class->get_property = pluma_spell_checker_get_property;
+
+ object_class->finalize = pluma_spell_checker_finalize;
+
+ g_object_class_install_property (object_class,
+ PROP_LANGUAGE,
+ g_param_spec_pointer ("language",
+ "Language",
+ "The language used by the spell checker",
+ G_PARAM_READWRITE));
+
+ signals[ADD_WORD_TO_PERSONAL] =
+ g_signal_new ("add_word_to_personal",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (PlumaSpellCheckerClass, add_word_to_personal),
+ NULL, NULL,
+ pluma_marshal_VOID__STRING_INT,
+ G_TYPE_NONE,
+ 2,
+ G_TYPE_STRING,
+ G_TYPE_INT);
+
+ signals[ADD_WORD_TO_SESSION] =
+ g_signal_new ("add_word_to_session",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (PlumaSpellCheckerClass, add_word_to_session),
+ NULL, NULL,
+ pluma_marshal_VOID__STRING_INT,
+ G_TYPE_NONE,
+ 2,
+ G_TYPE_STRING,
+ G_TYPE_INT);
+
+ signals[SET_LANGUAGE] =
+ g_signal_new ("set_language",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (PlumaSpellCheckerClass, set_language),
+ NULL, NULL,
+ pluma_marshal_VOID__POINTER,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_POINTER);
+
+ signals[CLEAR_SESSION] =
+ g_signal_new ("clear_session",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (PlumaSpellCheckerClass, clear_session),
+ NULL, NULL,
+ pluma_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+}
+
+static void
+pluma_spell_checker_init (PlumaSpellChecker *spell_checker)
+{
+ spell_checker->broker = enchant_broker_init ();
+ spell_checker->dict = NULL;
+ spell_checker->active_lang = NULL;
+}
+
+PlumaSpellChecker *
+pluma_spell_checker_new (void)
+{
+ PlumaSpellChecker *spell;
+
+ spell = PLUMA_SPELL_CHECKER (
+ g_object_new (PLUMA_TYPE_SPELL_CHECKER, NULL));
+
+ g_return_val_if_fail (spell != NULL, NULL);
+
+ return spell;
+}
+
+static gboolean
+lazy_init (PlumaSpellChecker *spell,
+ const PlumaSpellCheckerLanguage *language)
+{
+ if (spell->dict != NULL)
+ return TRUE;
+
+ g_return_val_if_fail (spell->broker != NULL, FALSE);
+
+ spell->active_lang = NULL;
+
+ if (language != NULL)
+ {
+ spell->active_lang = language;
+ }
+ else
+ {
+ /* First try to get a default language */
+ const PlumaSpellCheckerLanguage *l;
+ gint i = 0;
+ const gchar * const *lang_tags = g_get_language_names ();
+
+ while (lang_tags [i])
+ {
+ l = pluma_spell_checker_language_from_key (lang_tags [i]);
+
+ if (l != NULL)
+ {
+ spell->active_lang = l;
+ break;
+ }
+
+ i++;
+ }
+ }
+
+ /* Second try to get a default language */
+ if (spell->active_lang == NULL)
+ spell->active_lang = pluma_spell_checker_language_from_key ("en_US");
+
+ /* Last try to get a default language */
+ if (spell->active_lang == NULL)
+ {
+ const GSList *langs;
+ langs = pluma_spell_checker_get_available_languages ();
+ if (langs != NULL)
+ spell->active_lang = (const PlumaSpellCheckerLanguage *)langs->data;
+ }
+
+ if (spell->active_lang != NULL)
+ {
+ const gchar *key;
+
+ key = pluma_spell_checker_language_to_key (spell->active_lang);
+
+ spell->dict = enchant_broker_request_dict (spell->broker,
+ key);
+ }
+
+ if (spell->dict == NULL)
+ {
+ spell->active_lang = NULL;
+
+ if (language != NULL)
+ g_warning ("Spell checker plugin: cannot select a default language.");
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+gboolean
+pluma_spell_checker_set_language (PlumaSpellChecker *spell,
+ const PlumaSpellCheckerLanguage *language)
+{
+ gboolean ret;
+
+ g_return_val_if_fail (PLUMA_IS_SPELL_CHECKER (spell), FALSE);
+
+ if (spell->dict != NULL)
+ {
+ enchant_broker_free_dict (spell->broker, spell->dict);
+ spell->dict = NULL;
+ }
+
+ ret = lazy_init (spell, language);
+
+ if (ret)
+ g_signal_emit (G_OBJECT (spell), signals[SET_LANGUAGE], 0, language);
+ else
+ g_warning ("Spell checker plugin: cannot use language %s.",
+ pluma_spell_checker_language_to_string (language));
+
+ return ret;
+}
+
+const PlumaSpellCheckerLanguage *
+pluma_spell_checker_get_language (PlumaSpellChecker *spell)
+{
+ g_return_val_if_fail (PLUMA_IS_SPELL_CHECKER (spell), NULL);
+
+ if (!lazy_init (spell, spell->active_lang))
+ return NULL;
+
+ return spell->active_lang;
+}
+
+gboolean
+pluma_spell_checker_check_word (PlumaSpellChecker *spell,
+ const gchar *word,
+ gssize len)
+{
+ gint enchant_result;
+ gboolean res = FALSE;
+
+ g_return_val_if_fail (PLUMA_IS_SPELL_CHECKER (spell), FALSE);
+ g_return_val_if_fail (word != NULL, FALSE);
+
+ if (!lazy_init (spell, spell->active_lang))
+ return FALSE;
+
+ if (len < 0)
+ len = strlen (word);
+
+ if (strcmp (word, "pluma") == 0)
+ return TRUE;
+
+ if (pluma_spell_utils_is_digit (word, len))
+ return TRUE;
+
+ g_return_val_if_fail (spell->dict != NULL, FALSE);
+ enchant_result = enchant_dict_check (spell->dict, word, len);
+
+ switch (enchant_result)
+ {
+ case -1:
+ /* error */
+ res = FALSE;
+
+ g_warning ("Spell checker plugin: error checking word '%s' (%s).",
+ word, enchant_dict_get_error (spell->dict));
+
+ break;
+ case 1:
+ /* it is not in the directory */
+ res = FALSE;
+ break;
+ case 0:
+ /* is is in the directory */
+ res = TRUE;
+ break;
+ default:
+ g_return_val_if_reached (FALSE);
+ }
+
+ return res;
+}
+
+
+/* return NULL on error or if no suggestions are found */
+GSList *
+pluma_spell_checker_get_suggestions (PlumaSpellChecker *spell,
+ const gchar *word,
+ gssize len)
+{
+ gchar **suggestions;
+ size_t n_suggestions = 0;
+ GSList *suggestions_list = NULL;
+ gint i;
+
+ g_return_val_if_fail (PLUMA_IS_SPELL_CHECKER (spell), NULL);
+ g_return_val_if_fail (word != NULL, NULL);
+
+ if (!lazy_init (spell, spell->active_lang))
+ return NULL;
+
+ g_return_val_if_fail (spell->dict != NULL, NULL);
+
+ if (len < 0)
+ len = strlen (word);
+
+ suggestions = enchant_dict_suggest (spell->dict, word, len, &n_suggestions);
+
+ if (n_suggestions == 0)
+ return NULL;
+
+ g_return_val_if_fail (suggestions != NULL, NULL);
+
+ for (i = 0; i < (gint)n_suggestions; i++)
+ {
+ suggestions_list = g_slist_prepend (suggestions_list,
+ suggestions[i]);
+ }
+
+ /* The single suggestions will be freed by the caller */
+ g_free (suggestions);
+
+ suggestions_list = g_slist_reverse (suggestions_list);
+
+ return suggestions_list;
+}
+
+gboolean
+pluma_spell_checker_add_word_to_personal (PlumaSpellChecker *spell,
+ const gchar *word,
+ gssize len)
+{
+ g_return_val_if_fail (PLUMA_IS_SPELL_CHECKER (spell), FALSE);
+ g_return_val_if_fail (word != NULL, FALSE);
+
+ if (!lazy_init (spell, spell->active_lang))
+ return FALSE;
+
+ g_return_val_if_fail (spell->dict != NULL, FALSE);
+
+ if (len < 0)
+ len = strlen (word);
+
+ enchant_dict_add_to_pwl (spell->dict, word, len);
+
+ g_signal_emit (G_OBJECT (spell), signals[ADD_WORD_TO_PERSONAL], 0, word, len);
+
+ return TRUE;
+}
+
+gboolean
+pluma_spell_checker_add_word_to_session (PlumaSpellChecker *spell,
+ const gchar *word,
+ gssize len)
+{
+ g_return_val_if_fail (PLUMA_IS_SPELL_CHECKER (spell), FALSE);
+ g_return_val_if_fail (word != NULL, FALSE);
+
+ if (!lazy_init (spell, spell->active_lang))
+ return FALSE;
+
+ g_return_val_if_fail (spell->dict != NULL, FALSE);
+
+ if (len < 0)
+ len = strlen (word);
+
+ enchant_dict_add_to_session (spell->dict, word, len);
+
+ g_signal_emit (G_OBJECT (spell), signals[ADD_WORD_TO_SESSION], 0, word, len);
+
+ return TRUE;
+}
+
+gboolean
+pluma_spell_checker_clear_session (PlumaSpellChecker *spell)
+{
+ g_return_val_if_fail (PLUMA_IS_SPELL_CHECKER (spell), FALSE);
+
+ /* free and re-request dictionary */
+ if (spell->dict != NULL)
+ {
+ enchant_broker_free_dict (spell->broker, spell->dict);
+ spell->dict = NULL;
+ }
+
+ if (!lazy_init (spell, spell->active_lang))
+ return FALSE;
+
+ g_signal_emit (G_OBJECT (spell), signals[CLEAR_SESSION], 0);
+
+ return TRUE;
+}
+
+/*
+ * Informs dictionary, that word 'word' will be replaced/corrected by word
+ * 'replacement'
+ */
+gboolean
+pluma_spell_checker_set_correction (PlumaSpellChecker *spell,
+ const gchar *word,
+ gssize w_len,
+ const gchar *replacement,
+ gssize r_len)
+{
+ g_return_val_if_fail (PLUMA_IS_SPELL_CHECKER (spell), FALSE);
+ g_return_val_if_fail (word != NULL, FALSE);
+ g_return_val_if_fail (replacement != NULL, FALSE);
+
+ if (!lazy_init (spell, spell->active_lang))
+ return FALSE;
+
+ g_return_val_if_fail (spell->dict != NULL, FALSE);
+
+ if (w_len < 0)
+ w_len = strlen (word);
+
+ if (r_len < 0)
+ r_len = strlen (replacement);
+
+ enchant_dict_store_replacement (spell->dict,
+ word,
+ w_len,
+ replacement,
+ r_len);
+
+ return TRUE;
+}
+