1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the Qt Virtual Keyboard module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:GPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU
19 ** General Public License version 3 or (at your option) any later version
20 ** approved by the KDE Free Qt Foundation. The licenses are as published by
21 ** the Free Software Foundation and appearing in the file LICENSE.GPL3
22 ** included in the packaging of this file. Please review the following
23 ** information to ensure the GNU General Public License requirements will
24 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
25 **
26 ** $QT_END_LICENSE$
27 **
28 ****************************************************************************/
29
30 #include <pinyindecoderservice.h>
31 #include <pinyinime.h>
32 #include <dictdef.h>
33 #include <QStandardPaths>
34 #include <QFileInfo>
35 #include <QDir>
36 #include <QtCore/QLibraryInfo>
37 #include <QtCore/QCoreApplication>
38 #include <QDebug>
39
40 namespace QtVirtualKeyboard {
41
42 using namespace ime_pinyin;
43
44 QScopedPointer<PinyinDecoderService> PinyinDecoderService::_instance;
45
46 /*!
47 \class QtVirtualKeyboard::PinyinDecoderService
48 \internal
49 */
50
PinyinDecoderService(QObject * parent)51 PinyinDecoderService::PinyinDecoderService(QObject *parent) :
52 QObject(parent),
53 initDone(false)
54 {
55 }
56
~PinyinDecoderService()57 PinyinDecoderService::~PinyinDecoderService()
58 {
59 if (initDone) {
60 im_close_decoder();
61 initDone = false;
62 }
63 }
64
getInstance()65 PinyinDecoderService *PinyinDecoderService::getInstance()
66 {
67 if (!_instance)
68 _instance.reset(new PinyinDecoderService());
69 if (!_instance->init())
70 return 0;
71 return _instance.data();
72 }
73
init()74 bool PinyinDecoderService::init()
75 {
76 if (initDone)
77 return true;
78
79 //QString strDir = QCoreApplication::applicationDirPath();
80 // QString sysDict = "/usr/local/pinyin/dict_pinyin.dat";
81 // QString usrDictPath = "/usr/local/pinyin/usr_dict.dat";
82 QString sysDict = qApp->applicationDirPath() +"/pinyin/dict_pinyin.dat";
83 QString usrDictPath = qApp->applicationDirPath() +"/pinyin/usr_dict.dat";
84
85 if (QFileInfo::exists(sysDict) == false)
86 {
87 qDebug() << qApp->applicationDirPath() +"/pinyin/dict_pinyin.dat not found" << sysDict;
88 return false;
89 }
90
91 QFileInfo usrDictInfo(usrDictPath);
92 if (!usrDictInfo.exists()) {
93 qDebug() << "PinyinDecoderService::init(): creating directory for user dictionary" << usrDictInfo.absolutePath();
94 QDir().mkpath(usrDictInfo.absolutePath());
95 }
96
97 initDone = im_open_decoder(sysDict.toUtf8().constData(), usrDictInfo.absoluteFilePath().toUtf8().constData());
98 if (!initDone)
99 qDebug() << "Could not initialize pinyin engine. sys_dict:" << sysDict << "usr_dict:" << usrDictInfo.absoluteFilePath();
100
101 return initDone;
102 }
103
setUserDictionary(bool enabled)104 void PinyinDecoderService::setUserDictionary(bool enabled)
105 {
106 if (enabled == im_is_user_dictionary_enabled())
107 return;
108 if (enabled) {
109 //QString usrDictPath = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation);
110 QFileInfo usrDictInfo(qApp->applicationDirPath() +"/pinyin/usr_dict.dat");
111 im_init_user_dictionary(usrDictInfo.absoluteFilePath().toUtf8().constData());
112 } else {
113 im_init_user_dictionary(NULL);
114 }
115 }
116
isUserDictionaryEnabled() const117 bool PinyinDecoderService::isUserDictionaryEnabled() const
118 {
119 return im_is_user_dictionary_enabled();
120 }
121
setLimits(int maxSpsLen,int maxHzsLen)122 void PinyinDecoderService::setLimits(int maxSpsLen, int maxHzsLen)
123 {
124 if (maxSpsLen <= 0)
125 maxSpsLen = kMaxSearchSteps - 1;
126 if (maxHzsLen <= 0)
127 maxHzsLen = kMaxSearchSteps;
128 im_set_max_lens(size_t(maxSpsLen), size_t(maxHzsLen));
129 }
130
search(const QString & spelling)131 int PinyinDecoderService::search(const QString &spelling)
132 {
133 QByteArray spellingBuf = spelling.toLatin1();
134 return int(im_search(spellingBuf.constData(), spellingBuf.length()));
135 }
136
deleteSearch(int pos,bool isPosInSpellingId,bool clearFixedInThisStep)137 int PinyinDecoderService::deleteSearch(int pos, bool isPosInSpellingId, bool clearFixedInThisStep)
138 {
139 if (pos <= 0)
140 pos = 0;
141 return int(im_delsearch(size_t(pos), isPosInSpellingId, clearFixedInThisStep));
142 }
143
resetSearch()144 void PinyinDecoderService::resetSearch()
145 {
146 im_reset_search();
147 }
148
pinyinString(bool decoded)149 QString PinyinDecoderService::pinyinString(bool decoded)
150 {
151 size_t py_len;
152 const char *py = im_get_sps_str(&py_len);
153 if (!decoded)
154 py_len = strlen(py);
155
156 return QString(QLatin1String(py, (int)py_len));
157 }
158
pinyinStringLength(bool decoded)159 int PinyinDecoderService::pinyinStringLength(bool decoded)
160 {
161 size_t py_len;
162 const char *py = im_get_sps_str(&py_len);
163 if (!decoded)
164 py_len = strlen(py);
165 return (int)py_len;
166 }
167
spellingStartPositions()168 QVector<int> PinyinDecoderService::spellingStartPositions()
169 {
170 const unsigned short *spl_start;
171 int len;
172 // There will be len + 1 elements in the buffer when len > 0.
173 len = (int)im_get_spl_start_pos(spl_start);
174
175 QVector<int> arr;
176 arr.resize(len + 2);
177 arr[0] = len; // element 0 is used to store the length of buffer.
178 for (int i = 0; i <= len; i++)
179 arr[i + 1] = spl_start[i];
180 return arr;
181 }
182
candidateAt(int index)183 QString PinyinDecoderService::candidateAt(int index)
184 {
185 Q_ASSERT(index >= 0);
186 QVector<QChar> candidateBuf;
187 candidateBuf.resize(kMaxSearchSteps + 1);
188 if (!im_get_candidate(size_t(index), (char16 *)candidateBuf.data(), candidateBuf.length() - 1))
189 return QString();
190 candidateBuf.last() = 0;
191 return QString(candidateBuf.data());
192 }
193
fetchCandidates(int index,int count,int sentFixedLen)194 QList<QString> PinyinDecoderService::fetchCandidates(int index, int count, int sentFixedLen)
195 {
196 QList<QString> candidatesList;
197 for (int i = index; i < index + count; i++) {
198 QString retStr = candidateAt(i);
199 if (0 == i)
200 retStr.remove(0, sentFixedLen);
201 candidatesList.append(retStr);
202 }
203 return candidatesList;
204 }
205
chooceCandidate(int index)206 int PinyinDecoderService::chooceCandidate(int index)
207 {
208 return int(im_choose(index));
209 }
210
cancelLastChoice()211 int PinyinDecoderService::cancelLastChoice()
212 {
213 return int(im_cancel_last_choice());
214 }
215
fixedLength()216 int PinyinDecoderService::fixedLength()
217 {
218 return (int)im_get_fixed_len();
219 }
220
flushCache()221 void PinyinDecoderService::flushCache()
222 {
223 im_flush_cache();
224 }
225
predictionList(const QString & history)226 QList<QString> PinyinDecoderService::predictionList(const QString &history)
227 {
228 QList<QString> predictList;
229 char16 (*predictItems)[kMaxPredictSize + 1] = 0;
230 int predictNum = int(im_get_predicts(history.utf16(), predictItems));
231 predictList.reserve(predictNum);
232 for (int i = 0; i < predictNum; i++)
233 predictList.append(QString((QChar *)predictItems[i]));
234 return predictList;
235 }
236
237 } // namespace QtVirtualKeyboard
238