File indexing completed on 2024-04-28 11:48:59

0001 /*  This file is part of the KDE libraries
0002 
0003     SPDX-FileCopyrightText: 2009 Jakub Stachowski <qbast@go2.pl>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 
0008 #include <QString>
0009 
0010 #include "guesslanguage.h"
0011 #include "languagefilter_p.h"
0012 #include "loader_p.h"
0013 #include "settingsimpl_p.h"
0014 #include "speller.h"
0015 
0016 namespace Sonnet
0017 {
0018 #define MIN_RELIABILITY 0.1
0019 #define MAX_ITEMS 5
0020 
0021 class LanguageFilterPrivate
0022 {
0023 public:
0024     LanguageFilterPrivate(AbstractTokenizer *s)
0025         : source(s)
0026     {
0027         gl.setLimits(MAX_ITEMS, MIN_RELIABILITY);
0028     }
0029 
0030     ~LanguageFilterPrivate()
0031     {
0032         delete source;
0033     }
0034 
0035     QString mainLanguage() const;
0036 
0037     AbstractTokenizer *source = nullptr;
0038     Token lastToken;
0039 
0040     mutable QString lastLanguage;
0041     mutable QString cachedMainLanguage;
0042     QString prevLanguage;
0043 
0044     GuessLanguage gl;
0045     Speller sp;
0046 };
0047 
0048 QString LanguageFilterPrivate::mainLanguage() const
0049 {
0050     if (cachedMainLanguage.isNull()) {
0051         cachedMainLanguage = gl.identify(source->buffer(), QStringList(Loader::openLoader()->settings()->defaultLanguage()));
0052     }
0053     return cachedMainLanguage;
0054 }
0055 
0056 /* -----------------------------------------------------------------*/
0057 
0058 LanguageFilter::LanguageFilter(AbstractTokenizer *source)
0059     : d(new LanguageFilterPrivate(source))
0060 {
0061     d->prevLanguage = Loader::openLoader()->settings()->defaultLanguage();
0062 }
0063 
0064 LanguageFilter::LanguageFilter(const LanguageFilter &other)
0065     : d(new LanguageFilterPrivate(other.d->source))
0066 {
0067     d->lastToken = other.d->lastToken;
0068     d->lastLanguage = other.d->lastLanguage;
0069     d->cachedMainLanguage = other.d->cachedMainLanguage;
0070     d->prevLanguage = other.d->prevLanguage;
0071 }
0072 
0073 LanguageFilter::~LanguageFilter()
0074 {
0075     delete d;
0076 }
0077 
0078 bool LanguageFilter::hasNext() const
0079 {
0080     return d->source->hasNext();
0081 }
0082 
0083 void LanguageFilter::setBuffer(const QString &buffer)
0084 {
0085     d->cachedMainLanguage = QString();
0086     d->source->setBuffer(buffer);
0087 }
0088 
0089 Token LanguageFilter::next()
0090 {
0091     d->lastToken = d->source->next();
0092     d->prevLanguage = d->lastLanguage;
0093     d->lastLanguage = QString();
0094     return d->lastToken;
0095 }
0096 
0097 QString LanguageFilter::language() const
0098 {
0099     if (d->lastLanguage.isNull()) {
0100         d->lastLanguage = d->gl.identify(d->lastToken.toString(), QStringList() << d->prevLanguage << Loader::openLoader()->settings()->defaultLanguage());
0101     }
0102     const QStringList available = d->sp.availableLanguages();
0103 
0104     // FIXME: do something a little more smart here
0105     if (!available.contains(d->lastLanguage)) {
0106         for (const QString &lang : available) {
0107             if (lang.startsWith(d->lastLanguage)) {
0108                 d->lastLanguage = lang;
0109                 break;
0110             }
0111         }
0112     }
0113 
0114     return d->lastLanguage;
0115 }
0116 
0117 bool LanguageFilter::isSpellcheckable() const
0118 {
0119     const QString &lastlang = language();
0120     if (lastlang.isEmpty()) {
0121         return false;
0122     }
0123 
0124     if (d->sp.availableLanguages().contains(lastlang)) {
0125         return true;
0126     }
0127 
0128     return false;
0129 }
0130 
0131 QString LanguageFilter::buffer() const
0132 {
0133     return d->source->buffer();
0134 }
0135 
0136 void LanguageFilter::replace(int position, int len, const QString &newWord)
0137 {
0138     d->source->replace(position, len, newWord);
0139     // FIXME: fix lastToken
0140     // uncache language for current token - it may have changed
0141     d->lastLanguage = QString();
0142 }
0143 }