1 /*******************************************************************************
3 This file is part of mDictionary.
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.
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.
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/>.
18 Copyright 2010 Comarch S.A.
20 *******************************************************************************/
23 \brief Implementation of xdxf plugin's main class.
25 \author Jakub Jaszczynski <j.j.jaszczynski@gmail.com>
28 #include "xdxfplugin.h"
30 #include "../../include/Notify.h"
31 #include "DownloadDict.h"
32 #include "XdxfDictDownloader.h"
34 XdxfDictDownloader XdxfPlugin::dictDownloader;
37 bool XdxfPlugin::dictDownloaderInitialized = false;
40 XdxfPlugin::XdxfPlugin(QObject *parent) : CommonDictInterface(parent),
41 _langFrom(""), _langTo(""),_name(""), _infoNote("") {
42 _settings = new Settings();
43 _dictDialog = new XdxfDictDialog(this, this);
45 connect(_dictDialog, SIGNAL(notify(Notify::NotifyType,QString)),
46 this, SIGNAL(notify(Notify::NotifyType,QString)));
48 if(!dictDownloaderInitialized) {
49 connect(&dictDownloader, SIGNAL(notify(Notify::NotifyType,QString)),
50 this, SIGNAL(notify(Notify::NotifyType,QString)));
51 dictDownloaderInitialized = true;
54 _settings->setValue("type","xdxf");
55 _iconPath = "/usr/share/mdictionary/xdxf.png";
56 _icon = QIcon(_iconPath);
64 void XdxfPlugin::retranslate() {
65 QString locale = QLocale::system().name();
66 QTranslator *translator = new QTranslator(this);
68 if(!translator->load(":/xdxf/translations/" + locale)) {
69 translator->load(":/xdxf/translations/en_US");
71 QCoreApplication::installTranslator(translator);
75 XdxfPlugin::~XdxfPlugin() {
81 QString XdxfPlugin::langFrom() const {
86 QString XdxfPlugin::langTo() const {
91 QString XdxfPlugin::name() const {
96 QString XdxfPlugin::type() const {
97 return QString("xdxf");
101 QString XdxfPlugin::infoNote() const {
106 QList<Translation*> XdxfPlugin::searchWordList(QString word, int limit) {
107 if( word.indexOf("*")==-1 && word.indexOf("?")==-1 &&
108 word.indexOf("_")==-1 && word.indexOf("%")==-1)
112 return searchWordListCache(word,limit);
113 return searchWordListFile(word, limit);
117 QList<Translation*> XdxfPlugin::searchWordListCache(QString word, int limit) {
118 QSet<Translation*> translations;
119 QString cacheFilePath = _settings->value("cache_path");
121 db.setDatabaseName(cacheFilePath);
122 if(!QFile::exists(cacheFilePath) || !db.open()) {
123 qDebug() << "Database error" << db.lastError().text() << endl;
124 Q_EMIT notify(Notify::Warning, QString(tr("Cache database cannot be "
125 "opened for %1 dictionary. Searching in XDXF file. "
126 "You may want to recache.").arg(name())));
127 _settings->setValue("cached","false");
128 return searchWordListFile(word, limit);
132 word = word.toLower();
133 word = word.replace("*", "%");
134 word = word.replace("?", "_");
138 cur.prepare("select word from dict where word like ? or normalized "
141 cur.prepare("select word from dict where word like ? or normalized "
143 cur.addBindValue(word);
144 cur.addBindValue(word);
146 cur.addBindValue(limit);
149 while(cur.next() && (translations.size()<limit || limit==0)) {
150 translations.insert(new TranslationXdxf(
151 cur.value(0).toString(),
152 _dictionaryInfo, this));
155 return translations.toList();
159 QList<Translation*> XdxfPlugin::searchWordListFile(QString word, int limit) {
160 QSet<Translation*> translations;
161 QFile dictionaryFile(_settings->value("path"));
162 word = word.toLower();
165 QRegExp regWord(word);
166 regWord.setCaseSensitivity(Qt::CaseInsensitive);
167 regWord.setPatternSyntax(QRegExp::Wildcard);
169 /*check xdxf file exist*/
170 if(!QFile::exists(_settings->value("path"))
171 || !dictionaryFile.open(QFile::ReadOnly | QFile::Text)) {
172 qDebug()<<"Error: could not open file";
173 Q_EMIT notify(Notify::Warning,
174 QString(tr("XDXF file cannot be read for %1").arg(name())));
175 return translations.toList();
178 QXmlStreamReader reader(&dictionaryFile);
182 /*search words list*/
183 while(!reader.atEnd() && !stopped){
184 reader.readNextStartElement();
185 if(reader.name()=="ar") {
186 while(reader.name()!="k" && !reader.atEnd())
187 reader.readNextStartElement();
189 readKey = reader.readElementText();
190 if((regWord.exactMatch(readKey)
191 || regWord.exactMatch(removeAccents(readKey)))
192 && (i<limit || limit==0) && !reader.atEnd()) {
193 translations<<(new TranslationXdxf(readKey.toLower(),
194 _dictionaryInfo,this));
195 if(translations.size()==limit && limit!=0)
199 this->thread()->yieldCurrentThread();
202 dictionaryFile.close();
203 return translations.toList();
207 QString XdxfPlugin::search(QString key) {
209 return searchCache(key);
210 return searchFile(key);
214 QString XdxfPlugin::searchCache(QString key) {
216 QString cacheFilePath = _settings->value("cache_path");
217 db.setDatabaseName(cacheFilePath);
220 if(!QFile::exists(cacheFilePath) || !db.open()) {
221 qDebug() << "Database error" << db.lastError().text() << endl;
222 Q_EMIT notify(Notify::Warning, QString(tr("Cache database cannot be "
223 "opened for %1 dictionary. Searching in XDXF file. "
224 "You may want to recache.").arg(name())));
225 _settings->setValue("cached","false");
226 return searchFile(key);
231 cur.prepare("select translation from dict where word like ?");
232 cur.addBindValue(key);
235 result += cur.value(0).toString();
242 QString XdxfPlugin::searchFile(QString key) {
243 QFile dictionaryFile(_settings->value("path"));
244 QString resultString("");
247 /*check xdxf file exist*/
248 if(!QFile::exists(_settings->value("path"))
249 || !dictionaryFile.open(QFile::ReadOnly | QFile::Text)) {
250 Q_EMIT notify(Notify::Warning,
251 QString(tr("XDXF file cannot be read for %1").arg(name())));
252 qDebug()<<"Error: could not open file";
256 QXmlStreamReader reader(&dictionaryFile);
261 /*search translations for word*/
262 while (!reader.atEnd()&& !stopped) {
264 if(reader.tokenType() == QXmlStreamReader::StartElement) {
265 if(reader.name()=="k") {
266 readKey = reader.readElementText();
267 if(readKey.toLower()==key.toLower())
273 while(reader.name()!="ar" && !reader.atEnd()) {
274 if(reader.name()!="" && reader.name()!="k") {
275 if(reader.tokenType()==QXmlStreamReader::EndElement)
277 if(reader.tokenType()==QXmlStreamReader::StartElement)
279 temp+=reader.name().toString();
280 if(reader.name().toString()=="c" &&
281 reader.tokenType()==QXmlStreamReader::StartElement)
282 temp= temp + " c=\"" + reader.attributes().
283 value("c").toString() + "\"";
286 temp+= reader.text().toString().replace("<","<").
290 if(temp.at(0)==QChar('\n'))
292 resultString+="<key>" + readKey +"</key>";
293 resultString+="<t>" + temp + "</t>";
296 this->thread()->yieldCurrentThread();
299 dictionaryFile.close();
304 void XdxfPlugin::stop() {
309 DictDialog* XdxfPlugin::dictDialog() {
314 CommonDictInterface* XdxfPlugin::getNew(const Settings *settings) const {
315 XdxfPlugin *plugin = new XdxfPlugin();
317 connect(plugin, SIGNAL(notify(Notify::NotifyType,QString)),
318 this, SIGNAL(notify(Notify::NotifyType,QString)));
320 ((XdxfDictDialog*)plugin->dictDialog())->setLastDialogParent(_dictDialog->lastDialogParent());
322 if(settings && plugin->setSettings(settings)) {
323 disconnect(plugin, SIGNAL(notify(Notify::NotifyType,QString)),
324 this, SIGNAL(notify(Notify::NotifyType,QString)));
328 disconnect(plugin, SIGNAL(notify(Notify::NotifyType,QString)),
329 this, SIGNAL(notify(Notify::NotifyType,QString)));
336 bool XdxfPlugin::isAvailable() const {
341 Settings* XdxfPlugin::settings() {
346 bool XdxfPlugin::isCached() {
347 if(_settings->value("cached") == "true")
353 bool XdxfPlugin::setSettings(const Settings *settings) {
355 bool isPathChange=false;
356 QString oldPath = _settings->value("path");
357 Settings *oldSettings = new Settings ;
359 if(oldPath != settings->value("path")) {
360 if(oldPath!="" && _settings->value("cache_path")!="")
365 foreach(QString key, _settings->keys())
366 oldSettings->setValue(key, _settings->value(key));
368 foreach(QString key, settings->keys())
369 if(key != "generateCache")
370 _settings->setValue(key, settings->value(key));
372 if(!getDictionaryInfo()) {
373 Q_EMIT notify(Notify::Warning,
374 QString(tr("XDXF file is in wrong format")));
375 qDebug()<<"Error: xdxf file is in wrong format";
377 _settings=oldSettings;
384 _settings->setValue("cached","false");
385 if(_settings->value("cached")=="true"
386 && _settings->value("cache_path")!="") {
387 db_name = _settings->value("type")
388 + _settings->value("cache_path");
389 db = QSqlDatabase::addDatabase("QSQLITE",db_name);
393 if((_settings->value("cached") == "false" ||
394 _settings->value("cached").isEmpty()) &&
395 settings->value("generateCache") == "true") {
400 else if (settings->value("generateCache") == "false") {
401 _settings->setValue("cached", "false");
406 Q_EMIT settingsChanged();
411 bool XdxfPlugin::getDictionaryInfo() {
412 QFile dictionaryFile(_settings->value("path"));
413 if(!QFile::exists(_settings->value("path"))
414 || !dictionaryFile.open(QFile::ReadOnly | QFile::Text)) {
415 Q_EMIT notify(Notify::Warning,
416 QString(tr("XDXF dictionary cannot be read from file")));
417 qDebug()<<"Error: could not open file";
422 QXmlStreamReader reader(&dictionaryFile);
423 reader.readNextStartElement();
424 if(reader.name()=="xdxf") {
426 if(reader.attributes().hasAttribute("lang_from"))
427 _langFrom = reader.attributes().value("lang_from").toString();
428 if(reader.attributes().hasAttribute("lang_to"))
429 _langTo = reader.attributes().value("lang_to").toString();
431 reader.readNextStartElement();
432 if(reader.name()=="full_name")
433 _name=reader.readElementText();
435 qDebug()<<"no full_name";
436 reader.readNextStartElement();
437 if(reader.name()=="description")
438 _infoNote=reader.readElementText();
440 qDebug()<<"no description";
442 _dictionaryInfo= _name + " [" + _langFrom + "-"
445 dictionaryFile.close();
452 QIcon* XdxfPlugin::icon() {
456 QString XdxfPlugin::iconPath(){
461 int XdxfPlugin::countWords() {
464 QFile dictionaryFile(_settings->value("path"));
465 if(!QFile::exists(_settings->value("path"))
466 || !dictionaryFile.open(QFile::ReadOnly | QFile::Text)) {
467 Q_EMIT notify(Notify::Warning,
468 QString(tr("XDXF file cannot be read for %1 dictionary")
470 qDebug()<<"Error: could not open file";
474 dictionaryFile.seek(0);
478 while(!dictionaryFile.atEnd()) {
479 line = dictionaryFile.readLine();
480 if(line.contains("<k>")) {
484 _wordsCount = wordsCount;
485 dictionaryFile.close();
490 bool XdxfPlugin::makeCache(QString) {
491 XdxfCachingDialog d(_dictDialog->lastDialogParent());
493 connect(&d, SIGNAL(cancelCaching()),
495 connect(this, SIGNAL(updateCachingProgress(int,int)),
496 &d, SLOT(updateCachingProgress(int,int)));
499 QCoreApplication::processEvents();
500 QFileInfo dictFileN(_settings->value("path"));
504 /*create cache file name*/
507 cachePathN = QDir::homePath() + "/.mdictionary/"
508 + dictFileN.completeBaseName()+"."
509 +QString::number(i) + ".cache";
511 } while(QFile::exists(cachePathN));
513 db_name = _settings->value("type") + cachePathN;
514 db = QSqlDatabase::addDatabase("QSQLITE",db_name);
516 /*checke errors (File open and db open)*/
517 QFile dictionaryFile(dictFileN.filePath());
518 if (!QFile::exists(_settings->value("path"))
519 || !dictionaryFile.open(QFile::ReadOnly | QFile::Text)) {
520 Q_EMIT updateCachingProgress(100, 0);
521 Q_EMIT notify(Notify::Warning,
522 QString(tr("XDXF file cannot be read for %1 dictionary")
526 QXmlStreamReader reader(&dictionaryFile);
527 db.setDatabaseName(cachePathN);
529 qDebug() << "Database error" << db.lastError().text() << endl;
530 Q_EMIT updateCachingProgress(100, 0);
531 Q_EMIT notify(Notify::Warning, QString(tr("Cache database cannot be "
532 "opened for %1 dictionary. Searching in XDXF file. "
533 "You may want to recache.").arg(name())));
538 QCoreApplication::processEvents();
540 cur.exec("PRAGMA synchronous = 0");
541 cur.exec("drop table dict");
542 QCoreApplication::processEvents();
543 cur.exec("create table dict(word text, normalized text ,translation text)");
553 _settings->setValue("strip_accents", "true");
556 /*add all words to db*/
557 while (!reader.atEnd() && !stopped) {
558 QCoreApplication::processEvents();
560 if(reader.tokenType() == QXmlStreamReader::StartElement) {
561 if(reader.name()=="k"){
562 readKey = reader.readElementText();
568 while(reader.name()!="ar" && !reader.atEnd()) {
569 if(reader.name()!="" && reader.name()!="k") {
570 if(reader.tokenType()==QXmlStreamReader::EndElement)
572 if(reader.tokenType()==QXmlStreamReader::StartElement)
574 temp+=reader.name().toString();
575 if(reader.name().toString()=="c"
576 && reader.tokenType()==QXmlStreamReader::StartElement) {
578 + reader.attributes().value("c").toString()
583 temp+= reader.text().toString().replace("<","<").replace(">"
587 if(temp.at(0)==QChar('\n'))
589 temp="<key>" + readKey + "</key>" + "<t>" + temp+ "</t>";
591 cur.prepare("insert into dict values(?,?,?)");
592 cur.addBindValue(readKey.toLower());
593 cur.addBindValue(removeAccents(readKey).toLower());
594 cur.addBindValue(temp);
597 int prog = counter*100/_wordsCount;
598 if(prog % 2 == 0 && lastProg != prog) {
599 Q_EMIT updateCachingProgress(prog,timer.restart());
605 cur.exec("select count(*) from dict");
607 /*checke errors (wrong number of added words)*/
609 if(!cur.next() || countWords() != cur.value(0).toInt()) {
610 Q_EMIT updateCachingProgress(100, timer.restart());
611 Q_EMIT notify(Notify::Warning,
612 QString(tr("Database caching error, please try again.")));
614 _settings->setValue("cache_path", cachePathN);
617 _settings->setValue("cache_path","");
621 _settings->setValue("cache_path", cachePathN);
622 _settings->setValue("cached", "true");
624 disconnect(&d, SIGNAL(cancelCaching()),
626 disconnect(this, SIGNAL(updateCachingProgress(int,int)),
627 &d, SLOT(updateCachingProgress(int,int)));
633 void XdxfPlugin::clean() {
634 if(QFile::exists(_settings->value("cache_path"))) {
635 QFile(_settings->value("cache_path")).remove();
636 QSqlDatabase::removeDatabase(db_name);
641 Q_EXPORT_PLUGIN2(xdxf, XdxfPlugin)