Added possibility of stopping cache process
[mdictionary] / trunk / src / plugins / xdxf / src / xdxfplugin.cpp
1 /*******************************************************************************
2
3     This file is part of mDictionary.
4
5     mDictionary is free software: you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation, either version 3 of the License, or
8     (at your option) any later version.
9
10     mDictionary is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with mDictionary.  If not, see <http://www.gnu.org/licenses/>.
17
18     Copyright 2010 Comarch S.A.
19
20 *******************************************************************************/
21
22 #include "xdxfplugin.h"
23 #include <QDebug>
24 #include <QFile>
25 #include <QXmlStreamReader>
26 #include <QtPlugin>
27 #include "TranslationXdxf.h"
28 #include "../../../includes/settings.h"
29
30 XdxfPlugin::XdxfPlugin(QObject *parent) : CommonDictInterface(parent),
31                     _langFrom(tr("")), _langTo(tr("")),_name(tr("")),
32                     _type(tr("xdxf")), _infoNote(tr("")) {
33     _wordsCount = -1;
34     _settings = new Settings();
35     _dictDialog = new XdxfDictDialog(this, this);
36     _settings->setValue("type","xdxf");
37
38     stopped = false;
39
40     _icon = QIcon(":/icons/xdxf.png");
41 }
42
43 QString XdxfPlugin::langFrom() const {   
44     return _langFrom;
45 }
46
47 QString XdxfPlugin::langTo() const {
48     return  _langTo;
49 }
50
51 QString XdxfPlugin::name() const {
52     return  _name;
53 }
54
55 QString XdxfPlugin::type() const {
56 //    return _settings->value("type");
57     return _type;
58 }
59
60 QString XdxfPlugin::infoNote() const {
61     return  _infoNote;
62 }
63
64 QList<Translation*> XdxfPlugin::searchWordList(QString word, int limit) {
65     if(_settings->value("cached") == "true")
66         return searchWordListCache(word,limit);
67     return searchWordListFile(word, limit);
68 }
69
70 QList<Translation*> XdxfPlugin::searchWordListCache(QString word, int limit) {
71
72     QSet<Translation*> translations;
73     QString cacheFilePath = _settings->value("cache_path");
74         db.setDatabaseName(cacheFilePath);
75         if(!db.open()) {
76             qDebug() << "Database error" << db.lastError().text() << endl;
77             return searchWordListFile(word, limit);
78         }
79
80         stopped = false;
81         if(word.indexOf("*")==-1)
82             word+="%";
83         word = word.replace("*", "%");
84         word = removeAccents(word);
85
86         QSqlQuery cur(db);
87         cur.prepare("select word from dict where word like ? limit ?");
88         cur.addBindValue(word);
89         cur.addBindValue(limit);
90         cur.exec();
91         while(cur.next())
92             translations.insert(new TranslationXdxf(cur.value(0).toString(),
93                                                     _infoNote, this));
94         return translations.toList();
95 }
96
97
98
99 QList<Translation*> XdxfPlugin::searchWordListFile(QString word, int limit) {
100     QSet<Translation*> translations;
101     QFile dictionaryFile(path);
102
103     word = removeAccents(word);
104
105     stopped = false;
106     if(word.indexOf("*")==-1)
107         word+="*";
108     QRegExp regWord(word);
109     regWord.setCaseSensitivity(Qt::CaseInsensitive);
110     regWord.setPatternSyntax(QRegExp::Wildcard);
111     if(!dictionaryFile.open(QFile::ReadOnly | QFile::Text)) {
112         qDebug()<<"Error: could not open file";
113         return translations.toList();
114     }
115
116     QXmlStreamReader dictionaryReader(&dictionaryFile);
117     /*search words list*/
118     QString a;
119     int i=0;
120     while(!dictionaryReader.atEnd() && !stopped){
121         dictionaryReader.readNextStartElement();
122         if(dictionaryReader.name()=="ar"){
123             while(dictionaryReader.name()!="k" && !dictionaryReader.atEnd())
124                 dictionaryReader.readNextStartElement();
125             if(!dictionaryReader.atEnd())
126                 a = dictionaryReader.readElementText();
127             if(regWord.exactMatch(removeAccents(a)) && (i<limit || limit==0)) {
128                 bool ok=true;
129                 Translation *tran;
130                 foreach(tran,translations)
131                 {
132                     if(tran->key()==a)
133                         ok=false;  /*if key word is in the dictionary more that one */
134                 }
135                 if(ok)  /*add key word to list*/
136                     translations<<(new TranslationXdxf(a,_infoNote,this));
137                 i++;
138                 if(i>=limit && limit!=0)
139                     break;
140             }
141         }
142         this->thread()->yieldCurrentThread();
143     }
144     stopped=false;
145     dictionaryFile.close();
146     return translations.toList();
147 }
148
149 QString XdxfPlugin::search(QString key) {
150     if(_settings->value("cached") == "true")
151         return searchCache(key);
152     return searchFile(key);
153 }
154
155
156
157 QString XdxfPlugin::searchCache(QString key) {
158     QString result;
159     QString cacheFilePath = _settings->value("cache_path");
160     db.setDatabaseName(cacheFilePath);
161
162     if(!db.open()) {
163         qDebug() << "Database error" << db.lastError().text() << endl;
164         return searchFile(key);
165     }
166
167     QSqlQuery cur(db);
168     cur.prepare("select translation from dict where word like ? limit 1");
169     cur.addBindValue(key);
170     cur.exec();
171     if(cur.next())
172         result = cur.value(0).toString();
173     return result;
174
175 }
176
177
178
179
180 QString XdxfPlugin::searchFile(QString key) {
181     QFile dictionaryFile(path);
182     QString resultString("");
183     if(!dictionaryFile.open(QFile::ReadOnly | QFile::Text)) {
184         qDebug()<<"Error: could not open file";
185         return "";
186     }
187     QXmlStreamReader dictionaryReader(&dictionaryFile);
188
189
190     QString a;
191
192     bool match =false;
193     stopped = false;
194     while (!dictionaryReader.atEnd()&& !stopped) {
195         dictionaryReader.readNext();
196         if(dictionaryReader.tokenType() == QXmlStreamReader::StartElement) {
197             if(dictionaryReader.name()=="k") {
198                 a = dictionaryReader.readElementText();
199                 if(a==key)
200                     match = true;
201             }
202         }
203         else if(dictionaryReader.tokenType() == QXmlStreamReader::Characters) {
204             if(match) {
205                 QString temp(dictionaryReader.text().toString());
206                 temp.replace("\n","");
207                 if(temp == ""){
208                     while(dictionaryReader.name()!="ar"&&
209                                 !dictionaryReader.atEnd()){
210                         dictionaryReader.readNext();
211                         temp+=dictionaryReader.text().toString();
212                     }
213                 }
214                 resultString+=temp.replace("\n","")+"\n";
215                 match=false;
216             }
217         }
218         this->thread()->yieldCurrentThread();
219     }
220     stopped=false;
221     dictionaryFile.close();
222     return resultString;
223 }
224
225 void XdxfPlugin::stop() {
226     stopped=true;
227 }
228
229 DictDialog* XdxfPlugin::dictDialog() {
230      return _dictDialog;
231 }
232
233 void XdxfPlugin::setPath(QString path){
234     this->path=path;
235     _settings->setValue("path",path);
236     getDictionaryInfo();
237 }
238
239
240 CommonDictInterface* XdxfPlugin::getNew(const Settings *settings) const {
241     XdxfPlugin *plugin = new XdxfPlugin();
242     if(settings){
243         plugin->setPath(settings->value("path"));
244         QStringList list = settings->keys();
245         foreach(QString key, list)
246             plugin->settings()->setValue(key, settings->value(key));
247
248         plugin->db_name = plugin->_settings->value("type")
249                + plugin->_settings->value("path");
250         plugin->db = QSqlDatabase::addDatabase("QSQLITE", plugin->db_name);
251     }
252     return  plugin;
253 }
254
255 bool XdxfPlugin::isAvailable() const {
256     return true;
257 }
258
259 void XdxfPlugin::setHash(uint _hash)
260 {
261     this->_hash=_hash;
262 }
263
264 uint XdxfPlugin::hash() const
265 {
266    return _hash;
267 }
268
269 Settings* XdxfPlugin::settings() {
270     return _settings;
271 }
272
273 bool XdxfPlugin::isCached()
274 {
275     return false;
276 }
277
278 void XdxfPlugin::setSettings(Settings *settings) {
279     _settings = settings;
280     setPath(_settings->value("path"));
281     emit settingsChanged();
282 }
283
284
285 void XdxfPlugin::getDictionaryInfo() {
286     QFile dictionaryFile(path);
287     if(!dictionaryFile.open(QFile::ReadOnly | QFile::Text)) {
288         qDebug()<<"Error: could not open file";
289         return;
290     }
291
292     QXmlStreamReader dictionaryReader(&dictionaryFile);
293     dictionaryReader.readNextStartElement();
294     if(dictionaryReader.name()=="xdxf") {
295       if(dictionaryReader.attributes().hasAttribute("lang_from"))
296         _langFrom = dictionaryReader.attributes().value("lang_from").toString();
297       if(dictionaryReader.attributes().hasAttribute("lang_to"))
298         _langTo = dictionaryReader.attributes().value("lang_to").toString();
299     }
300     dictionaryReader.readNextStartElement();
301     if(dictionaryReader.name()=="full_name")
302         _name=dictionaryReader.readElementText();
303     dictionaryReader.readNextStartElement();
304     if(dictionaryReader.name()=="description")
305         _infoNote=dictionaryReader.readElementText();
306
307     dictionaryFile.close();
308 }
309
310 QString XdxfPlugin::removeAccents(QString string) {
311
312     string = string.replace(QString::fromUtf8("ł"), "l", Qt::CaseInsensitive);
313     QString normalized = string.normalized(QString::NormalizationForm_D);
314     normalized = normalized;
315     for(int i=0; i<normalized.size(); i++) {
316         if( !normalized[i].isLetterOrNumber() &&
317             !normalized[i].isSpace() &&
318             !normalized[i].isDigit() &&
319             normalized[i] != '*' &&
320             normalized[i] != '%') {
321             normalized.remove(i,1);
322         }
323     }
324     return normalized;
325 }
326
327 QIcon* XdxfPlugin::icon() {
328     return &_icon;
329 }
330
331 int XdxfPlugin::countWords() {
332     if(_wordsCount > 0)
333         return _wordsCount;
334
335     QFile dictionaryFile(path);
336     if(!dictionaryFile.open(QFile::ReadOnly | QFile::Text)) {
337         qDebug()<<"Error: could not open file";
338         return -1;
339     }
340
341     dictionaryFile.seek(0);
342
343     long wordsCount = 0;
344
345     QString line;
346     while(!dictionaryFile.atEnd()) {
347         line = dictionaryFile.readLine();
348         if(line.contains("<k>")) {
349             wordsCount++;
350         }
351     }
352     _wordsCount = wordsCount;
353     dictionaryFile.close();
354     return wordsCount;
355 }
356
357
358
359 bool XdxfPlugin::makeCache(QString dir) {
360     stopped = false;
361     QFileInfo dictFileN(_settings->value("path"));
362     QString cachePathN;
363     cachePathN = QDir::homePath() + "/.mdictionary/"
364                  + dictFileN.completeBaseName() + ".cache";
365
366     QFile dictionaryFile(dictFileN.filePath());
367
368
369     if (!dictionaryFile.open(QFile::ReadOnly | QFile::Text)) {
370         return 0;
371     }
372
373     QXmlStreamReader reader(&dictionaryFile);
374
375
376     db.setDatabaseName(cachePathN);
377     if(!db.open()) {
378         qDebug() << "Database error" << endl;
379         return false;
380     }
381     QSqlQuery cur(db);
382     cur.exec("PRAGMA synchronous = 0");
383     cur.exec("drop table dict");
384     cur.exec("create table dict(word text ,translation text)");
385     int counter = 0;
386     cur.exec("BEGIN;");
387
388     QString a;
389     bool match = false;
390     QTime timer;
391     timer.start();
392     countWords();
393
394
395     counter=0;
396     while (!reader.atEnd() && !stopped) {
397
398         reader.readNext();
399
400         if(reader.tokenType() == QXmlStreamReader::StartElement) {
401             if(reader.name()=="k"){
402                 a = reader.readElementText();
403                 match = true;
404             }
405         }
406         else if(reader.tokenType() == QXmlStreamReader::Characters) {
407              if(match) {
408                 QString temp(reader.text().toString());
409                 temp.replace("\n","");
410                 if(temp == ""){
411                     while(reader.name()!="ar"&&
412                                 !reader.atEnd()){
413                         reader.readNext();
414                         temp+=reader.text().toString();
415                     }
416                 }
417                 match = false;
418                 cur.prepare("insert into dict values(?,?)");
419                 cur.addBindValue(a);
420                 cur.addBindValue(temp);
421                 cur.exec();
422                 counter++;
423                 int prog = counter*100/_wordsCount;
424                 if(prog % 5 == 0)
425                     Q_EMIT update(prog);
426             }
427
428         }
429     }
430
431     cur.exec("END;");
432     cur.exec("select count(*) from dict");
433     if(!cur.next() || countWords() != cur.value(0).toInt())
434         return false;
435     _settings->setValue("cache_path", cachePathN);
436     _settings->setValue("cached", "true");
437     return true;
438 }
439
440
441 Q_EXPORT_PLUGIN2(xdxf, XdxfPlugin)