add change from searchFile to searchCache in XdxfPlugin
[mdictionary] / trunk / src / plugins / xdxf / src / xdxfplugin.cpp
index 466b7a6..af10ad3 100644 (file)
@@ -1,19 +1,52 @@
+/*******************************************************************************
+
+    This file is part of mDictionary.
+
+    mDictionary is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    mDictionary is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with mDictionary.  If not, see <http://www.gnu.org/licenses/>.
+
+    Copyright 2010 Comarch S.A.
+
+*******************************************************************************/
+
 #include "xdxfplugin.h"
 #include <QDebug>
 #include <QFile>
 #include <QXmlStreamReader>
 #include <QtPlugin>
 #include "TranslationXdxf.h"
+#include "../../../includes/settings.h"
 
 XdxfPlugin::XdxfPlugin(QObject *parent) : CommonDictInterface(parent),
                     _langFrom(tr("")), _langTo(tr("")),_name(tr("")),
                     _type(tr("xdxf")), _infoNote(tr("")) {
-    path="dict.xdxf";
+    _wordsCount = -1;
+    _settings = new Settings();
+    _dictDialog = new XdxfDictDialog(this, this);
+    cachingDialog = new XdxfCachingDialog(this);
+
+    connect(cachingDialog, SIGNAL(cancelCaching()),
+            this, SLOT(stop()));
+
+    _settings->setValue("type","xdxf");
+
     stopped = false;
+
+    _icon = QIcon(":/icons/xdxf.png");
 }
 
