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