6#include "QskHunspellTextPredictor.h"
14#include <hunspell/hunspell.h>
16#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
18#include <qtextcodec.h>
25 StringConverter(
const QByteArray& encoding )
26 : m_codec( QTextCodec::codecForName( encoding ) )
30 inline QString fromHunspell(
const char* text )
const
33 return m_codec->toUnicode( text );
35 return QString::fromUtf8( text );
38 inline QByteArray toHunspell(
const QString& text )
const
41 return m_codec->fromUnicode( text );
52#include <qstringconverter.h>
59 StringConverter(
const QByteArray& encoding )
60 : m_decoder( encoding )
61 , m_encoder( encoding )
65 inline QString fromHunspell(
const char* text )
const
67 if ( m_decoder.isValid() )
68 return m_decoder.decode( text );
70 return QString::fromUtf8( text );
73 inline QByteArray toHunspell(
const QString& text )
const
75 if ( m_encoder.isValid() )
76 return m_encoder.encode( text );
82 mutable QStringDecoder m_decoder;
83 mutable QStringEncoder m_encoder;
89class QskHunspellTextPredictor::PrivateData
92 Hunhandle* hunspellHandle =
nullptr;
93 QByteArray hunspellEncoding;
94 QStringList candidates;
98QskHunspellTextPredictor::QskHunspellTextPredictor(
99 const QLocale& locale, QObject*
object )
100 : Inherited( object )
101 , m_data( new PrivateData() )
103 m_data->locale = locale;
106 QMetaObject::invokeMethod(
this,
107 &QskHunspellTextPredictor::loadDictionaries, Qt::QueuedConnection );
110QskHunspellTextPredictor::~QskHunspellTextPredictor()
112 Hunspell_destroy( m_data->hunspellHandle );
115void QskHunspellTextPredictor::reset()
117 if ( !m_data->candidates.isEmpty() )
119 m_data->candidates.clear();
120 Q_EMIT predictionChanged( QString(), {} );
124QPair< QString, QString > QskHunspellTextPredictor::affAndDicFile(
125 const QString& path,
const QLocale& locale )
127 QString prefix = QStringLiteral(
"%1/%2" ).arg( path, locale.name() );
128 QString affFile = prefix + QStringLiteral(
".aff" );
129 QString dicFile = prefix + QStringLiteral(
".dic" );
131 if( QFile::exists( affFile ) && QFile::exists( dicFile ) )
133 return qMakePair( affFile, dicFile );
141void QskHunspellTextPredictor::loadDictionaries()
143 const auto userPaths = QString::fromUtf8( qgetenv(
"QSK_HUNSPELL_PATH" ) );
145 auto paths = userPaths.split( QDir::listSeparator(), Qt::SkipEmptyParts );
147#if !defined( Q_OS_WIN32 )
148 paths += QStringLiteral(
"/usr/share/hunspell" );
149 paths += QStringLiteral(
"/usr/share/myspell/dicts" );
152 for(
const auto& path : paths )
154 auto files = affAndDicFile( path, m_data->locale );
156 if( !files.first.isEmpty() && !files.second.isEmpty() )
158 m_data->hunspellHandle = Hunspell_create( files.first.toUtf8(), files.second.toUtf8() );
159 m_data->hunspellEncoding = Hunspell_get_dic_encoding( m_data->hunspellHandle );
164 if( !m_data->hunspellHandle )
166 qWarning() <<
"could not find Hunspell files for locale" << m_data->locale
167 <<
"in the following directories:" << paths
168 <<
". Consider setting QSK_HUNSPELL_PATH to the directory "
169 <<
"containing Hunspell .aff and .dic files.";
173void QskHunspellTextPredictor::request(
const QString& text )
175 if( !m_data->hunspellHandle )
177 Q_EMIT predictionChanged( text, {} );
181 StringConverter converter( m_data->hunspellEncoding );
185 const int count = Hunspell_suggest( m_data->hunspellHandle,
186 &suggestions, converter.toHunspell( text ).constData() );
188 QStringList candidates;
189 candidates.reserve( count );
191 for (
int i = 0; i < count; i++ )
193 const auto suggestion = converter.fromHunspell( suggestions[ i ] );
195 if ( suggestion.startsWith( text ) )
196 candidates.prepend( suggestion );
198 candidates.append( suggestion );
201 Hunspell_free_list( m_data->hunspellHandle, &suggestions, count );
203 m_data->candidates = candidates;
204 Q_EMIT predictionChanged( text, m_data->candidates );
207#include "moc_QskHunspellTextPredictor.cpp"