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