Fixed bug in bookmarks
[mdictionary] / src / mdictionary / backbone / backbone.h
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 /*! \file backbone.cpp
23 \brief Backbone/core main header \see Backbone
24
25
26 \author Bartosz Szatkowski <bulislaw@linux.com>
27 */
28
29 #ifndef BACKBONE_H
30 #define BACKBONE_H
31
32 #include <QObject>
33 #include <QList>
34 #include <QHash>
35 #include <QSet>
36 #include <QPluginLoader>
37 #include <QFuture>
38 #include <QtConcurrentRun>
39 #include <QtConcurrentMap>
40 #include <QFutureIterator>
41 #include <QTimer>
42 #include <QTime>
43 #include <QDir>
44 #include <QThread>
45 #include <QDebug>
46 #include <QSettings>
47 #include <QFutureWatcher>
48 #include "../../include/CommonDictInterface.h"
49 #include "../../include/settings.h"
50 #include "../../include/translation.h"
51 #include "../../include/History.h"
52 #include "../../include/Notify.h"
53 #include "ConfigGenerator.h"
54 #include "Bookmarks.h"
55
56
57 /*! Inner part of dictionary - glues together GUI and plugins, also kind of
58     GoF facade (for GUI) cover few classes \see Bookmarks \see History
59
60   Backbone is responsible for managing plugins and dictionaries, starting
61   new searches and threads, merging search results from multiple dictionaries.
62
63   Each plugin may live in multiple instances - each with its own dictionary,
64   backbone must provide a way to create them at start (with specific Settings) and
65   distinguish each ditionary.
66
67   Backbone also manages bookmarks and history: providing interface to GUI.
68
69   Backbone is also responsible for saving and spawning session via configs
70   file (stored in ~/.mdictionary) -> configs are kind of tricky because
71   mDictionary is delivered with two simple dicts -> it's necessary to separate default
72   configs from user configs (updating/reinstalling app results in overwritten
73   default config file), moreover config file there is general mdictionary
74   configuration (apart from dictionaries and plugin ones).
75
76   Other modules may set some internal backbone behaviour via \see setSettings():
77   Settings object with options given:
78      * history_size - int, size of stored searches
79      * search_limit - int, how many different words each dictionary may return
80      * search_dictionaries - true/false, whether search in dictionaries
81      * search_bookmarks - true/false, whether search in bookmarks
82
83     Searching schema:
84         At first GUI should ask for a list of words matching a given pattern,
85         then each Translation object is capable of finding its own final translation
86
87       List of words:
88         - GUI calls search(...)
89         - Backbone calls plugins searchWordList(...) in idealThreadCount()+1 threads
90         - Backbone sets the FutureWatcher to be notified when plugins are done
91         - Backbone fetches results from Future<..> and formats it for GUI, then
92            emits ready()
93         - GUI calls result()
94
95       Final translation:
96          - GUI calls searchXml()
97          - Backbone starts toXml for each translation object in separate threads
98          - Backbone sets FutureWatcher to be notified after last toXml returns
99          - Backbone fetches translation from Future<...> objects and calls
100              xmlReady()
101          - Gui calls xmlResult()
102
103 */
104 class Backbone : public QObject
105 {
106     Q_OBJECT
107
108 public:
109     /*! \param pluginPath path to plugins (leave blank for default)
110         \param configPath path to folder with configuration files
111         \param dry dry run is mode without paying attention to configuration etc
112           mainly for testing
113       */
114     Backbone(QString pluginPath="", QString configPath="",
115              bool dry = 0, QObject *parent = 0);
116     ~Backbone();
117     Backbone(const Backbone& b);
118
119     //! \return all loaded dictionaries with activity state flag
120     QHash<CommonDictInterface*, bool> getDictionaries();
121
122     //! \return all loaded plugins
123     QList<CommonDictInterface*> getPlugins();
124
125     //! \return history of performed searches
126     History* history();
127
128     //! \return search fesult
129     QMultiHash<QString, Translation*> result();
130
131     //! \return maximum number of words that plugin could find
132     int searchLimit() const;
133
134     //! \return final translation (after searching for xml)
135     QStringList xmls();
136
137     /*! maximum number of translations that each plugin may return; it must be
138         public static because of QtConcurent::mapped restrictions about
139         what kind of function may be used there see Qt docs */
140     static int _searchLimit;
141
142
143
144 public Q_SLOTS:
145     //! stops all current searches and emits searchCanceled signal
146     void stopSearching();
147
148     /*! searches for a word translation
149        \param word word to be translated
150       */
151     void search(QString word);
152
153     /*! sets active dictionaries (searches are performed only in active dicts)
154        \param List of dictionaries to be activated
155       */
156     void selectedDictionaries(QList<CommonDictInterface*>);
157
158     /*! adds a new dictionary and activates it
159       \param dict dictionary to be added
160       \param active decides whether searches are perfomed in given dictionaries
161       */
162     void addDictionary(CommonDictInterface* dict, bool active = 1);
163
164
165     //! stops all current activity - emitting signal \see closeOk
166     void quit();
167
168
169     /*! Fired by FutureWatcher when a list of words is ready (after calling search),
170         fetch Future<...> to final result
171       */
172     void translationReady();
173
174     /*! Fired by FutureWatcher when search result is ready, fetch Future to
175         final result
176       */
177     void xmlTranslationReady();
178
179     /*! Removes a given dictionary
180         \param dict dictionary to be deleted
181       */
182     void removeDictionary(CommonDictInterface* dict);
183
184     /*! Saves plugins new state/configuration after each change */
185     void dictUpdated();
186
187     /*! Performs search for final translation (xml) form
188       \param list of Translation* to be searched for
189       */
190     void searchXml(QList<Translation*>);
191
192
193     /*! adds bookmarks to given translations (translation object is fetched and
194       added to bookmarks data base (key and translation stored in db))
195       \param translations list of Translation objects to be stored in db
196       */
197     void addBookmark(QList<Translation*> translations) {
198         Translation* translation;
199         foreach(translation, translations)
200             _bookmarks.add(translation);
201     }
202
203
204     /*! Removes bookmarks to given translations
205       \param translations remove bookmark to these translations
206       */
207     void removeBookmark(QList<Translation*> translations) {
208         foreach(Translation* translation, translations)
209             _bookmarks.remove(translation);
210     }
211
212
213
214     /*! Removes all bookmarks
215       */
216     void removeAllBookmarks(){
217         _bookmarks.clear();
218     }
219
220
221    /*! Searching a list of bookmarks may take some time, so it's moved to a
222        new thread (to avoid GUI blocking), further it's consistent with ordinary
223        searching a list of words (\see search)
224        */
225    void fetchBookmarks() {
226         _result.clear();
227
228         stopped = false;
229         dictFin = 1;
230         bookmarkFin = 0;
231
232         _innerBookmarks = QtConcurrent::run(_bookmarks,
233                 &Bookmarks::list);
234         _bookmarkSearchWatcher.setFuture(_innerBookmarks);
235    }
236
237
238
239    /*! Sets settings for backbone: history_size, search_limit,
240        searching backends (search_bookmarks, search_dictionaries)
241        \param settings settings object with options set
242        */
243     void setSettings(Settings* settings);
244
245
246     /*! \return corresponding settings object with history_size, search_limit,
247        searching backends (search_bookmarks, search_dictionaries)
248        */
249     Settings* settings();
250
251
252
253
254
255
256 Q_SIGNALS:
257     /*! emitted when backbone is ready to close - after getting stop signal it
258         should kill all threads and so on */
259     void closeOk();
260
261     //! emitted when there are search results ready to fetch
262     void ready();
263
264     //! emitted when xml result is ready to fetch
265     void xmlReady();
266
267     //! thrown when searches are stopped
268     void searchCanceled();
269
270     //! emitted when bookmark list is ready to fetch
271     void bookmarksReady();
272
273     /*! emitted by direct connection to plugins notifying signals
274         \param Notify::NotifyType GUI may decide to show different types in
275             different ways
276         \param text of the notification
277     */
278     void notify(Notify::NotifyType, QString);
279
280 private Q_SLOTS:
281     void bookmarksListReady();
282
283
284 private:
285     QHash<CommonDictInterface*, bool> _dicts; // List of dictionaries
286     QList<CommonDictInterface*> _plugins;  // List of plugins
287
288
289     QFuture<QList<Translation*> > _innerResult; //Res of concurrent word search
290     QFuture<QString> _innerXmlResult;  // Result of xml search
291     QFuture<QList<Translation*> > _innerBookmarks; //Res of search in bookmarks
292     QFuture<QList<Translation*> > _innerListBookmarks; //Res of search in bookmarks
293     QFuture<QStringList> _innerXmlBookmarks; //Xml result of bookmarks search
294
295     QMultiHash<QString, Translation*> _result; //Final result of word search
296     QStringList _xmlResult; // Final result of xml search
297     QList<Translation*> _bookmarksResult; // Final result of search in bookmarks
298
299
300     // Keeps track of concurent computations
301     QFutureWatcher<QList<Translation*> > _resultWatcher;
302     QFutureWatcher<QList<Translation*> > _bookmarkWatcher;
303     QFutureWatcher<QList<Translation*> > _bookmarkSearchWatcher;
304     QFutureWatcher<QString> _xmlResultWatcher;
305
306
307     QString _pluginPath;
308     QString _configPath;
309     QString _dir;
310     int _historyLen;
311     qreal _zoom;
312
313     bool dryRun; // mainly for testing - when true then doesn't bother configs etc
314     bool stopped; // true when user stops searching/fetching
315     bool bookmarkFin, dictFin; // informs whether given search type is ready
316     bool _searchDicts, _searchBookmarks; // whether search performed in given source
317
318     Bookmarks _bookmarks;
319
320
321     void init();
322
323     QStringList getFilesFromDir(QString dir, QStringList nameFilter);
324     void loadPlugins(); //< locate and load plugins
325     void loadPrefs(QString fileName);
326     void loadDicts(QString fileName);
327
328     void saveState(QSettings*, Settings*, bool, uint);
329     void addInternalDictionary(CommonDictInterface*, bool);
330     void savePrefs(QSettings*);
331
332     CommonDictInterface* plugin(QString type); // searches for plugin of a given type
333     QList<CommonDictInterface*> activeDicts();
334     bool containsDict(uint hash) const;
335     int _dictNum;
336
337     History* _history;
338
339     friend class BackboneTest;
340
341 };
342
343 #endif // BACKBONE_H