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