]> git.lyx.org Git - features.git/commitdiff
* add support for the enchant spell checker (bug 6226).
authorJürgen Spitzmüller <spitz@lyx.org>
Fri, 22 Jan 2010 15:26:38 +0000 (15:26 +0000)
committerJürgen Spitzmüller <spitz@lyx.org>
Fri, 22 Jan 2010 15:26:38 +0000 (15:26 +0000)
SCons might be broken.

git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@33157 a592a061-630c-0410-9148-cb99ea01b6c8

config/spell.m4
development/scons/SConstruct
development/scons/scons_manifest.py
src/EnchantChecker.cpp [new file with mode: 0644]
src/EnchantChecker.h [new file with mode: 0644]
src/LyX.cpp
src/Makefile.am
src/frontends/qt4/GuiPrefs.cpp

index adce739c945b05ce93048cae0c1fa240ad54f2db..a7299490716408f3918af21eab869594ac1ae577 100644 (file)
@@ -23,6 +23,26 @@ AC_DEFUN([CHECK_WITH_ASPELL],
        fi
        ])
 
+# Macro to add for using enchant spellchecker libraries!     -*- sh -*-
+AC_DEFUN([CHECK_WITH_ENCHANT],
+[
+       lyx_use_enchant=true
+       AC_ARG_WITH(enchant, AC_HELP_STRING([--without-enchant],[do not check for Enchant library]))
+       test "$with_enchant" = "no" && lyx_use_enchant=false
+
+       if $lyx_use_enchant; then
+       PKG_CHECK_MODULES([ENCHANT], [enchant], [], [lyx_use_enchant=false])
+       AC_MSG_CHECKING([whether to use enchant])
+       if $lyx_use_enchant ; then
+           AC_MSG_RESULT(yes)
+           AC_DEFINE(USE_ENCHANT, 1, [Define as 1 to use the enchant library])
+           lyx_flags="$lyx_flags use-enchant"
+       else
+           AC_MSG_RESULT(no)
+       fi
+    fi
+    ])
+
 # Macro to add for using hunspell spellchecker libraries!     -*- sh -*-
 AC_DEFUN([CHECK_WITH_HUNSPELL],
 [
@@ -55,6 +75,11 @@ AC_DEFUN([LYX_CHECK_SPELL_ENGINES],
 
        AM_CONDITIONAL(USE_ASPELL, $lyx_use_aspell)
 
+       lyx_use_enchant=false
+       CHECK_WITH_ENCHANT
+
+       AM_CONDITIONAL(USE_ENCHANT, $lyx_use_enchant)
+
        lyx_use_hunspell=false
        CHECK_WITH_HUNSPELL
 
index 176b6e05d851ff0ec052cf7a60976fda09e87e14..e28e6f1de3f1fc41f9adc8bbecec164a12235a64 100644 (file)
@@ -136,7 +136,7 @@ opts.AddVariables(
             ) ),
     #
     EnumVariable('spell', 'Choose spell checker to use.', 'auto',
-               allowed_values = ('aspell', 'hunspell', 'auto', 'no') ),
+               allowed_values = ('aspell', 'enchant', 'hunspell', 'auto', 'no') ),
     # packaging method
     EnumVariable('packaging', 'Packaging method to use.', default_packaging_method,
         allowed_values = ('windows', 'posix', 'macosx')),
@@ -810,8 +810,14 @@ else:
 # determine headers to use
 spell_opt = ARGUMENTS.get('spell', 'auto')
 env['USE_ASPELL'] = False
+env['USE_ENCHANT'] = False
+env['USE_HUNSPELL'] = False
 if spell_opt in ['auto', 'aspell'] and conf.CheckLib(aspell_lib):
     spell_engine = 'USE_ASPELL'
+elif spell_opt in ['auto', 'enchant'] and conf.CheckLib('enchant'):
+    spell_engine = 'USE_ENCHANT'
+elif spell_opt in ['auto', 'hunspell'] and conf.CheckLib('enchant'):
+    spell_engine = 'USE_HUNSPELL'
 else:
     spell_engine = None
 
@@ -1069,7 +1075,7 @@ char * strerror(int n);
 )
 
 # these keys are needed in env
