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