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