-for key in ['USE_ASPELL', 'HAVE_FCNTL',\
+for key in ['USE_ASPELL', 'USE_ENCHANT', 'USE_HUNSPELL', 'HAVE_FCNTL',\
     'HAVE_LIBGDI32', 'HAVE_LIBAIKSAURUS', 'AIKSAURUS_LIB']:
     # USE_ASPELL etc does not go through result
     if result.has_key(key):
@@ -1227,6 +1233,8 @@ libs = [
     ('HAVE_LIBGDI32', 'gdi32'),
     ('HAVE_LIBAIKSAURUS', env['AIKSAURUS_LIB']),
     ('USE_ASPELL', aspell_lib),
+    ('USE_ENCHANT', 'enchant'),
+    ('USE_HUNSPELL', 'hunspell')
 ]
 
 for lib in libs:
@@ -1547,6 +1555,10 @@ Alias('tex2lyx', tex2lyx)
 #
 if env.has_key('USE_ASPELL') and env['USE_ASPELL']:
     src_post_files.append('AspellChecker.cpp')
+elif env.has_key('USE_ENCHANT') and env['USE_ENCHANT']:
+    src_post_files.append('EnchantChecker.cpp')
+elif env.has_key('USE_HUNSPELL') and env['USE_HUNSPELL']:
+    src_post_files.append('HunspellChecker.cpp')
 
 # tells scons how to get these moced files, although not all moced files are needed
 # (or are actually generated).
index 962e28401676a271cd093975d9c6fdd6511022fe..166c16e485e1cfe9a81f82d7a37e82a7f6ca051c 100644 (file)
@@ -60,6 +60,7 @@ src_header_files = Split('''
     Dimension.h
     DispatchResult.h
     DocIterator.h
+    EnchantChecker.h
     Encoding.h
     ErrorList.h
     Exporter.h
@@ -251,6 +252,7 @@ src_post_files = Split('''
 
 src_extra_src_files = Split('''
     AspellChecker.cpp
+    EnchantChecker.cpp
     HunspellChecker.cpp
     main.cpp
     Section.cpp
diff --git a/src/EnchantChecker.cpp b/src/EnchantChecker.cpp
new file mode 100644 (file)
index 0000000..23cbee9
--- /dev/null
@@ -0,0 +1,163 @@
+/**
+ * \file EnchantChecker.cpp
+ * This file is part of LyX, the document processor.
+ * Licence details can be found in the file COPYING.
+ *
+ * \author Caolán McNamara
+ * \author Jürgen Spitzmüller
+ *
+ * Full author contact details are available in file CREDITS.
+ */
+
+#include <config.h>
+
+#include <enchant++.h>
+
+#include "EnchantChecker.h"
+#include "LyXRC.h"
+#include "WordLangTuple.h"
+
+#include "support/lassert.h"
+#include "support/debug.h"
+#include "support/docstring_list.h"
+
+#include <map>
+#include <string>
+
+using namespace std;
+
+namespace lyx {
+
+namespace {
+
+struct Speller {
+       enchant::Dict * speller;
+};
+
+typedef std::map<std::string, Speller> Spellers;
+  
+} // anon namespace
+
+struct EnchantChecker::Private
+{
+       Private() {}
+
+       ~Private();
+
+       /// add a speller of the given language
+       enchant::Dict * addSpeller(string const & lang);
+
+       ///
+       enchant::Dict * speller(string const & lang);
+
+       /// the spellers
+       Spellers spellers_;
+};
+
+
+EnchantChecker::Private::~Private()
+{
+       Spellers::iterator it = spellers_.begin();
+       Spellers::iterator end = spellers_.end();
+
+       for (; it != end; ++it) {
+               delete it->second.speller;
+       }
+}
+
+
+enchant::Dict * EnchantChecker::Private::addSpeller(string const & lang)
+{
+       enchant::Broker * instance = enchant::Broker::instance();
+       enchant::Dict * dict = instance->request_dict(lang);
+
+       if (dict) {
+               Speller m;
+               m.speller = dict;
+               spellers_[lang] = m;
+               return m.speller;
+       }
+       // FIXME error handling?
+       return 0;
+}
+
+
+enchant::Dict * EnchantChecker::Private::speller(string const & lang)
+{
+       Spellers::iterator it = spellers_.find(lang);
+       if (it != spellers_.end())
+               return it->second.speller;
+       
+       return addSpeller(lang);
+}
+
+
+EnchantChecker::EnchantChecker(): d(new Private)
+{
+}
+
+
+EnchantChecker::~EnchantChecker()
+{
+       delete d;
+}
+
+
+SpellChecker::Result EnchantChecker::check(WordLangTuple const & word)
+{
+       enchant::Dict * m = d->speller(word.lang_code());
+
+       if (!m)
+               return OK;
+
+       std::string utf8word(to_utf8(word.word()));
+
+       if (m->check(utf8word))
+               return OK;
+
+       return UNKNOWN_WORD;
+}
+
+
+void EnchantChecker::insert(WordLangTuple const & word)
+{
+       Spellers::iterator it = d->spellers_.find(word.lang_code());
+       if (it != d->spellers_.end())
+               it->second.speller->add(to_utf8(word.word()));
+}
+
+
+void EnchantChecker::accept(WordLangTuple const & word)
+{
+       Spellers::iterator it = d->spellers_.find(word.lang_code());
+       if (it != d->spellers_.end())
+               it->second.speller->add_to_session(to_utf8(word.word()));
+}
+
+
+void EnchantChecker::suggest(WordLangTuple const & wl,
+       docstring_list & suggestions)
+{
+       suggestions.clear();
+       enchant::Dict * m = d->speller(wl.lang_code());
+
+       if (!m)
+               return;
+
+       string utf8word = to_utf8(wl.word());
+
+       vector<string> suggs = m->suggest(utf8word);
+       vector<string>::const_iterator it = suggs.begin();
+       
+       for (; it != suggs.end(); ++it)
+               suggestions.push_back(from_utf8(*it));
+}
+
+
+docstring const EnchantChecker::error()
+{
+       return docstring();
+}
+
+
+} // namespace lyx
diff --git a/src/EnchantChecker.h b/src/EnchantChecker.h
new file mode 100644 (file)
index 0000000..e0954bc
--- /dev/null
@@ -0,0 +1,49 @@
+// -*- C++ -*-
+/**
+ * \file EnchantChecker.h
+ * This file is part of LyX, the document processor.
+ * Licence details can be found in the file COPYING.
+ *
+ * \author Caolán McNamara
+ * \author Jürgen Spitzmüller
+ *
+ * Full author contact details are available in file CREDITS.
+ */
+
+#ifndef LYX_ENCHANT_H
+#define LYX_ENCHANT_H
+
+#include "SpellChecker.h"
+
+namespace enchant {
+    class Dict;
+}
+
+namespace lyx {
+
+class BufferParams;
+
+
+class EnchantChecker : public SpellChecker {
+public:
+       EnchantChecker();
+       ~EnchantChecker();
+
+       /// SpellChecker inherited methods.
+       ///@{
+       enum Result check(WordLangTuple const &);
+       void suggest(WordLangTuple const &, docstring_list &);
+       void insert(WordLangTuple const &);
+       void accept(WordLangTuple const &);
+       docstring const error();
+       ///@}
+
+private:
+       struct Private;
+       Private * d;
+};
+
+
+} // namespace lyx
+
+#endif // LYX_ENCHANT_H
index 7b5c07636f00556e3b9fa21e5d44ecc3a9424b2c..02759cad546c9f4ebe9ba8258caa286332f1ccd2 100644 (file)
@@ -25,6 +25,7 @@
 #include "ConverterCache.h"
 #include "Converter.h"
 #include "CutAndPaste.h"
+#include "EnchantChecker.h"
 #include "Encoding.h"
 #include "ErrorList.h"
 #include "Format.h"
@@ -122,7 +123,7 @@ void reconfigureUserLyXDir()
 /// The main application class private implementation.
 struct LyX::Impl
 {
-       Impl() : spell_checker_(0), aspell_checker_(0), hunspell_checker_(0)
+       Impl() : spell_checker_(0), aspell_checker_(0), enchant_checker_(0), hunspell_checker_(0)
        {
                // Set the default User Interface language as soon as possible.
                // The language used will be derived from the environment
@@ -133,6 +134,7 @@ struct LyX::Impl
        ~Impl()
        {
                delete aspell_checker_;
+               delete enchant_checker_;
                delete hunspell_checker_;
        }
 
@@ -182,6 +184,8 @@ struct LyX::Impl
        ///
        SpellChecker * aspell_checker_;
        ///
+       SpellChecker * enchant_checker_;
+       ///
        SpellChecker * hunspell_checker_;
 };
 
@@ -1288,6 +1292,14 @@ void setSpellChecker()
                return;
        }
 #endif
+#if defined(USE_ENCHANT)
+       if (lyxrc.spellchecker == "enchant") {
+               if (!singleton_->pimpl_->enchant_checker_)
+                       singleton_->pimpl_->enchant_checker_ = new EnchantChecker();
+               singleton_->pimpl_->spell_checker_ = singleton_->pimpl_->enchant_checker_;
+               return;
+       }
+#endif
 #if defined(USE_HUNSPELL)
        if (lyxrc.spellchecker == "hunspell") {
                if (!singleton_->pimpl_->hunspell_checker_)
index 989438df0db895d06e33785eb9dcb4960cf8a1d3..54b8d65308393c314cfe9c53b80bbd65c7c245c2 100644 (file)
@@ -4,7 +4,7 @@ include $(top_srcdir)/config/common.am
 
 DISTCLEANFILES += config.h libintl.h
 
-AM_CPPFLAGS += $(PCH_FLAGS) -I$(top_srcdir)/src $(BOOST_INCLUDES)
+AM_CPPFLAGS += $(PCH_FLAGS) -I$(top_srcdir)/src $(BOOST_INCLUDES) $(ENCHANT_CFLAGS)
 AM_CPPFLAGS += $(QT4_CPPFLAGS) $(QT4_CORE_INCLUDES)
 
 if BUILD_CLIENT_SUBDIR
@@ -21,7 +21,7 @@ EXTRA_DIST = Section.h \
        pch.h
 
 OTHERLIBS = $(BOOST_LIBS) $(INTLLIBS) $(MYTHES_LIBS) $(AIKSAURUS_LIBS) \
-               @LIBS@ $(SOCKET_LIBS) $(LIBSHLWAPI) $(LIBPSAPI)
+                $(ENCHANT_LIBS) @LIBS@ $(SOCKET_LIBS) $(LIBSHLWAPI) $(LIBPSAPI)
 
 noinst_LIBRARIES = liblyxcore.a
 bin_PROGRAMS = lyx
@@ -52,6 +52,10 @@ if USE_ASPELL
 ASPELL = AspellChecker.cpp AspellChecker.h
 endif
 
+if USE_ENCHANT
+ENCHANT = EnchantChecker.cpp EnchantChecker.h
+endif
+
 if USE_HUNSPELL
 HUNSPELL = HunspellChecker.cpp HunspellChecker.h
 endif
@@ -71,6 +75,7 @@ lyx_SOURCES = \
        Compare.h \
        Dimension.cpp \
        Dimension.h \
+       $(ENCHANT) \
        $(HUNSPELL) \
        PrinterParams.cpp \
        PrinterParams.h \
index ea71bfdfce6cd660d2830918a588c178f0fcc9b6..4518838456d131f635df510acedb43869c3f44fb 100644 (file)
@@ -1312,10 +1312,13 @@ PrefSpellchecker::PrefSpellchecker(GuiPreferences * form)
        setupUi(this);
 
 #if defined(USE_ASPELL)
-       spellcheckerCB->addItem("aspell");
+       spellcheckerCB->addItem(qt_("aspell"), QString("aspell"));
+#endif
+#if defined(USE_ENCHANT)
+       spellcheckerCB->addItem(qt_("enchant"), QString("enchant"));
 #endif
 #if defined(USE_HUNSPELL)
-       spellcheckerCB->addItem("hunspell");
+       spellcheckerCB->addItem(qt_("hunspell"), QString("hunspell"));
 #endif
 
        if (theSpellChecker()) {
@@ -1341,7 +1344,8 @@ PrefSpellchecker::PrefSpellchecker(GuiPreferences * form)
 
 void PrefSpellchecker::apply(LyXRC & rc) const
 {
-       rc.spellchecker = fromqstr(spellcheckerCB->currentText());
+       rc.spellchecker = fromqstr(spellcheckerCB->itemData(
+                       spellcheckerCB->currentIndex()).toString());
        rc.spellchecker_alt_lang = fromqstr(altLanguageED->text());
        rc.spellchecker_esc_chars = fromqstr(escapeCharactersED->text());
        rc.spellchecker_accept_compound = compoundWordCB->isChecked();
@@ -1351,8 +1355,8 @@ void PrefSpellchecker::apply(LyXRC & rc) const
 
 void PrefSpellchecker::update(LyXRC const & rc)
 {
-       spellcheckerCB->setCurrentIndex(spellcheckerCB->findText(
-               toqstr(rc.spellchecker)));
+       spellcheckerCB->setCurrentIndex(
+               spellcheckerCB->findData(toqstr(rc.spellchecker)));
        altLanguageED->setText(toqstr(rc.spellchecker_alt_lang));
        escapeCharactersED->setText(toqstr(rc.spellchecker_esc_chars));
        compoundWordCB->setChecked(rc.spellchecker_accept_compound);