Backbone test fixed
[mdictionary] / trunk / src / base / backbone / backbone.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 // Created by Bartosz Szatkowski
23
24 #include "backbone.h"
25 #include <QDebug>
26
27 void Backbone::init() {
28    _interval = 250; //msec
29    dryRun = false;
30
31    if(!_configPath.size())
32        _configPath = QDir::homePath() + "/.mdictionary/mdictionary.config";
33    if(!_defaultConfigPath.size())
34        _defaultConfigPath = QDir::homePath() + "/.mdictionary/mdictionary.defaults";
35    if(!_pluginPath.size())
36        _pluginPath = "/usr/lib/mdictionary";
37    _historyLen = 10;
38    _searchLimit = 15;
39
40    loadPrefs(_defaultConfigPath);
41    _defaultPluginPath = _pluginPath;
42    _defaultHistoryLen = _historyLen;
43    _defaultSearchLimit = _searchLimit;
44    loadPrefs(_configPath);
45
46    loadPlugins();
47
48    loadDicts(_defaultConfigPath, true);
49    loadDicts(_configPath);
50
51    connect(&_timerSearch, SIGNAL(timeout()), this, SLOT(translationReady()));
52    connect(&_timerHtmlSearch, SIGNAL(timeout()), this,
53            SLOT(htmlTranslationReady()));
54 }
55
56 Backbone::Backbone(QString pluginPath, QString configPath, QObject *parent)
57     : QObject(parent)
58 {
59     init();
60     dryRun = true;
61     _pluginPath = pluginPath;
62     _configPath = configPath;
63     _defaultConfigPath = configPath;
64 }
65
66
67
68 Backbone::~Backbone()
69 {
70     QListIterator<CommonDictInterface*> it(_dicts.keys());
71
72     while(it.hasNext())
73         delete it.next();
74
75     it = QListIterator<CommonDictInterface*>(_plugins);
76     while(it.hasNext())
77         delete it.next();
78
79     QHashIterator<QString, Translation*> it2(_result);
80     while(it2.hasNext())
81         delete it2.next().value();
82
83 }
84
85
86
87
88 Backbone::Backbone(const Backbone &b) :QObject(b.parent()) {
89    // init();
90     _dicts = QHash<CommonDictInterface*, bool > (b._dicts);
91     _plugins = QList<CommonDictInterface* > (b._plugins);
92     _result = QHash<QString, Translation* > (b._result);
93     _searchLimit = b.searchLimit();
94 }
95
96
97
98
99 int Backbone::searchLimit() const {
100     return _searchLimit;
101 }
102
103
104
105
106 QHash<CommonDictInterface*, bool > Backbone::getDictionaries() {
107     return _dicts;
108 }
109
110
111
112
113 QList<CommonDictInterface* > Backbone::getPlugins() {
114     return _plugins;
115 }
116
117
118
119
120 QList<QString> Backbone::getHistory() {
121     //TODO code needed
122 }
123
124
125
126
127 QMultiHash<QString, Translation*> Backbone::result() {
128     return _result;
129 }
130
131
132
133
134 void Backbone::stopSearching() {
135     _timerSearch.stop();
136     _timerHtmlSearch.stop();
137     foreach(CommonDictInterface* dict, _dicts.keys())
138         dict->stop();
139 }
140
141
142
143
144 void Backbone::search(QStringList words) {
145     _timerSearch.stop();
146     _result.clear();
147     _innerResult.clear();
148
149     _timerSearch.start(_interval);
150     foreach(QString word, words)
151         foreach(CommonDictInterface* dict, _dicts.keys())
152             if(_dicts[dict] == 1) {
153                 QFuture<QList<Translation*> > tr =
154                         QtConcurrent::run(dict,
155                                       &CommonDictInterface::searchWordList,word,
156                                                              searchLimit());
157                 _innerResult.append(tr);
158             }
159
160 }
161
162
163
164
165 void Backbone::selectedDictionaries(QList<CommonDictInterface* > activeDicts) {
166     foreach(CommonDictInterface* dict, _dicts.keys())
167         if(activeDicts.contains(dict))
168             _dicts[dict] = 1;
169         else
170             _dicts[dict] = 0;
171     dictUpdated();
172  }
173
174
175
176 void Backbone::addDictionary(CommonDictInterface *dict, bool active) {
177     addInternalDictionary(dict,active);
178     dictUpdated();
179 }
180
181
182
183  void Backbone::addInternalDictionary(CommonDictInterface* dict, bool active) {
184      dict->setHash(_dicts.size()+1);
185      _dicts[dict] = active;
186      connect(dict, SIGNAL(settingsChanged()), this, SLOT(dictUpdated()));
187  }
188
189  void Backbone::removeDictionary(CommonDictInterface *dict) {
190      _dicts.remove(dict);
191      dictUpdated();
192
193  }
194
195
196
197  void Backbone::quit() {
198     stopSearching();
199     Q_EMIT closeOk();
200 }
201
202
203
204 int Backbone::activeSearches() const {
205     return _innerResult.size();
206 }
207
208
209
210 void Backbone::translationReady() {
211     foreach(QFuture<QList<Translation*> > trans, _innerResult) {
212         if(!trans.isFinished())
213             continue;
214         QList<Translation*> tList = trans.result();
215         foreach(Translation* t, tList) {
216             _result.insert(t->key().toLower(), t);
217         }
218         _innerResult.removeOne(trans);
219     }
220     if(!_innerResult.size()) {
221         _timerSearch.stop();
222         Q_EMIT ready();
223     }
224 }
225
226 QStringList Backbone::getFilesFromDir(QString dir, QStringList nameFilter) {
227     QDir plug(QDir::toNativeSeparators(dir));
228     if(!plug.exists()) {
229         qDebug() << plug.absolutePath() << " folder dosen't exists";
230         return QStringList();
231     }
232     plug.setFilter(QDir::Files);
233     QStringList list = plug.entryList(nameFilter);
234
235     for(int i = 0; i < list.size(); i++)
236         list[i] = plug.absoluteFilePath(list.at(i));
237     return list;
238 }
239
240
241 void Backbone::loadPlugins() {
242     if(dryRun)
243         return;
244     QStringList nameFilter;
245     nameFilter << "*.so";
246     QStringList files = getFilesFromDir(_pluginPath, nameFilter);
247     qDebug() << files;
248
249     foreach(QString file, files) {
250         QPluginLoader loader(file);
251         if(!loader.load()) {
252             qDebug()<< file << " " << loader.errorString();
253             continue;
254         }
255         QObject *pl = loader.instance();
256
257         CommonDictInterface *plugin = qobject_cast<CommonDictInterface*>(pl);
258         _plugins.append(plugin);
259     }
260 }
261
262
263
264 CommonDictInterface* Backbone::plugin(QString type) {
265     foreach(CommonDictInterface* plugin, _plugins)
266         if(plugin->type() == type)
267             return plugin;
268     return 0;
269 }
270
271
272
273 void Backbone::loadPrefs(QString fileName) {
274     if(dryRun)
275         return;
276     QFileInfo file(QDir::toNativeSeparators(fileName));
277     QDir confDir(file.dir());
278     if(!confDir.exists()){
279         qDebug() << "Configuration file dosn't exists ("
280                 << file.filePath() << ")";
281         return;
282     }
283     QSettings set(file.filePath(), QSettings::IniFormat);
284     _pluginPath = set.value("general/plugin_path", _pluginPath).toString();
285     _historyLen = set.value("general/history_length", 10).toInt();
286     _searchLimit = set.value("general/search_limit", 15).toInt();
287 }
288
289
290
291 void Backbone::savePrefs(QSettings *set) {
292     if(dryRun)
293         return;
294     set->setValue("general/plugin_path", _pluginPath);
295     set->setValue("general/history_length", _historyLen);
296     set->setValue("general/search_limit", _searchLimit);
297 }
298
299
300
301 void Backbone::saveDefaultPrefs(QSettings *set) {
302     if(dryRun)
303         return;
304     set->setValue("general/plugin_path", _defaultPluginPath);
305     set->setValue("general/history_length", _defaultHistoryLen);
306     set->setValue("general/search_limit", _defaultSearchLimit);
307 }
308
309
310
311 void Backbone::loadDicts(QString fileName, bool _default) {
312     if(dryRun)
313         return;
314     QFileInfo file(QDir::toNativeSeparators(fileName));
315     qDebug() << file.filePath();
316     QDir confDir(file.dir());
317     if(!confDir.exists()){
318         qDebug() << "Configuration file dosn't exists ("
319                 << file.filePath() << ")";
320         return;
321     }
322
323     QSettings set(file.filePath(), QSettings::IniFormat);
324     QStringList dicts = set.childGroups();
325     foreach(QString dict, dicts) {
326         if(!dict.contains("dictionary_"))
327             continue;
328         CommonDictInterface* plug = plugin
329                                     (set.value(dict + "/type", "").toString());
330         if(!plug) {
331             qDebug() << "Config file error: "
332                     << set.value(dict + "/type", "").toString()
333                     << " dosen't exists";
334             continue;
335         }
336         Settings* plugSet = new Settings();
337         set.beginGroup(dict);
338         QStringList items = set.childKeys();
339         foreach(QString item, items) {
340             plugSet->setValue(item, set.value(item, "").toString());
341         }
342         bool active = set.value("active",1).toBool();
343
344         if(_default)
345             plugSet->setValue("_default_", "true");
346
347         set.endGroup();
348         addInternalDictionary(plug->getNew(plugSet), active);
349     }
350 }
351
352
353
354 void Backbone::dictUpdated() {
355     if(dryRun)
356         return;
357     QFileInfo file(QDir::toNativeSeparators(_configPath));
358     QDir confDir(file.dir());
359     if(!confDir.exists())
360         confDir.mkpath(file.dir().path());
361     QSettings set(file.filePath(), QSettings::IniFormat);
362     set.clear();
363
364     QFileInfo defFile(QDir::toNativeSeparators(_defaultConfigPath));
365     QDir defConfDir(defFile.dir());
366     if(!defConfDir.exists())
367         defConfDir.mkpath(defFile.dir().path());
368     QSettings defSet(defFile.filePath(), QSettings::IniFormat);
369     defSet.clear();
370     savePrefs(&set);
371     saveDefaultPrefs(&defSet);
372
373     foreach(CommonDictInterface* dict, _dicts.keys()){
374         if(!dict || !dict->settings())
375             continue;
376         if(!dict->settings()->keys().contains("_default_"))
377             saveState(&set, dict->settings(), _dicts[dict], dict->hash());
378         else
379             saveState(&defSet, dict->settings(), _dicts[dict], dict->hash());
380     }
381 }
382
383
384
385 void Backbone::saveState(QSettings* set, Settings* plugSet, bool active
386                          , uint hash) {
387     if(dryRun)
388         return;
389     if(!set || !plugSet)
390         return;
391     QString section;
392     section.append(QString("dictionary_%1").arg(hash));
393     QList<QString> keys = plugSet->keys();
394     foreach(QString key, keys)
395         set->setValue(section + "/" + key, plugSet->value(key));
396     set->setValue(section + "/active", active);
397 }
398
399
400
401 QStringList Backbone::htmls() {
402     return _htmlResult;
403 }
404
405
406
407 void Backbone::searchHtml(QList<Translation *> translations) {
408     _timerHtmlSearch.stop();
409     _htmlResult.clear();
410     _innerHtmlResult.clear();
411     _timerHtmlSearch.start();
412
413     foreach(Translation* trans, translations)
414         if(trans)
415            _innerHtmlResult.append(
416                    QtConcurrent::run(trans, &Translation::toHtml));
417 }
418
419 void Backbone::htmlTranslationReady() {
420     foreach(QFuture<QString> res, _innerHtmlResult) {
421         if(!res.isFinished())
422             continue;
423         _htmlResult.append(res.result());
424         _innerHtmlResult.removeOne(res);
425     }
426     if(!_innerHtmlResult.size()) {
427         _timerHtmlSearch.stop();
428         Q_EMIT htmlReady();
429     }
430
431 }