Merge branch 'master' of ssh://drop.maemo.org/git/mdictionary
[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     cachingDialog = new XdxfCachingDialog(this);
37
38     connect(cachingDialog, SIGNAL(cancelCaching()),
39             this, SLOT(stop()));
40
41     _settings->setValue("type","xdxf");
42
43     stopped = false;
44
45     _icon = QIcon(":/icons/xdxf.png");
46 }
47
48 QString XdxfPlugin::langFrom() const {   
49     return _langFrom;
50 }
51
52 QString XdxfPlugin::langTo() const {
53     return  _langTo;
54 }
55
56 QString XdxfPlugin::name() const {
57     return  _name;
58 }
59
60 QString XdxfPlugin::type() const {
61 //    return _settings->value("type");
62     return _type;
63 }
64
65 QString XdxfPlugin::infoNote() const {
66     return  _infoNote;
67 }
68
69 QList<Translation*> XdxfPlugin::searchWordList(QString word, int limit) {
70     //if(_settings->value("cached") == "true")
71     if(word.indexOf("*")==-1 && word.indexOf("?")==-1 && word.indexOf("_")==-1
72        && word.indexOf("%")==-1)
73         word+="*";
74     if(isCached())
75         return searchWordListCache(word,limit);
76     return searchWordListFile(word, limit);
77 }
78
79 QList<Translation*> XdxfPlugin::searchWordListCache(QString word, int limit) {
80
81     QSet<Translation*> translations;
82     QString cacheFilePath = _settings->value("cache_path");
83         db.setDatabaseName(cacheFilePath);
84         if(!db.open()) {
85             qDebug() << "Database error" << db.lastError().text() << endl;
86             return searchWordListFile(word, limit);
87         }
88
89         stopped = false;
90         if(word.indexOf("*")==-1 && word.indexOf("?")== 0)
91             word+="%";
92         word = word.toLower();
93         word = word.replace("*", "%");
94         word = word.replace("?", "_");
95         word = removeAccents(word);
96         qDebug() << word;
97
98         QSqlQuery cur(db);
99         cur.prepare("select word from dict where word like ? limit ?");
100         cur.addBindValue(word);
101         cur.addBindValue(limit);
102         cur.exec();
103         while(cur.next())
104             translations.insert(new TranslationXdxf(
105                         cur.value(0).toString().toLower(),
106                         _infoNote, this));
107         return translations.toList();
108 }
109
110
111
112 QList<Translation*> XdxfPlugin::searchWordListFile(QString word, int limit) {
113     QSet<Translation*> translations;
114     QFile dictionaryFile(path);
115
116     word = word.toLower();
117     word = removeAccents(word);
118
119     stopped = false;
120     QRegExp regWord(word);
121     regWord.setCaseSensitivity(Qt::CaseInsensitive);
122     regWord.setPatternSyntax(QRegExp::Wildcard);
123     if(!dictionaryFile.open(QFile::ReadOnly | QFile::Text)) {
124         qDebug()<<"Error: could not open file";
125         return translations.toList();
126     }
127
128     QXmlStreamReader dictionaryReader(&dictionaryFile);
129     /*search words list*/
130     QString a;
131     int i=0;
132     while(!dictionaryReader.atEnd() && !stopped){
133         dictionaryReader.readNextStartElement();
134         if(dictionaryReader.name()=="ar"){
135             while(dictionaryReader.name()!="k" && !dictionaryReader.atEnd())
136                 dictionaryReader.readNextStartElement();
137             if(!dictionaryReader.atEnd())
138                 a = dictionaryReader.readElementText();
139             if(regWord.exactMatch(removeAccents(a)) && (i<limit || limit==0)) {
140                 bool ok=true;
141                 Translation *tran;
142                 foreach(tran,translations) {
143                     if(tran->key()==a)
144                         ok=false;  /*if key word is in the dictionary more that one */
145                 }
146                 if(ok)  /*add key word to list*/
147                     translations<<(new TranslationXdxf(a.toLower(),
148                                 _infoNote,this));
149                 i++;
150                 if(i>=limit && limit!=0)
151                     break;
152             }
153         }
154         this->thread()->yieldCurrentThread();
155     }
156     stopped=false;
157     dictionaryFile.close();
158     return translations.toList();
159 }
160
161 QString XdxfPlugin::search(QString key) {
162 //    if(_settings->value("cached") == "true")
163     if(isCached())
164         return searchCache(key);
165     return searchFile(key);
166 }
167
168
169
170 QString XdxfPlugin::searchCache(QString key) {
171     QString result;
172     QString cacheFilePath = _settings->value("cache_path");
173     db.setDatabaseName(cacheFilePath);
174     key = key.toLower();
175
176     if(!db.open()) {
177         qDebug() << "Database error" << db.lastError().text() << endl;
178         return searchFile(key);
179     }
180
181     QSqlQuery cur(db);
182     cur.prepare("select translation from dict where word like ? limit 1");
183     cur.addBindValue(key);
184     cur.exec();
185     if(cur.next())
186         result = cur.value(0).toString();
187     return result;
188
189 }
190
191
192
193
194 QString XdxfPlugin::searchFile(QString key) {
195     key = key.toLower();
196     QFile dictionaryFile(path);
197     QString resultString("");
198     if(!dictionaryFile.open(QFile::ReadOnly | QFile::Text)) {
199         qDebug()<<"Error: could not open file";
200         return "";
201     }
202     QXmlStreamReader dictionaryReader(&dictionaryFile);
203
204
205     QString a;
206
207     bool match =false;
208     stopped = false;
209     while (!dictionaryReader.atEnd()&& !stopped) {
210         dictionaryReader.readNext();
211         if(dictionaryReader.tokenType() == QXmlStreamReader::StartElement) {
212             if(dictionaryReader.name()=="k") {
213                 a = dictionaryReader.readElementText();
214                 if(a==key)
215                     match = true;
216             }
217         }
218         else if(dictionaryReader.tokenType() == QXmlStreamReader::Characters) {
219             if(match) {
220  /*             QString temp(dictionaryReader.text().toString());
221                 if(temp=="\n")
222                     temp=dictionaryReader.readElementText();
223                 temp.replace("\n","");
224                 if(temp == ""){
225                     int i=0;
226                     while(dictionaryReader.name()!="ar"&&
227                                 !dictionaryReader.atEnd()){
228                         dictionaryReader.readNext();
229                         if(dictionaryReader.name()!="" &&
230                                          dictionaryReader.name()!="ar") {
231                             if(dictionaryReader.tokenType()==QXmlStreamReader::EndElement)
232                                 temp+=tr("</");
233                             if(dictionaryReader.tokenType()==QXmlStreamReader::StartElement)
234                                 temp+=tr("<");
235                             qDebug()<<dictionaryReader.tokenType();
236                             temp=temp+dictionaryReader.name().toString() + tr(">");
237                             i++;
238                         }
239                         temp+=dictionaryReader.text().toString();
240                     }
241                 }
242                 resultString+=temp.replace("\n","")+"\n";
243                 match=false;
244 */
245                 QString temp("");
246                 while(dictionaryReader.name()!="ar" && !dictionaryReader.atEnd()) {
247                     if(dictionaryReader.name()!="") {
248                         if(dictionaryReader.tokenType()==QXmlStreamReader::EndElement)
249                             temp+=tr("</");
250                         if(dictionaryReader.tokenType()==QXmlStreamReader::StartElement)
251                             temp+=tr("<");
252                         temp=temp+dictionaryReader.name().toString() + tr(">");
253                     }
254                     temp+= dictionaryReader.text().toString();
255                     dictionaryReader.readNext();
256                 }
257                 resultString+=tr("<t>") + temp.replace("\n","") + tr("</t>");
258                 match=false;
259             }
260         }
261         this->thread()->yieldCurrentThread();
262     }
263     stopped=false;
264     dictionaryFile.close();
265     return resultString;
266 }
267
268 void XdxfPlugin::stop() {
269     stopped=true;
270 }
271
272 DictDialog* XdxfPlugin::dictDialog() {
273      return _dictDialog;
274 }
275
276 void XdxfPlugin::setPath(QString path){
277     this->path=path;
278     _settings->setValue("path",path);
279     //getDictionaryInfo();
280 }
281
282
283 CommonDictInterface* XdxfPlugin::getNew(const Settings *settings) const {
284     XdxfPlugin *plugin = new XdxfPlugin();
285     if(settings){
286         plugin->setPath(settings->value("path"));
287
288         QStringList list = settings->keys();
289         foreach(QString key, list)
290             plugin->settings()->setValue(key, settings->value(key));
291
292
293         plugin->db_name = plugin->_settings->value("type")
294                + plugin->_settings->value("path");
295         plugin->db = QSqlDatabase::addDatabase("QSQLITE", plugin->db_name);
296
297         if(settings->value("cached").isEmpty() &&
298            settings->value("generateCache") == "true") {
299             plugin->makeCache("");
300         }
301     }
302
303     plugin->getDictionaryInfo();
304     return  plugin;
305 }
306
307 bool XdxfPlugin::isAvailable() const {
308     return true;
309 }
310
311 void XdxfPlugin::setHash(uint _hash) {
312     this->_hash=_hash;
313 }
314
315 uint XdxfPlugin::hash() const {
316    return _hash;
317 }
318
319 Settings* XdxfPlugin::settings() {
320     return _settings;
321 }
322
323 bool XdxfPlugin::isCached() {
324     if(_settings->value("cached") == "true")
325         return true;
326     return false;
327 }
328
329 void XdxfPlugin::setSettings(Settings *settings) {
330
331     QString oldPath = _settings->value("path");
332     if(oldPath != settings->value("path")) {
333         setPath(settings->value("path"));
334     }
335
336     if((_settings->value("cached") == "false" ||
337         _settings->value("cached").isEmpty()) &&
338        settings->value("generateCache") == "true") {
339         makeCache("");
340     }
341     else {
342        _settings->setValue("cached", "false");
343     }
344
345     emit settingsChanged();
346 }
347
348
349 void XdxfPlugin::getDictionaryInfo() {
350     QFile dictionaryFile(path);
351     if(!dictionaryFile.open(QFile::ReadOnly | QFile::Text)) {
352         qDebug()<<"Error: could not open file";
353         return;
354     }
355
356     QXmlStreamReader dictionaryReader(&dictionaryFile);
357     dictionaryReader.readNextStartElement();
358     if(dictionaryReader.name()=="xdxf") {
359       if(dictionaryReader.attributes().hasAttribute("lang_from"))
360         _langFrom = dictionaryReader.attributes().value("lang_from").toString();
361       if(dictionaryReader.attributes().hasAttribute("lang_to"))
362         _langTo = dictionaryReader.attributes().value("lang_to").toString();
363     }
364     dictionaryReader.readNextStartElement();
365     if(dictionaryReader.name()=="full_name")
366         _name=dictionaryReader.readElementText();
367     dictionaryReader.readNextStartElement();
368     if(dictionaryReader.name()=="description")
369         _infoNote=dictionaryReader.readElementText();
370
371     dictionaryFile.close();
372 }
373
374 QString XdxfPlugin::removeAccents(QString string) {
375     string = string.replace(QString::fromUtf8("ł"), "l", Qt::CaseInsensitive);
376     QString normalized = string.normalized(QString::NormalizationForm_D);
377     normalized = normalized;
378     for(int i=0; i<normalized.size(); i++) {
379         if( !normalized[i].isLetterOrNumber() &&
380             !normalized[i].isSpace() &&
381             !normalized[i].isDigit() &&
382             normalized[i] != '*' &&
383             normalized[i] != '%' &&
384             normalized[i] != '_' &&
385             normalized[i] != '?' ) {
386             normalized.remove(i,1);
387         }
388     }
389     return normalized;
390 }
391
392 QIcon* XdxfPlugin::icon() {
393     return &_icon;
394 }
395
396 int XdxfPlugin::countWords() {
397     if(_wordsCount > 0)
398         return _wordsCount;
399
400     QFile dictionaryFile(path);
401     if(!dictionaryFile.open(QFile::ReadOnly | QFile::Text)) {
402         qDebug()<<"Error: could not open file";
403         return -1;
404     }
405
406     dictionaryFile.seek(0);
407
408     long wordsCount = 0;
409
410     QString line;
411     while(!dictionaryFile.atEnd()) {
412         line = dictionaryFile.readLine();
413         if(line.contains("<k>")) {
414             wordsCount++;
415         }
416     }
417     _wordsCount = wordsCount;
418     dictionaryFile.close();
419     return wordsCount;
420 }
421
422
423
424 bool XdxfPlugin::makeCache(QString dir) {
425     cachingDialog->setVisible(true);
426     QCoreApplication::processEvents();
427     stopped = false;
428     QFileInfo dictFileN(_settings->value("path"));
429     QString cachePathN;
430     cachePathN = QDir::homePath() + "/.mdictionary/"
431                  + dictFileN.completeBaseName() + ".cache";
432
433     QFile dictionaryFile(dictFileN.filePath());
434
435
436     if (!dictionaryFile.open(QFile::ReadOnly | QFile::Text)) {
437         return 0;
438     }
439
440     QXmlStreamReader reader(&dictionaryFile);
441
442     db.setDatabaseName(cachePathN);
443     if(!db.open()) {
444         qDebug() << "Database error" << db.lastError().text() << endl;
445         return false;
446     }
447     QCoreApplication::processEvents();
448     QSqlQuery cur(db);
449     cur.exec("PRAGMA synchronous = 0");
450     cur.exec("drop table dict");
451     QCoreApplication::processEvents();
452     cur.exec("create table dict(word text ,translation text)");
453     int counter = 0;
454     cur.exec("BEGIN;");
455
456     QString a;
457     bool match = false;
458     QTime timer;
459     timer.start();
460     countWords();
461
462     int lastProg = -1;
463
464
465     counter=0;
466     while (!reader.atEnd() && !stopped) {
467
468         QCoreApplication::processEvents();
469         reader.readNext();
470
471         if(reader.tokenType() == QXmlStreamReader::StartElement) {
472             if(reader.name()=="k"){
473                 a = reader.readElementText();
474                 match = true;
475             }
476         }
477         else if(reader.tokenType() == QXmlStreamReader::Characters) {
478              if(match) {
479                 QString temp("");
480                 while(reader.name()!="ar" && !reader.atEnd()) {
481                     if(reader.name()!="") {
482                         if(reader.tokenType()==QXmlStreamReader::EndElement)
483                             temp+=tr("</");
484                         if(reader.tokenType()==QXmlStreamReader::StartElement)
485                             temp+=tr("<");
486                         temp=temp+reader.name().toString() + tr(">");
487                     }
488                     temp+= reader.text().toString();
489                     reader.readNext();
490                 }
491                 temp=tr("<t>") + temp.replace("\n","") + tr("</t>");
492                 match = false;
493                 cur.prepare("insert into dict values(?,?)");
494                 cur.addBindValue(a);
495                 cur.addBindValue(temp);
496                 cur.exec();
497                 counter++;
498                 int prog = counter*100/_wordsCount;
499                 if(prog % 5 == 0 && lastProg != prog) {
500                     Q_EMIT updateCachingProgress(prog,
501                                                  timer.restart());
502                     lastProg = prog;
503                 }
504             }
505
506         }
507     }
508
509     cur.exec("END;");
510     cur.exec("select count(*) from dict");
511
512     countWords();
513     cachingDialog->setVisible(false);
514
515     if(!cur.next() || countWords() != cur.value(0).toInt())
516         return false;
517     _settings->setValue("cache_path", cachePathN);
518     _settings->setValue("cached", "true");
519
520     return true;
521 }
522
523
524 Q_EXPORT_PLUGIN2(xdxf, XdxfPlugin)