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