File indexing completed on 2024-04-28 07:50:09

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() = default;
0074 
0075 bool LanguageFilter::hasNext() const
0076 {
0077     return d->source->hasNext();
0078 }
0079 
0080 void LanguageFilter::setBuffer(const QString &buffer)
0081 {
0082     d->cachedMainLanguage = QString();
0083     d->source->setBuffer(buffer);
0084 }
0085 
0086 Token LanguageFilter::next()
0087 {
0088     d->lastToken = d->source->next();
0089     d->prevLanguage = d->lastLanguage;
0090     d->lastLanguage = QString();
0091     return d->lastToken;
0092 }
0093 
0094 QString LanguageFilter::language() const
0095 {
0096     if (d->lastLanguage.isNull()) {
0097         d->lastLanguage = d->gl.identify(d->lastToken.toString(), QStringList() << d->prevLanguage << Loader::openLoader()->settings()->defaultLanguage());
0098     }
0099     const QStringList available = d->sp.availableLanguages();
0100 
0101     // FIXME: do something a little more smart here
0102     if (!available.contains(d->lastLanguage)) {
0103         for (const QString &lang : available) {
0104             if (lang.startsWith(d->lastLanguage)) {
0105                 d->lastLanguage = lang;
0106                 break;
0107             }
0108         }
0109     }
0110 
0111     return d->lastLanguage;
0112 }
0113 
0114 bool LanguageFilter::isSpellcheckable() const
0115 {
0116     const QString &lastlang = language();
0117     if (lastlang.isEmpty()) {
0118         return false;
0119     }
0120 
0121     if (d->sp.availableLanguages().contains(lastlang)) {
0122         return true;
0123     }
0124 
0125     return false;
0126 }
0127 
0128 QString LanguageFilter::buffer() const
0129 {
0130     return d->source->buffer();
0131 }
0132 
0133 void LanguageFilter::replace(int position, int len, const QString &newWord)
0134 {
0135     d->source->replace(position, len, newWord);
0136     // FIXME: fix lastToken
0137     // uncache language for current token - it may have changed
0138     d->lastLanguage = QString();
0139 }
0140 }