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