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 *******************************************************************************/
22 /*! \file xdxfplugin.cpp
23 \author Jakub Jaszczynski <j.j.jaszczynski@gmail.com>
26 #include "xdxfplugin.h"
28 #include "../../include/Notify.h"
30 XdxfPlugin::XdxfPlugin(QObject *parent) : CommonDictInterface(parent),
31 _langFrom(""), _langTo(""),_name(""), _infoNote("") {
32 _settings = new Settings();
33 _dictDialog = new XdxfDictDialog(this, this);
35 connect(_dictDialog, SIGNAL(notify(Notify::NotifyType,QString)),
36 this, SIGNAL(notify(Notify::NotifyType,QString)));
39 _settings->setValue("type","xdxf");
40 _icon = QIcon("/usr/share/mdictionary/xdxf.png");
47 void XdxfPlugin::retranslate() {
48 QString locale = QLocale::system().name();
50 QTranslator *translator = new QTranslator(this);
52 if(!translator->load(":/xdxf/translations/" + locale)) {
53 translator->load(":/xdxf/translations/en_US");
55 QCoreApplication::installTranslator(translator);
59 XdxfPlugin::~XdxfPlugin() {
65 QString XdxfPlugin::langFrom() const {
70 QString XdxfPlugin::langTo() const {
75 QString XdxfPlugin::name() const {
80 QString XdxfPlugin::type() const {
81 return QString("xdxf");
85 QString XdxfPlugin::infoNote() const {
90 QList<Translation*> XdxfPlugin::searchWordList(QString word, int limit) {
91 if( word.indexOf("*")==-1 && word.indexOf("?")==-1 &&
92 word.indexOf("_")==-1 && word.indexOf("%")==-1)
96 return searchWordListCache(word,limit);
97 return searchWordListFile(word, limit);
101 QList<Translation*> XdxfPlugin::searchWordListCache(QString word, int limit) {
102 QSet<Translation*> translations;
103 QString cacheFilePath = _settings->value("cache_path");
105 db.setDatabaseName(cacheFilePath);
106 if(!QFile::exists(cacheFilePath) || !db.open()) {
107 qDebug() << "Database error" << db.lastError().text() << endl;
108 Q_EMIT notify(Notify::Warning, QString(tr("Cache database cannot be "
109 "opened for %1 dictionary. Searching in XDXF file. "
110 "You may want to recache.").arg(name())));
111 _settings->setValue("cached","false");
112 return searchWordListFile(word, limit);
115 word = word.toLower();
116 word = word.replace("*", "%");
117 word = word.replace("?", "_");
121 cur.prepare("select word from dict where word like ? or normalized "
124 cur.prepare("select word from dict where word like ? or normalized "
126 cur.addBindValue(word);
127 cur.addBindValue(word);
129 cur.addBindValue(limit);
132 while(cur.next() && (translations.size()<limit || limit==0)) {
133 translations.insert(new TranslationXdxf(
134 cur.value(0).toString(),
135 _dictionaryInfo, this));
138 return translations.toList();
142 QList<Translation*> XdxfPlugin::searchWordListFile(QString word, int limit) {
143 QSet<Translation*> translations;
144 QFile dictionaryFile(_settings->value("path"));
145 word = word.toLower();
148 QRegExp regWord(word);
149 regWord.setCaseSensitivity(Qt::CaseInsensitive);
150 regWord.setPatternSyntax(QRegExp::Wildcard);
152 /*check xdxf file exist*/
153 if(!QFile::exists(_settings->value("path"))
154 || !dictionaryFile.open(QFile::ReadOnly | QFile::Text)) {
155 qDebug()<<"Error: could not open file";
156 Q_EMIT notify(Notify::Warning,
157 QString(tr("XDXF file cannot be read for %1").arg(name())));
158 return translations.toList();
161 QXmlStreamReader reader(&dictionaryFile);
165 /*search words list*/
166 while(!reader.atEnd() && !stopped){
167 reader.readNextStartElement();
168 if(reader.name()=="ar") {
169 while(reader.name()!="k" && !reader.atEnd())
170 reader.readNextStartElement();
172 readKey = reader.readElementText();
173 if((regWord.exactMatch(readKey)
174 || regWord.exactMatch(removeAccents(readKey)))
175 && (i<limit || limit==0) && !reader.atEnd()) {
176 // qDebug()<<readKey;
177 translations<<(new TranslationXdxf(readKey.toLower(),
178 _dictionaryInfo,this));
179 if(translations.size()==limit && limit!=0)
183 this->thread()->yieldCurrentThread();
186 dictionaryFile.close();
187 return translations.toList();
191 QString XdxfPlugin::search(QString key) {
193 return searchCache(key);
194 return searchFile(key);
198 QString XdxfPlugin::searchCache(QString key) {
200 QString cacheFilePath = _settings->value("cache_path");
201 db.setDatabaseName(cacheFilePath);
204 if(!QFile::exists(cacheFilePath) || !db.open()) {
205 qDebug() << "Database error" << db.lastError().text() << endl;
206 Q_EMIT notify(Notify::Warning, QString(tr("Cache database cannot be "
207 "opened for %1 dictionary. Searching in XDXF file. "
208 "You may want to recache.").arg(name())));
209 _settings->setValue("cached","false");
210 return searchFile(key);
215 cur.prepare("select translation from dict where word like ?");
216 cur.addBindValue(key);
219 result += cur.value(0).toString();
228 QString XdxfPlugin::searchFile(QString key) {
229 QFile dictionaryFile(_settings->value("path"));
230 QString resultString("");
233 /*check xdxf file exist*/
234 if(!QFile::exists(_settings->value("path"))
235 || !dictionaryFile.open(QFile::ReadOnly | QFile::Text)) {
236 Q_EMIT notify(Notify::Warning,
237 QString(tr("XDXF file cannot be read for %1").arg(name())));
238 qDebug()<<"Error: could not open file";
242 QXmlStreamReader reader(&dictionaryFile);
247 /*search translations for word*/
248 while (!reader.atEnd()&& !stopped) {
250 if(reader.tokenType() == QXmlStreamReader::StartElement) {
251 if(reader.name()=="k") {
252 readKey = reader.readElementText();
253 if(readKey.toLower()==key.toLower())
259 while(reader.name()!="ar" && !reader.atEnd()) {
260 if(reader.name()!="" && reader.name()!="k") {
261 if(reader.tokenType()==QXmlStreamReader::EndElement)
263 if(reader.tokenType()==QXmlStreamReader::StartElement)
265 temp+=reader.name().toString();
266 if(reader.name().toString()=="c" &&
267 reader.tokenType()==QXmlStreamReader::StartElement)
268 temp= temp + " c=\"" + reader.attributes().
269 value("c").toString() + "\"";
272 temp+= reader.text().toString().replace("<","<").
276 if(temp.at(0)==QChar('\n'))
278 resultString+="<key>" + readKey +"</key>";
279 resultString+="<t>" + temp + "</t>";
282 this->thread()->yieldCurrentThread();
285 dictionaryFile.close();
290 void XdxfPlugin::stop() {
296 DictDialog* XdxfPlugin::dictDialog() {
301 CommonDictInterface* XdxfPlugin::getNew(const Settings *settings) const {
302 XdxfPlugin *plugin = new XdxfPlugin();
304 connect(plugin, SIGNAL(notify(Notify::NotifyType,QString)),
305 this, SIGNAL(notify(Notify::NotifyType,QString)));
307 ((XdxfDictDialog*)plugin->dictDialog())->setLastDialogParent(_dictDialog->lastDialogParent());
311 if(settings && plugin->setSettings(settings)) {
313 disconnect(plugin, SIGNAL(notify(Notify::NotifyType,QString)),
314 this, SIGNAL(notify(Notify::NotifyType,QString)));
318 disconnect(plugin, SIGNAL(notify(Notify::NotifyType,QString)),
319 this, SIGNAL(notify(Notify::NotifyType,QString)));
326 bool XdxfPlugin::isAvailable() const {
331 Settings* XdxfPlugin::settings() {
336 bool XdxfPlugin::isCached() {
337 if(_settings->value("cached") == "true")
343 bool XdxfPlugin::setSettings(const Settings *settings) {
345 bool isPathChange=false;
346 QString oldPath = _settings->value("path");
347 Settings *oldSettings = new Settings ;
349 if(oldPath != settings->value("path")) {
350 if(oldPath!="" && _settings->value("cache_path")!="")
355 foreach(QString key, _settings->keys())
356 oldSettings->setValue(key, _settings->value(key));
358 foreach(QString key, settings->keys()) {
359 if(key != "generateCache")
360 _settings->setValue(key, settings->value(key));
363 if(!getDictionaryInfo()) {
364 Q_EMIT notify(Notify::Warning,
365 QString(tr("XDXF file is in wrong format")));
366 qDebug()<<"Error: xdxf file is in wrong format";
368 _settings=oldSettings;
375 _settings->setValue("cached","false");
376 if(_settings->value("cached")=="true"
377 && _settings->value("cache_path")!="") {
378 db_name = _settings->value("type")
379 + _settings->value("cache_path");
380 db = QSqlDatabase::addDatabase("QSQLITE",db_name);
384 if((_settings->value("cached") == "false" ||
385 _settings->value("cached").isEmpty()) &&
386 settings->value("generateCache") == "true") {
391 else if (settings->value("generateCache") == "false") {
392 _settings->setValue("cached", "false");
397 Q_EMIT settingsChanged();
402 bool XdxfPlugin::getDictionaryInfo() {
403 QFile dictionaryFile(_settings->value("path"));
404 if(!QFile::exists(_settings->value("path"))
405 || !dictionaryFile.open(QFile::ReadOnly | QFile::Text)) {
406 Q_EMIT notify(Notify::Warning,
407 QString(tr("XDXF dictionary cannot be read from file")));
408 qDebug()<<"Error: could not open file";
413 QXmlStreamReader reader(&dictionaryFile);
414 reader.readNextStartElement();
415 if(reader.name()=="xdxf") {
417 if(reader.attributes().hasAttribute("lang_from"))
418 _langFrom = reader.attributes().value("lang_from").toString();
419 if(reader.attributes().hasAttribute("lang_to"))
420 _langTo = reader.attributes().value("lang_to").toString();
422 reader.readNextStartElement();
423 if(reader.name()=="full_name")
424 _name=reader.readElementText();
426 qDebug()<<"no full_name";
427 reader.readNextStartElement();
428 if(reader.name()=="description")
429 _infoNote=reader.readElementText();
431 qDebug()<<"no description";
433 _dictionaryInfo= _name + " [" + _langFrom + "-"
436 dictionaryFile.close();
443 QIcon* XdxfPlugin::icon() {
448 int XdxfPlugin::countWords() {
451 QFile dictionaryFile(_settings->value("path"));
452 if(!QFile::exists(_settings->value("path"))
453 || !dictionaryFile.open(QFile::ReadOnly | QFile::Text)) {
454 Q_EMIT notify(Notify::Warning,
455 QString(tr("XDXF file cannot be read for %1 dictionary")
457 qDebug()<<"Error: could not open file";
461 dictionaryFile.seek(0);
466 while(!dictionaryFile.atEnd()) {
467 line = dictionaryFile.readLine();
468 if(line.contains("<k>")) {
472 _wordsCount = wordsCount;
473 dictionaryFile.close();
478 bool XdxfPlugin::makeCache(QString) {
480 XdxfCachingDialog d(_dictDialog->lastDialogParent());
482 // qDebug()<<_dictDialog->lastDialogParent();
484 connect(&d, SIGNAL(cancelCaching()),
486 connect(this, SIGNAL(updateCachingProgress(int,int)),
487 &d, SLOT(updateCachingProgress(int,int)));
491 QCoreApplication::processEvents();
492 QFileInfo dictFileN(_settings->value("path"));
496 /*create cache file name*/
499 cachePathN = QDir::homePath() + "/.mdictionary/"
500 + dictFileN.completeBaseName()+"."
501 +QString::number(i) + ".cache";
503 } while(QFile::exists(cachePathN));
505 db_name = _settings->value("type") + cachePathN;
506 db = QSqlDatabase::addDatabase("QSQLITE",db_name);
508 /*checke errors (File open and db open)*/
509 QFile dictionaryFile(dictFileN.filePath());
510 if (!QFile::exists(_settings->value("path"))
511 || !dictionaryFile.open(QFile::ReadOnly | QFile::Text)) {
512 Q_EMIT updateCachingProgress(100, 0);
513 Q_EMIT notify(Notify::Warning,
514 QString(tr("XDXF file cannot be read for %1 dictionary")
518 QXmlStreamReader reader(&dictionaryFile);
519 db.setDatabaseName(cachePathN);
521 qDebug() << "Database error" << db.lastError().text() << endl;
522 Q_EMIT updateCachingProgress(100, 0);
523 Q_EMIT notify(Notify::Warning, QString(tr("Cache database cannot be "
524 "opened for %1 dictionary. Searching in XDXF file. "
525 "You may want to recache.").arg(name())));
530 QCoreApplication::processEvents();
532 cur.exec("PRAGMA synchronous = 0");
533 cur.exec("drop table dict");
534 QCoreApplication::processEvents();
535 cur.exec("create table dict(word text, normalized text ,translation text)");
545 _settings->setValue("strip_accents", "true");
548 /*add all words to db*/
549 while (!reader.atEnd() && !stopped) {
551 QCoreApplication::processEvents();
553 if(reader.tokenType() == QXmlStreamReader::StartElement) {
554 if(reader.name()=="k"){
555 readKey = reader.readElementText();
561 while(reader.name()!="ar" && !reader.atEnd()) {
562 if(reader.name()!="" && reader.name()!="k") {
563 if(reader.tokenType()==QXmlStreamReader::EndElement)
565 if(reader.tokenType()==QXmlStreamReader::StartElement)
567 temp+=reader.name().toString();
568 if(reader.name().toString()=="c"
569 && reader.tokenType()==QXmlStreamReader::StartElement) {
571 + reader.attributes().value("c").toString()
576 temp+= reader.text().toString().replace("<","<").replace(">"
580 if(temp.at(0)==QChar('\n'))
582 temp="<key>" + readKey + "</key>" + "<t>" + temp+ "</t>";
584 cur.prepare("insert into dict values(?,?,?)");
585 cur.addBindValue(readKey.toLower());
586 cur.addBindValue(removeAccents(readKey).toLower());
587 cur.addBindValue(temp);
590 int prog = counter*100/_wordsCount;
591 if(prog % 2 == 0 && lastProg != prog) {
592 Q_EMIT updateCachingProgress(prog,timer.restart());
598 cur.exec("select count(*) from dict");
600 /*checke errors (wrong number of added words)*/
602 if(!cur.next() || countWords() != cur.value(0).toInt()) {
603 Q_EMIT updateCachingProgress(100, timer.restart());
604 Q_EMIT notify(Notify::Warning,
605 QString(tr("Database caching error, please try again.")));
607 _settings->setValue("cache_path", cachePathN);
610 _settings->setValue("cache_path","");
614 _settings->setValue("cache_path", cachePathN);
615 _settings->setValue("cached", "true");
617 disconnect(&d, SIGNAL(cancelCaching()),
619 disconnect(this, SIGNAL(updateCachingProgress(int,int)),
620 &d, SLOT(updateCachingProgress(int,int)));
625 void XdxfPlugin::clean() {
626 if(QFile::exists(_settings->value("cache_path"))) {
627 QFile(_settings->value("cache_path")).remove();
628 QSqlDatabase::removeDatabase(db_name);
633 Q_EXPORT_PLUGIN2(xdxf, XdxfPlugin)