-QString XdxfPlugin::langFrom() const {
-    return  _langFrom;
+QString XdxfPlugin::langFrom() const {   
+    return _langFrom;
 }
 
 QString XdxfPlugin::langTo() const {
@@ -25,6 +58,7 @@ QString XdxfPlugin::name() const {
 }
 
 QString XdxfPlugin::type() const {
+//    return _settings->value("type");
     return _type;
 }
 
@@ -33,96 +67,212 @@ QString XdxfPlugin::infoNote() const {
 }
 
 QList<Translation*> XdxfPlugin::searchWordList(QString word, int limit) {
+    //if(_settings->value("cached") == "true")
+    if(word.indexOf("*")==-1 && word.indexOf("?")==-1 && word.indexOf("_")==-1
+       && word.indexOf("%")==-1)
+        word+="*";
+    if(isCached())
+        return searchWordListCache(word,limit);
+    return searchWordListFile(word, limit);
+}
+
+QList<Translation*> XdxfPlugin::searchWordListCache(QString word, int limit) {
+
+    QSet<Translation*> translations;
+    QString cacheFilePath = _settings->value("cache_path");
+        db.setDatabaseName(cacheFilePath);
+        if(!db.open()) {
+            qDebug() << "Database error" << db.lastError().text() << endl;
+            return searchWordListFile(word, limit);
+        }
+
+        stopped = false;
+        if(word.indexOf("*")==-1 && word.indexOf("?")== 0)
+            word+="%";
+        word = word.replace("*", "%");
+        word = word.replace("?", "_");
+        word = removeAccents(word);
+        qDebug() << word;
+
+        QSqlQuery cur(db);
+        cur.prepare("select word from dict where word like ? limit ?");
+        cur.addBindValue(word);
+        cur.addBindValue(limit);
+        cur.exec();
+        while(cur.next())
+            translations.insert(new TranslationXdxf(cur.value(0).toString(),
+                                                    _infoNote, this));
+        return translations.toList();
+}
+
+
+
+QList<Translation*> XdxfPlugin::searchWordListFile(QString word, int limit) {
+    QSet<Translation*> translations;
+    QFile dictionaryFile(path);
+
+    word = removeAccents(word);
+
     stopped = false;
     QRegExp regWord(word);
     regWord.setCaseSensitivity(Qt::CaseInsensitive);
     regWord.setPatternSyntax(QRegExp::Wildcard);
-
-    QList<Translation*> translations;
-    QFile dictionaryFile(path);
     if(!dictionaryFile.open(QFile::ReadOnly | QFile::Text)) {
         qDebug()<<"Error: could not open file";
-        return translations;
-    }
-    QXmlStreamReader dictionaryReader(&dictionaryFile);
-    dictionaryReader.readNextStartElement();
-    if(dictionaryReader.name()=="xdxf") {
-      if(dictionaryReader.attributes().hasAttribute("lang_from"))
-        _langFrom = dictionaryReader.attributes().value("lang_from").toString();
-      if(dictionaryReader.attributes().hasAttribute("lang_to"))
-        _langTo = dictionaryReader.attributes().value("lang_to").toString();
-    }
-    dictionaryReader.readNextStartElement();
-    if(dictionaryReader.name()=="full_name")
-        _name=dictionaryReader.readElementText();
-    dictionaryReader.readNextStartElement();
-    if(dictionaryReader.name()=="description")
-        _infoNote=dictionaryReader.readElementText();
+        return translations.toList();
+    }
+
+    QXmlStreamReader reader(&dictionaryFile);
+    /*search words list*/
     QString a;
     int i=0;
-    while(!dictionaryReader.atEnd() && !stopped){
-        dictionaryReader.readNextStartElement();
-        if(dictionaryReader.name()=="ar"){
-            while(dictionaryReader.name()!="k" && !dictionaryReader.atEnd())
-                dictionaryReader.readNextStartElement();
-           a = dictionaryReader.readElementText();
-           if(regWord.exactMatch(a) && i<limit) {
-                translations.append(new TranslationXdxf(a,_infoNote,this));
+    while(!reader.atEnd() && !stopped){
+        reader.readNextStartElement();
+        if(reader.name()=="ar") {
+            while(reader.name()!="k" && !reader.atEnd())
+                reader.readNextStartElement();
+            if(!reader.atEnd())
+                a = reader.readElementText();
+            if(regWord.exactMatch(removeAccents(a)) && (i<limit || limit==0)) {
+                bool ok=true;
+                Translation *tran;
+                foreach(tran,translations)
+                {
+                    if(tran->key()==a)
+                        ok=false;  /*if key word is in the dictionary more that one */
+                }
+                if(ok)  /*add key word to list*/
+                    translations<<(new TranslationXdxf(a,_infoNote,this));
                 i++;
-                if(i>=limit)
+                if(i>=limit && limit!=0)
                     break;
             }
         }
+        this->thread()->yieldCurrentThread();
     }
     stopped=false;
     dictionaryFile.close();
-    return translations;
+    return translations.toList();
 }
 
 QString XdxfPlugin::search(QString key) {
+//    if(_settings->value("cached") == "true")
+    if(isCached())
+        return searchCache(key);
+    return searchFile(key);
+}
+
+
+
+QString XdxfPlugin::searchCache(QString key) {
+    QString result;
+    QString cacheFilePath = _settings->value("cache_path");
+    db.setDatabaseName(cacheFilePath);
+
+    if(!db.open()) {
+        qDebug() << "Database error" << db.lastError().text() << endl;
+        return searchFile(key);
+    }
+
+    QSqlQuery cur(db);
+    cur.prepare("select translation from dict where word like ? limit 1");
+    cur.addBindValue(key);
+    cur.exec();
+    if(cur.next())
+        result = cur.value(0).toString();
+    return result;
+
+}
+
+
+
+
+QString XdxfPlugin::searchFile(QString key) {
     QFile dictionaryFile(path);
+    QString resultString("");
     if(!dictionaryFile.open(QFile::ReadOnly | QFile::Text)) {
         qDebug()<<"Error: could not open file";
         return "";
     }
-    QXmlStreamReader dictionaryReader(&dictionaryFile);
+    QXmlStreamReader reader(&dictionaryFile);
+
 
     QString a;
+
     bool match =false;
-    while (!dictionaryReader.atEnd()) {
-        dictionaryReader.readNext();
-        if(dictionaryReader.tokenType() == QXmlStreamReader::StartElement) {
-            if(dictionaryReader.name()=="k") {
-                a = dictionaryReader.readElementText();
+    stopped = false;
+    while (!reader.atEnd()&& !stopped) {
+        reader.readNext();
+        if(reader.tokenType() == QXmlStreamReader::StartElement) {
+            if(reader.name()=="k") {
+                a = reader.readElementText();
                 if(a==key)
                     match = true;
             }
         }
-        else if(dictionaryReader.tokenType() == QXmlStreamReader::Characters)  {
-            if(match) {
-              QString temp(dictionaryReader.text().toString().replace("\n",""));
-              dictionaryFile.close();
-              return temp;
+        if(match) {
+            QString temp("");
+            while(reader.name()!="ar" && !reader.atEnd()) {
+                if(reader.name()!="" && reader.name()!="k") {
+                    if(reader.tokenType()==QXmlStreamReader::EndElement)
+                        temp+=tr("</");
+                    if(reader.tokenType()==QXmlStreamReader::StartElement)
+                        temp+=tr("<");
+                    temp+=reader.name().toString();
+                    if(reader.name().toString()=="c" && reader.tokenType()==QXmlStreamReader::StartElement)
+                       temp= temp + tr(" c=\"") + reader.attributes().value(tr("c")).toString() + tr("\"");
+                    temp+=tr(">");
+                }
+                temp+= reader.text().toString();
+                reader.readNext();
             }
+            resultString+=tr("<t>") + temp.replace("\n","") + tr("</t>");
+            match=false;
         }
+        this->thread()->yieldCurrentThread();
     }
-    return "";
+    stopped=false;
+    dictionaryFile.close();
+    return resultString;
 }
 
 void XdxfPlugin::stop() {
     stopped=true;
 }
 
-QDialog* XdxfPlugin::loadDialog() {
-     path="dict.xdxf";
+DictDialog* XdxfPlugin::dictDialog() {
+     return _dictDialog;
 }
 
-QDialog* XdxfPlugin::settingsDialog() {
-    path="dict.xdxf";
+void XdxfPlugin::setPath(QString path){
+    this->path=path;
+    _settings->setValue("path",path);
+    //getDictionaryInfo();
 }
 
-CommonDictInterface* XdxfPlugin::getNew(const Settings*) const {
-  return new XdxfPlugin();
+
+CommonDictInterface* XdxfPlugin::getNew(const Settings *settings) const {
+    XdxfPlugin *plugin = new XdxfPlugin();
+    if(settings){
+        plugin->setPath(settings->value("path"));
+
+        QStringList list = settings->keys();
+        foreach(QString key, list)
+            plugin->settings()->setValue(key, settings->value(key));
+
+
+        plugin->db_name = plugin->_settings->value("type")
+               + plugin->_settings->value("path");
+        plugin->db = QSqlDatabase::addDatabase("QSQLITE", plugin->db_name);
+
+        if(settings->value("cached").isEmpty() &&
+           settings->value("generateCache") == "true") {
+            plugin->makeCache("");
+        }
+    }
+
+    plugin->getDictionaryInfo();
+    return  plugin;
 }
 
 bool XdxfPlugin::isAvailable() const {
@@ -139,4 +289,213 @@ uint XdxfPlugin::hash() const
    return _hash;
 }
 
+Settings* XdxfPlugin::settings() {
+    return _settings;
+}
+
+bool XdxfPlugin::isCached()
+{
+    if(_settings->value("cached") == "true")
+        return true;
+    return false;
+}
+
+void XdxfPlugin::setSettings(Settings *settings) {
+
+    QString oldPath = _settings->value("path");
+    if(oldPath != settings->value("path")) {
+        setPath(settings->value("path"));
+    }
+
+    if((_settings->value("cached") == "false" ||
+        _settings->value("cached").isEmpty()) &&
+       settings->value("generateCache") == "true") {
+        makeCache("");
+    }
+    else {
+       _settings->setValue("cached", "false");
+    }
+
+    emit settingsChanged();
+}
+
+
+void XdxfPlugin::getDictionaryInfo() {
+    QFile dictionaryFile(path);
+    if(!dictionaryFile.open(QFile::ReadOnly | QFile::Text)) {
+        qDebug()<<"Error: could not open file";
+        return;
+    }
+
+    QXmlStreamReader reader(&dictionaryFile);
+    reader.readNextStartElement();
+    if(reader.name()=="xdxf") {
+      if(reader.attributes().hasAttribute("lang_from"))
+        _langFrom = reader.attributes().value("lang_from").toString();
+      if(reader.attributes().hasAttribute("lang_to"))
+        _langTo = reader.attributes().value("lang_to").toString();
+    }
+    reader.readNextStartElement();
+    if(reader.name()=="full_name")
+        _name=reader.readElementText();
+    reader.readNextStartElement();
+    if(reader.name()=="description")
+        _infoNote=reader.readElementText();
+
+    dictionaryFile.close();
+}
+
+QString XdxfPlugin::removeAccents(QString string) {
+
+    string = string.replace(QString::fromUtf8("ł"), "l", Qt::CaseInsensitive);
+    QString normalized = string.normalized(QString::NormalizationForm_D);
+    normalized = normalized;
+    for(int i=0; i<normalized.size(); i++) {
+        if( !normalized[i].isLetterOrNumber() &&
+            !normalized[i].isSpace() &&
+            !normalized[i].isDigit() &&
+            normalized[i] != '*' &&
+            normalized[i] != '%' &&
+            normalized[i] != '_' &&
+            normalized[i] != '?' ) {
+            normalized.remove(i,1);
+        }
+    }
+    return normalized;
+}
+
+QIcon* XdxfPlugin::icon() {
+    return &_icon;
+}
+
+int XdxfPlugin::countWords() {
+    if(_wordsCount > 0)
+        return _wordsCount;
+
+    QFile dictionaryFile(path);
+    if(!dictionaryFile.open(QFile::ReadOnly | QFile::Text)) {
+        qDebug()<<"Error: could not open file";
+        return -1;
+    }
+
+    dictionaryFile.seek(0);
+
+    long wordsCount = 0;
+
+    QString line;
+    while(!dictionaryFile.atEnd()) {
+        line = dictionaryFile.readLine();
+        if(line.contains("<k>")) {
+            wordsCount++;
+        }
+    }
+    _wordsCount = wordsCount;
+    dictionaryFile.close();
+    return wordsCount;
+}
+
+
+
+bool XdxfPlugin::makeCache(QString dir) {
+    cachingDialog->setVisible(true);
+    QCoreApplication::processEvents();
+    stopped = false;
+    QFileInfo dictFileN(_settings->value("path"));
+    QString cachePathN;
+    cachePathN = QDir::homePath() + "/.mdictionary/"
+                 + dictFileN.completeBaseName() + ".cache";
+
+    QFile dictionaryFile(dictFileN.filePath());
+
+
+    if (!dictionaryFile.open(QFile::ReadOnly | QFile::Text)) {
+        return 0;
+    }
+
+    QXmlStreamReader reader(&dictionaryFile);
+
+
+    db.setDatabaseName(cachePathN);
+    if(!db.open()) {
+        qDebug() << "Database error" << endl;
+        return false;
+    }
+    QCoreApplication::processEvents();
+    QSqlQuery cur(db);
+    cur.exec("PRAGMA synchronous = 0");
+    cur.exec("drop table dict");
+    QCoreApplication::processEvents();
+    cur.exec("create table dict(word text ,translation text)");
+    int counter = 0;
+    cur.exec("BEGIN;");
+
+    QString a;
+    bool match = false;
+    QTime timer;
+    timer.start();
+    countWords();
+
+    int lastProg = -1;
+
+
+    counter=0;
+    while (!reader.atEnd() && !stopped) {
+
+        QCoreApplication::processEvents();
+       // usleep(50);
+        reader.readNext();
+
+        if(reader.tokenType() == QXmlStreamReader::StartElement) {
+            if(reader.name()=="k"){
+                a = reader.readElementText();
+                match = true;
+            }
+        }
+        if(match) {
+            QString temp("");
+            while(reader.name()!="ar" && !reader.atEnd()) {
+                if(reader.name()!="" && reader.name()!="k") {
+                    if(reader.tokenType()==QXmlStreamReader::EndElement)
+                        temp+=tr("</");
+                    if(reader.tokenType()==QXmlStreamReader::StartElement)
+                        temp+=tr("<");
+                    temp+=reader.name().toString();
+                    if(reader.name().toString()=="c" && reader.tokenType()==QXmlStreamReader::StartElement)
+                       temp= temp + tr(" c=\"") + reader.attributes().value(tr("c")).toString() + tr("\"");
+                    temp+=tr(">");
+                }
+                temp+= reader.text().toString();
+                reader.readNext();
+            }
+            temp += tr("<t>") + temp.replace("\n","") + tr("</t>");
+            match=false;
+            cur.prepare("insert into dict values(?,?)");
+            cur.addBindValue(a);
+            cur.addBindValue(temp);
+            cur.exec();
+            counter++;
+            int prog = counter*100/_wordsCount;
+            if(prog % 5 == 0 && lastProg != prog) {
+                Q_EMIT updateCachingProgress(prog,
+                                             timer.restart());
+                lastProg = prog;
+            }
+        }
+    }
+
+    cur.exec("END;");
+    cur.exec("select count(*) from dict");
+
+    countWords();
+    cachingDialog->setVisible(false);
+
+    if(!cur.next() || countWords() != cur.value(0).toInt())
+        return false;
+    _settings->setValue("cache_path", cachePathN);
+    _settings->setValue("cached", "true");
+
+    return true;
+}
+
+
 Q_EXPORT_PLUGIN2(xdxf, XdxfPlugin)