Added notify manager, which prevent from showing the same notify multiple times
[mdictionary] / trunk / src / base / gui / MainWindow.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 //! \file MainWindow.cpp
23 //! \author Mateusz Półrola <mateusz.polrola@comarch.pl>
24
25 #include "MainWindow.h"
26 #include <QtGui>
27 #ifdef Q_WS_MAEMO_5
28     #include <QMaemo5InformationBox>
29 #endif
30
31
32 MainWindow::MainWindow(Backbone *backbone, QWidget *parent):
33     GUIInterface(parent) {
34
35     this->backbone = backbone;
36
37
38     initializeUI();
39
40     connectBackbone();
41     connectSearchBar();
42     connectWordList();
43     connectTranslationWidget();
44     connectDictManager();
45     connectMenu();
46     connectBookmarksWidget();
47
48     setExactSearch(false);
49
50     showMaximized();
51 }
52
53 MainWindow::~MainWindow() {
54
55 }
56
57
58 void MainWindow::initializeUI() {
59
60     #ifdef Q_WS_MAEMO_5
61         setAttribute(Qt::WA_Maemo5StackedWindow);
62     #endif
63
64
65     setWindowIcon(QIcon(":/icons/64x64/mdictionary.png"));
66     setWindowTitle("mDictionary");
67
68     /*translationWidget is another stacked window, so we don't add it to
69       layout only create it with this widget as parent
70       it must be created as first object in main window, otherwise sometimes
71       when app starts in maemo, when trying to set stacked window attribure
72       it segfaults*/
73     translationWidget = new TranslationWidget(this);
74
75     mainLayout = new QVBoxLayout();
76     QWidget* w = new QWidget();
77     w->setLayout(mainLayout);
78     setCentralWidget(w);
79
80     menuBar = new QMenuBar();
81     setMenuBar(menuBar);
82
83     initializeSearchWidgets();
84
85     initializeMenu();
86
87     notifyManager = new NotifyManager(this);
88 }
89
90 void MainWindow::initializeSearchWidgets() {
91     searchBarWidget = new SearchBarWidget();
92
93     wordListWidget = new WordListWidget();
94
95     welcomeScreenWidget = new WelcomeScreenWidget();
96
97     #ifdef Q_WS_MAEMO_5
98         //At start we set widget as welcome screen widget
99         mainLayout->addWidget(welcomeScreenWidget);
100         mainLayout->addWidget(searchBarWidget, 0, Qt::AlignBottom);
101     #else
102         translationWidget->hide();
103         //we add to splitter word list and welcome screen
104         splitter = new QSplitter(Qt::Horizontal);
105         splitter->addWidget(wordListWidget);
106         splitter->addWidget(welcomeScreenWidget);
107         splitter->setStretchFactor(1, 150);
108
109         mainLayout->addWidget(splitter);
110         mainLayout->addWidget(searchBarWidget);
111     #endif
112 }
113
114 void MainWindow::initializeMenu() {
115     initializeMenuWidgets();
116
117 #ifdef Q_WS_MAEMO_5
118     menuWidget = new MenuWidget(this);
119
120     menuWidget->addSubMenu(tr("Settings"), settingsWidget);
121     menuWidget->addSubMenu(tr("Dictionaries"), dictManagerWidget);
122     menuWidget->addSubMenu(tr("Bookmarks"), bookmarksWidget);
123     menuWidget->addSubMenu(tr("About"), aboutWidget);
124
125     menuBar->addAction(menuWidget);
126 #else
127     dictionariesAction = menuBar->addAction(tr("Dictionaries"));
128     connect(dictionariesAction, SIGNAL(triggered()),
129             dictManagerWidget, SLOT(show()));
130
131     settingsAction = menuBar->addAction(tr("Settings"));
132     connect(settingsAction, SIGNAL(triggered()),
133             settingsWidget, SLOT(show()));
134
135     QMenu* m = menuBar->addMenu(tr("Bookmarks"));
136     bookmarksShowAllAction = new QAction(tr("Show all"), m);
137
138     bookmarksRemoveAllAction = new QAction(tr("Remove all"), m);
139
140     m->addAction(bookmarksShowAllAction);
141     m->addAction(bookmarksRemoveAllAction);
142
143     aboutAction = menuBar->addAction(tr("About"));
144     connect(aboutAction, SIGNAL(triggered()),
145             aboutWidget, SLOT(show()));
146 #endif
147 }
148
149 void MainWindow::initializeMenuWidgets() {
150     dictManagerWidget = new DictManagerWidget(this);
151     dictManagerWidget->hide();
152
153     settingsWidget = new SettingsWidget(this);
154     settingsWidget->hide();
155
156     bookmarksWidget = new BookmarksWidget(this);
157     bookmarksWidget->hide();
158
159     aboutWidget = new AboutWidget(this);
160     aboutWidget->hide();
161 }
162
163 void MainWindow::closeEvent(QCloseEvent *event) {
164     //request to stop all searches and close app
165     Q_EMIT quit();
166     event->accept();
167 }
168
169 bool MainWindow::isInExactSearch() {
170     return _exactSearch;
171 }
172
173 void MainWindow::setExactSearch(bool exact) {
174     _exactSearch = exact;
175 }
176
177 void MainWindow::setExactSearchString(QString word) {
178     searchString = word;
179 }
180
181 void MainWindow::wordListReady() {
182     //gets results from backbone
183     QMultiHash<QString, Translation*> backboneResult = backbone->result();
184     QHash<QString, QList<Translation*> > searchResult;
185
186     #ifdef Q_WS_MAEMO_5
187         hideWelcomeScreen();
188     #endif
189
190     //if nothing was found
191     if(backboneResult.count() == 0) {
192         showNotify(Notify::Info, tr("Can't find any matching words"));
193
194         //show empty list to remove results of old search
195         Q_EMIT showWordList(searchResult);
196     }
197     else {
198         //find translations of the same key word
199         QMultiHash<QString, Translation*>::iterator i;
200         for(i = backboneResult.begin(); i != backboneResult.end(); i++) {
201             searchResult[i.key()].push_back(i.value());
202         }
203
204         //show search results
205         Q_EMIT showWordList(searchResult);
206
207
208         if(isInExactSearch()) {
209             QList<Translation*> exactTranslation;
210             if(checkExactSearch(searchResult, exactTranslation)) {
211                 qDebug()<<exactTranslation.count();
212                 Q_EMIT searchTranslations(exactTranslation);
213             }
214             else {
215                 showNotify(Notify::Info,
216                            tr("Can't find exactly matching word"));
217             }
218
219             setExactSearch(false);
220         }
221     }
222 }
223
224 bool MainWindow::checkExactSearch(
225         QHash<QString, QList<Translation *> > searchResult,
226         QList<Translation *> &found) {
227
228     bool foundExactMatch = false;
229     QHash<QString, QList<Translation*> >::iterator j;
230     for(j = searchResult.begin(); j != searchResult.end(); j++) {
231         if(j.key().toLower() == searchString.toLower()
232             && !foundExactMatch) {
233             found = j.value();
234             return true;
235         }
236     }
237     return false;
238 }
239
240 void MainWindow::translationsReady() {
241     #ifndef Q_WS_MAEMO_5
242         hideWelcomeScreen();
243     #endif
244
245     Q_EMIT showTranslation(backbone->htmls());
246     notifyManager->screenChanged();
247 }
248
249
250 void MainWindow::hideWelcomeScreen() {
251 #ifdef Q_WS_MAEMO_5
252     //switch welcome screen with word list
253     if(!wordListWidget->isVisible()) {
254         mainLayout->removeWidget(welcomeScreenWidget);
255         welcomeScreenWidget->deleteLater();
256
257         mainLayout->insertWidget(0, wordListWidget);
258     }
259 #else
260     //switch welcome screen with translation widget
261     if(!translationWidget->isVisible()) {
262         splitter->insertWidget(1,translationWidget);
263         splitter->setStretchFactor(1, 150);
264         welcomeScreenWidget->deleteLater();
265     }
266 #endif
267 }
268
269 QList<CommonDictInterface*> MainWindow::getPlugins() {
270     return backbone->getPlugins();
271 }
272
273 QHash<CommonDictInterface*, bool> MainWindow::getDictionaries() {
274     return backbone->getDictionaries();
275 }
276
277
278 void MainWindow::search(QString word) {
279     setExactSearch(false);
280     searchBarWidget->search(word);
281 }
282
283 void MainWindow::searchExact(QString word) {
284     setExactSearch(true);
285     searchBarWidget->search(word);
286 }
287
288 void MainWindow::searchDelay(QString word) {
289     searchBarWidget->searchDelay(word);
290 }
291
292
293
294
295
296 void MainWindow::searchingInterrupted() {
297     //make sure to unset exact search mode
298     setExactSearch(false);
299 }
300
301 void MainWindow::addToHistory(QList<Translation *> trans) {
302     if(trans.count() > 0) {
303         backbone->history()->add(trans[0]->key());
304     }
305 }
306
307 void MainWindow::historyNext() {
308     if(backbone->history()->nextAvailable()) {
309         QString next = backbone->history()->next();
310         #ifndef Q_WS_MAEMO_5
311             setExactSearch(true);
312         #endif
313         searchDelay(next);
314     }
315 }
316
317 void MainWindow::historyPrev() {
318     if(backbone->history()->prevAvailable()) {
319         #ifndef Q_WS_MAEMO_5
320             setExactSearch(true);
321         #endif
322         QString prev = backbone->history()->previous();
323         searchDelay(prev);
324     }
325 }
326
327 void MainWindow::disableMenu() {
328     #ifdef Q_WS_MAEMO_5
329         if(menuBar->actions().contains(menuWidget)) {
330               menuBar->removeAction(menuWidget);
331         }
332     #else
333         menuBar->setEnabled(false);
334     #endif
335 }
336
337 void MainWindow::enableMenu() {
338     #ifdef Q_WS_MAEMO_5
339         if(!menuBar->actions().contains(menuWidget)) {
340             menuBar->addAction(menuWidget);
341         }
342     #else
343         menuBar->setEnabled(true);
344     #endif
345 }
346
347 void MainWindow::showHistory(QPoint p) {
348
349     HistoryListDialog historyDialog(backbone->history()->list(), searchBarWidget);
350
351     #ifndef Q_WS_MAEMO_5
352         QPoint newPos = mapFromGlobal(p);
353         newPos.setY(searchBarWidget->pos().y() -
354                     historyDialog.sizeHint().height());
355         newPos.setX(width() - historyDialog.sizeHint().width());
356
357         historyDialog.move(newPos);
358     #endif
359
360     if(historyDialog.exec() == QDialog::Accepted) {
361         backbone->history()->setCurrentElement(historyDialog.selectedRow());
362         searchExact(historyDialog.selectedWord());
363     }
364 }
365
366 void MainWindow::setSettings(Settings *s) {
367     backbone->setSettings(s);
368 }
369
370 Settings* MainWindow::settings() {
371     return backbone->settings();
372 }
373
374
375 void MainWindow::showNotify(Notify::NotifyType type, QString text) {
376     notifyManager->showNotify(type, text);
377 }
378
379 void MainWindow::connectBackbone() {
380
381     connect(this, SIGNAL(searchWordList(QString)),
382             this, SIGNAL(setBusy()));
383
384     connect(this, SIGNAL(searchTranslations(QList<Translation*>)),
385             this, SIGNAL(setBusy()));
386
387     connect(this, SIGNAL(stopSearching()),
388             this, SIGNAL(setIdle()));
389
390     connect(this, SIGNAL(searchWordList(QString)),
391             this, SLOT(setExactSearchString(QString)));
392
393     connect(this, SIGNAL(searchTranslations(QList<Translation*>)),
394             this, SLOT(addToHistory(QList<Translation*>)));
395
396
397
398     connect(this, SIGNAL(quit()),
399             backbone, SLOT(quit()));
400
401     connect(this, SIGNAL(searchWordList(QString)),
402             backbone, SLOT(search(QString)));
403
404     connect(this, SIGNAL(searchTranslations(QList<Translation*>)),
405             backbone, SLOT(searchHtml(QList<Translation*>)));
406
407     connect(this, SIGNAL(stopSearching()),
408             backbone, SLOT(stopSearching()));
409
410     connect(this, SIGNAL(stopSearching()),
411             this, SLOT(searchingInterrupted()));
412
413     connect(this, SIGNAL(addNewDictionary(CommonDictInterface*)),
414             backbone, SLOT(addDictionary(CommonDictInterface*)));
415
416     connect(this, SIGNAL(removeDictionary(CommonDictInterface*)),
417             backbone, SLOT(removeDictionary(CommonDictInterface*)));
418
419     connect(this, SIGNAL(selectedDictionaries(QList<CommonDictInterface*>)),
420             backbone, SLOT(selectedDictionaries(QList<CommonDictInterface*>)));
421
422
423     connect(backbone, SIGNAL(ready()),
424             this, SIGNAL(setIdle()));
425
426     connect(backbone, SIGNAL(htmlReady()),
427             this, SIGNAL(setIdle()));
428
429
430     connect(backbone, SIGNAL(ready()),
431             this, SLOT(wordListReady()));
432
433     connect(backbone, SIGNAL(htmlReady()),
434             this, SLOT(translationsReady()));
435
436     connect(backbone, SIGNAL(searchCanceled()),
437             this, SIGNAL(setIdle()));
438
439     connect(backbone, SIGNAL(notify(Notify::NotifyType,QString)),
440             this, SLOT(showNotify(Notify::NotifyType,QString)));
441 }
442
443 void MainWindow::connectSearchBar() {
444     connect(searchBarWidget, SIGNAL(searchForTranslations(QString)),
445             this, SIGNAL(searchWordList(QString)));
446
447     connect(searchBarWidget, SIGNAL(stopSearching()),
448             this, SIGNAL(stopSearching()));
449
450     connect(this, SIGNAL(setBusy()),
451             searchBarWidget, SLOT(setBusy()));
452
453     connect(this, SIGNAL(setIdle()),
454             searchBarWidget, SLOT(setIdle()));
455
456     connect(searchBarWidget, SIGNAL(historyNext()),
457             this, SLOT(historyNext()));
458
459     connect(searchBarWidget, SIGNAL(historyPrev()),
460             this, SLOT(historyPrev()));
461
462     connect(searchBarWidget, SIGNAL(historyShow(QPoint)),
463             this, SLOT(showHistory(QPoint)));
464
465     connect(searchBarWidget, SIGNAL(refreshHistoryButtons()),
466             backbone->history(), SLOT(refreshStatus()));
467
468     connect(backbone->history(), SIGNAL(historyChanged(bool,bool,bool)),
469             searchBarWidget, SLOT(updateHistoryButtons(bool,bool,bool)));
470 }
471
472 void MainWindow::connectWordList() {
473     connect(this,
474             SIGNAL(showWordList(QHash<QString, QList<Translation*> >)),
475             wordListWidget,
476             SLOT(showSearchResults(QHash<QString,QList<Translation*> >)));
477
478     connect(wordListWidget, SIGNAL(showTranslation(QList<Translation*>)),
479             this, SIGNAL(searchTranslations(QList<Translation*>)));
480
481
482
483
484     connect(this, SIGNAL(setBusy()),
485             wordListWidget, SLOT(lockList()));
486
487     connect(this, SIGNAL(setIdle()),
488             wordListWidget, SLOT(unlockList()));
489
490     connect(wordListWidget, SIGNAL(addBookmark(QList<Translation*>)),
491             backbone, SLOT(addBookmark(QList<Translation*>)));
492
493     connect(wordListWidget, SIGNAL(removeBookmark(QList<Translation*>)),
494             backbone, SLOT(removeBookmark(QList<Translation*>)));
495 }
496
497 void MainWindow::connectTranslationWidget() {
498     connect(this, SIGNAL(showTranslation(QStringList)),
499             translationWidget, SLOT(show(QStringList)));
500
501      #ifdef Q_WS_MAEMO_5
502         connect(translationWidget, SIGNAL(search(QString)),
503                 this, SLOT(search(QString)));
504     #else
505         connect(translationWidget, SIGNAL(search(QString)),
506                 this, SLOT(searchExact(QString)));
507     #endif
508
509
510 }
511
512 void MainWindow::connectDictManager() {
513     connect(dictManagerWidget, SIGNAL(addDictionary(CommonDictInterface*)),
514             this, SIGNAL(addNewDictionary(CommonDictInterface*)));
515
516     connect(dictManagerWidget, SIGNAL(removeDictionary(CommonDictInterface*)),
517             this, SIGNAL(removeDictionary(CommonDictInterface*)));
518
519     connect(dictManagerWidget,
520             SIGNAL(selectedDictionaries(QList<CommonDictInterface*>)),
521             this, SIGNAL(selectedDictionaries(QList<CommonDictInterface*>)));
522 }
523
524 void MainWindow::connectMenu() {
525     connect(this, SIGNAL(setBusy()),
526             this, SLOT(disableMenu()));
527
528     connect(this, SIGNAL(setIdle()),
529             this, SLOT(enableMenu()));
530 }
531
532
533 void MainWindow::connectBookmarksWidget() {
534     #ifdef Q_WS_MAEMO_5
535         //after removing bookmarks we search for it once again to clear word list
536         connect(bookmarksWidget, SIGNAL(removeAllBookmarks()),
537                 this, SLOT(removeBookmarks()));
538
539
540         connect(bookmarksWidget, SIGNAL(showAllBookmarks()),
541                 menuWidget, SLOT(hideMenu()));
542
543         connect(bookmarksWidget, SIGNAL(showAllBookmarks()),
544                 backbone, SLOT(fetchBookmarks()));
545
546
547     #else
548         connect(bookmarksRemoveAllAction, SIGNAL(triggered()),
549                 this, SLOT(removeBookmarks()));
550         connect(bookmarksShowAllAction, SIGNAL(triggered()),
551                 backbone, SLOT(fetchBookmarks()));
552
553     #endif
554 }
555
556
557 void MainWindow::removeBookmarks() {
558     QWidget* par;
559     #ifdef Q_WS_MAEMO_5
560         par = bookmarksWidget;
561     #else
562         par = this;
563     #endif
564     if(QMessageBox::question(par, "Delete all bookmarks",
565              "Do you want to delete all bookmarks? (This action cannot be revoked)",
566              QMessageBox::Ok, QMessageBox::Cancel) == QMessageBox::Ok) {
567         backbone->removeAllBookmarks();
568         if(searchString.size())
569             backbone->search(searchString);
570
571     }
572 }