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