19 #include "QtSpell.hpp"
20 #include "Checker_p.hpp"
21 #include "Codetable.hpp"
23 #include <enchant++.h>
24 #include <QActionGroup>
25 #include <QApplication>
26 #include <QLibraryInfo>
29 #include <QTranslator>
32 static void dict_describe_cb(
const char*
const lang_tag,
38 QList<QString>* languages =
static_cast<QList<QString>*
>(user_data);
39 languages->append(lang_tag);
42 static enchant::Broker* get_enchant_broker() {
43 #ifdef QTSPELL_ENCHANT2
44 static enchant::Broker broker;
47 return enchant::Broker::instance();
52 class TranslationsInit {
55 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
56 QString translationsPath = QLibraryInfo::path(QLibraryInfo::TranslationsPath);
58 QString translationsPath = QLibraryInfo::location(QLibraryInfo::TranslationsPath);
61 QDir packageDir = QDir(QString(
"%1/../").arg(QApplication::applicationDirPath()));
62 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
63 translationsPath = packageDir.absolutePath() + translationsPath.mid(QLibraryInfo::path(QLibraryInfo::PrefixPath).length());
65 translationsPath = packageDir.absolutePath() + translationsPath.mid(QLibraryInfo::location(QLibraryInfo::PrefixPath).length());
68 bool success = spellTranslator.load(
"QtSpell_" + QLocale::system().name(), translationsPath);
70 QApplication::instance()->installTranslator(&spellTranslator);
73 QTranslator spellTranslator;
79 CheckerPrivate::CheckerPrivate()
83 CheckerPrivate::~CheckerPrivate()
88 void CheckerPrivate::init()
90 static TranslationsInit tsInit;
93 setLanguageInternal(
"");
98 return get_enchant_broker()->dict_exists(lang.toStdString());
101 Checker::Checker(QObject* parent)
103 , d_ptr(new CheckerPrivate())
125 bool success = d->setLanguageInternal(lang);
138 bool CheckerPrivate::setLanguageInternal(
const QString &newLang)
146 lang = QLocale::system().name();
147 if(lang.toLower() ==
"c" || lang.isEmpty()){
148 qWarning() <<
"Cannot use system locale " << lang;
156 speller = get_enchant_broker()->request_dict(lang.toStdString());
157 }
catch(enchant::Exception& e) {
158 qWarning() <<
"Failed to load dictionary: " << e.what();
169 d->decodeCodes = decode;
175 return d->decodeCodes;
181 d->spellingCheckbox = show;
187 return d->spellingCheckbox;
193 return d->spellingEnabled;
200 d->speller->add(word.toUtf8().data());
207 if(!d->speller || !d->spellingEnabled){
211 if(word.length() < 2){
215 return d->speller->check(word.toUtf8().data());
216 }
catch(
const enchant::Exception&){
224 d->speller->add_to_session(word.toUtf8().data());
232 std::vector<std::string> suggestions;
233 d->speller->suggest(word.toUtf8().data(), suggestions);
234 for(std::size_t i = 0, n = suggestions.size(); i < n; ++i){
235 list.append(QString::fromUtf8(suggestions[i].c_str()));
243 enchant::Broker* broker = get_enchant_broker();
244 QList<QString> languages;
245 broker->list_dicts(dict_describe_cb, &languages);
246 std::sort(languages.begin(), languages.end());
252 QString language, country, extra;
254 if(!country.isEmpty()){
255 QString decoded = QString(
"%1 (%2)").arg(language, country);
256 if(!extra.isEmpty()) {
257 decoded += QString(
" [%1]").arg(extra);
268 d->spellingEnabled = enabled;
272 void Checker::showContextMenu(QMenu* menu,
const QPoint& pos,
int wordPos)
275 QAction* insertPos = menu->actions().first();
276 if(d->speller && d->spellingEnabled){
277 QString word =
getWord(wordPos);
281 if(!suggestions.isEmpty()){
282 for(
int i = 0, n = qMin(10, suggestions.length()); i < n; ++i){
283 QAction* action =
new QAction(suggestions[i], menu);
284 action->setProperty(
"wordPos", wordPos);
285 action->setProperty(
"suggestion", suggestions[i]);
286 connect(action, &QAction::triggered,
this, &Checker::slotReplaceWord);
287 menu->insertAction(insertPos, action);
289 if(suggestions.length() > 10) {
290 QMenu* moreMenu =
new QMenu();
291 for(
int i = 10, n = suggestions.length(); i < n; ++i){
292 QAction* action =
new QAction(suggestions[i], moreMenu);
293 action->setProperty(
"wordPos", wordPos);
294 action->setProperty(
"suggestion", suggestions[i]);
295 connect(action, &QAction::triggered,
this, &Checker::slotReplaceWord);
296 moreMenu->addAction(action);
298 QAction* action =
new QAction(tr(
"More..."), menu);
299 menu->insertAction(insertPos, action);
300 action->setMenu(moreMenu);
302 menu->insertSeparator(insertPos);
305 QAction* addAction =
new QAction(tr(
"Add \"%1\" to dictionary").arg(word), menu);
306 addAction->setData(wordPos);
307 connect(addAction, &QAction::triggered,
this, &Checker::slotAddWord);
308 menu->insertAction(insertPos, addAction);
310 QAction* ignoreAction =
new QAction(tr(
"Ignore \"%1\"").arg(word), menu);
311 ignoreAction->setData(wordPos);
312 connect(ignoreAction, &QAction::triggered,
this, &Checker::slotIgnoreWord);
313 menu->insertAction(insertPos, ignoreAction);
314 menu->insertSeparator(insertPos);
317 if(d->spellingCheckbox){
318 QAction* action =
new QAction(tr(
"Check spelling"), menu);
319 action->setCheckable(
true);
320 action->setChecked(d->spellingEnabled);
322 menu->insertAction(insertPos, action);
324 if(d->speller && d->spellingEnabled){
325 QMenu* languagesMenu =
new QMenu();
326 QActionGroup* actionGroup =
new QActionGroup(languagesMenu);
329 QAction* action =
new QAction(text, languagesMenu);
330 action->setData(lang);
331 action->setCheckable(
true);
333 connect(action, &QAction::triggered,
this, &Checker::slotSetLanguage);
334 languagesMenu->addAction(action);
335 actionGroup->addAction(action);
337 QAction* langsAction =
new QAction(tr(
"Languages"), menu);
338 langsAction->setMenu(languagesMenu);
339 menu->insertAction(insertPos, langsAction);
340 menu->insertSeparator(insertPos);
347 void Checker::slotAddWord()
349 int wordPos = qobject_cast<QAction*>(QObject::sender())->data().toInt();
355 void Checker::slotIgnoreWord()
357 int wordPos = qobject_cast<QAction*>(QObject::sender())->data().toInt();
363 void Checker::slotReplaceWord()
365 QAction* action = qobject_cast<QAction*>(QObject::sender());
366 int wordPos = action->property(
"wordPos").toInt();
368 getWord(wordPos, &start, &end);
369 insertWord(start, end, action->property(
"suggestion").toString());
372 void Checker::slotSetLanguage(
bool checked)
375 QAction* action = qobject_cast<QAction*>(QObject::sender());
376 QString lang = action->data().toString();
378 action->setChecked(
false);
virtual ~Checker()
QtSpell::Checker object destructor.
bool getSpellingEnabled() const
Return whether spellchecking is performed.
static Codetable * instance()
Get codetable instance.
bool checkLanguageInstalled(const QString &lang)
Check whether the dictionary for a language is installed.
virtual QString getWord(int pos, int *start=0, int *end=0) const =0
Get the word at the specified cursor position.
void addWordToDictionary(const QString &word)
Add the specified word to the user dictionary.
void ignoreWord(const QString &word) const
Ignore a word for the current session.
bool getDecodeLanguageCodes() const
Return whether langauge codes are decoded in the UI.
void setDecodeLanguageCodes(bool decode)
Set whether to decode language codes in the UI.
virtual void insertWord(int start, int end, const QString &word)=0
Replaces the specified range with the specified word.
void setShowCheckSpellingCheckbox(bool show)
Set whether to display an "Check spelling" checkbox in the UI.
bool getShowCheckSpellingCheckbox() const
Return whether a "Check spelling" checkbox is displayed in the UI.
QString getLanguage() const
Retreive the current spelling language.
virtual void checkSpelling(int start=0, int end=-1)=0
Check the spelling.
void languageChanged(const QString &newLang)
This signal is emitted when the user selects a new language from the spellchecker UI...
Checker(QObject *parent=0)
QtSpell::Checker object constructor.
void setSpellingEnabled(bool enabled)
Set whether spell checking should be performed.
static QString decodeLanguageCode(const QString &lang)
Translates a language code to a human readable format (i.e. "en_US" -> "English (United States)")...
bool setLanguage(const QString &lang)
Set the spell checking language.
bool checkWord(const QString &word) const
Check the specified word.
static QList< QString > getLanguageList()
Requests the list of languages available for spell checking.
QList< QString > getSpellingSuggestions(const QString &word) const
Retreive a list of spelling suggestions for the misspelled word.
An abstract class providing spell checking support.
void lookup(const QString &language_code, QString &language_name, QString &country_name, QString &extra) const
Looks up the language and country name for the specified language code. If no matching entries are fo...
virtual bool isAttached() const =0
Returns whether a widget is attached to the checker.