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