* add support for the enchant spell checker (bug 6226).

SCons might be broken.

git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@33157 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
Jürgen Spitzmüller 2010-01-22 15:26:38 +00:00
parent 4322d35b15
commit 7746747506
8 changed files with 282 additions and 10 deletions

View 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

View 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).

View 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

163
src/EnchantChecker.cpp Normal file
View File

@ -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

49
src/EnchantChecker.h Normal file
View File

@ -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

View 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_)

View 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 \

View 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);