16257c684e73b89e3d80277b5774c5566d1828e6
[mdictionary] / src / mdictionary / 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 attribute
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 word list and welcome screen to splitter
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         showNotification(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                 Q_EMIT searchTranslations(exactTranslation);
212             }
213             else {
214                 showNotification(Notify::Info,
215                            tr("Can't find exactly matching word"));
216             }
217
218             setExactSearch(false);
219         }
220     }
221 }
222
223 bool MainWindow::checkExactSearch(
224         QHash<QString, QList<Translation *> > searchResult,
225         QList<Translation *> &found) {
226
227     bool foundExactMatch = false;
228     QHash<QString, QList<Translation*> >::iterator j;
229     for(j = searchResult.begin(); j != searchResult.end(); j++) {
230         if(j.key().toLower() == searchString.toLower()
231             && !foundExactMatch) {
232             found = j.value();
233             return true;
234         }
235     }
236     return false;
237 }
238
239 void MainWindow::translationsReady() {
240     #ifndef Q_WS_MAEMO_5
241         hideWelcomeScreen();
242     #endif
243
244     Q_EMIT showTranslation(backbone->htmls());
245     notifyManager->screenChanged();
246 }
247
248
249 void MainWindow::hideWelcomeScreen() {
250 #ifdef Q_WS_MAEMO_5
251     //switch welcome screen with word list
252     if(!wordListWidget->isVisible()) {
253         mainLayout->removeWidget(welcomeScreenWidget);
254         welcomeScreenWidget->deleteLater();
255
256         mainLayout->insertWidget(0, wordListWidget);
257     }
258 #else
259     //switch welcome screen with translation widget
260     if(!translationWidget->isVisible()) {
261         splitter->insertWidget(1,translationWidget);
262         splitter->setStretchFactor(1, 150);
263         welcomeScreenWidget->deleteLater();
264     }
265 #endif
266 }
267
268 QList<CommonDictInterface*> MainWindow::getPlugins() {
269     return backbone->getPlugins();
270 }
271
272 QHash<CommonDictInterface*, bool> MainWindow::getDictionaries() {
273     return backbone->getDictionaries();
274 }
275
276
277 void MainWindow::search(QString word) {
278     setExactSearch(false);
279     searchBarWidget->search(word);
280 }
281
282 void MainWindow::searchExact(QString word) {
283     setExactSearch(true);
284     searchBarWidget->search(word);
285 }
286
287 void MainWindow::searchDelay(QString word) {
288     searchBarWidget->searchDelay(word);
289 }
290
291
292
293
294
295 void MainWindow::searchingInterrupted() {
296     //make sure to unset exact search mode
297     setExactSearch(false);
298 }
299
300 void MainWindow::addToHistory(QList<Translation *> trans) {
301     if(trans.count() > 0) {
302         backbone->history()->add(trans[0]->key());
303     }
304 }
305
306 void MainWindow::historyNext() {
307     if(backbone->history()->nextAvailable()) {
308         QString next = backbone->history()->next();
309         #ifndef Q_WS_MAEMO_5
310             setExactSearch(true);
311         #endif
312         searchDelay(next);
313     }
314 }
315
316 void MainWindow::historyPrev() {
317     if(backbone->history()->prevAvailable()) {
318         #ifndef Q_WS_MAEMO_5
319             setExactSearch(true);
320         #endif
321         QString prev = backbone->history()->previous();
322         searchDelay(prev);
323     }
324 }
325
326 void MainWindow::disableMenu() {
327     #ifdef Q_WS_MAEMO_5
328         if(menuBar->actions().contains(menuWidget)) {
329               menuBar->removeAction(menuWidget);
330         }
331     #else
332         menuBar->setEnabled(false);
333     #endif
334 }
335
336 void MainWindow::enableMenu() {
337     #ifdef Q_WS_MAEMO_5
338         if(!menuBar->actions().contains(menuWidget)) {
339             menuBar->addAction(menuWidget);
340         }
341     #else
342         menuBar->setEnabled(true);
343     #endif
344 }
345
346 void MainWindow::showHistory(QPoint p) {
347
348     HistoryListDialog historyDialog(backbone->history()->list(), searchBarWidget);
349
350     #ifndef Q_WS_MAEMO_5
351         QPoint newPos = mapFromGlobal(p);
352         newPos.setY(searchBarWidget->pos().y() -
353                     historyDialog.sizeHint().height());
354         newPos.setX(width() - historyDialog.sizeHint().width());
355
356         historyDialog.move(newPos);
357     #endif
358
359     if(historyDialog.exec() == QDialog::Accepted) {
360         backbone->history()->setCurrentElement(historyDialog.selectedRow());
361         searchExact(historyDialog.selectedWord());
362     }
363 }
364
365 void MainWindow::setSettings(Settings *s) {
366     backbone->setSettings(s);
367 }
368
369 Settings* MainWindow::settings() {
370     return backbone->settings();
371 }
372
373
374 void MainWindow::showNotification(Notify::NotifyType type, QString text) {
375     notifyManager->showNotification(type, text);
376 }
377
378 void MainWindow::connectBackbone() {
379
380     connect(this, SIGNAL(searchWordList(QString)),
381             this, SIGNAL(setBusy()));
382
383     connect(this, SIGNAL(searchTranslations(QList<Translation*>)),
384             this, SIGNAL(setBusy()));
385
386     connect(this, SIGNAL(stopSearching()),
387             this, SIGNAL(setIdle()));
388
389     connect(this, SIGNAL(searchWordList(QString)),
390             this, SLOT(setExactSearchString(QString)));
391
392     connect(this, SIGNAL(searchTranslations(QList<Translation*>)),
393             this, SLOT(addToHistory(QList<Translation*>)));
394
395
396
397     connect(this, SIGNAL(quit()),
398             backbone, SLOT(quit()));
399
400     connect(this, SIGNAL(searchWordList(QString)),
401             backbone, SLOT(search(QString)));
402
403     connect(this, SIGNAL(searchTranslations(QList<Translation*>)),
404             backbone, SLOT(searchHtml(QList<Translation*>)));
405
406     connect(this, SIGNAL(stopSearching()),
407             backbone, SLOT(stopSearching()));
408
409     connect(this, SIGNAL(stopSearching()),
410             this, SLOT(searchingInterrupted()));
411
412     connect(this, SIGNAL(addNewDictionary(CommonDictInterface*)),
413             backbone, SLOT(addDictionary(CommonDictInterface*)));
414
415     connect(this, SIGNAL(removeDictionary(CommonDictInterface*)),
416             backbone, SLOT(removeDictionary(CommonDictInterface*)));
417
418     connect(this, SIGNAL(selectedDictionaries(QList<CommonDictInterface*>)),
419             backbone, SLOT(selectedDictionaries(QList<CommonDictInterface*>)));
420
421
422     connect(backbone, SIGNAL(ready()),
423             this, SIGNAL(setIdle()));
424
425     connect(backbone, SIGNAL(htmlReady()),
426             this, SIGNAL(setIdle()));
427
428
429     connect(backbone, SIGNAL(ready()),
430             this, SLOT(wordListReady()));
431
432     connect(backbone, SIGNAL(htmlReady()),
433             this, SLOT(translationsReady()));
434
435     connect(backbone, SIGNAL(searchCanceled()),
436             this, SIGNAL(setIdle()));
437
438     connect(backbone, SIGNAL(notify(Notify::NotifyType,QString)),
439             this, SLOT(showNotification(Notify::NotifyType,QString)));
440 }
441
442 void MainWindow::connectSearchBar() {
443     connect(searchBarWidget, SIGNAL(searchForTranslations(QString)),
444             this, SIGNAL(searchWordList(QString)));
445
446     connect(searchBarWidget, SIGNAL(stopSearching()),
447             this, SIGNAL(stopSearching()));
448
449     connect(this, SIGNAL(setBusy()),
450             searchBarWidget, SLOT(setBusy()));
451
452     connect(this, SIGNAL(setIdle()),
453             searchBarWidget, SLOT(setIdle()));
454
455     connect(searchBarWidget, SIGNAL(historyNext()),
456             this, SLOT(historyNext()));
457
458     connect(searchBarWidget, SIGNAL(historyPrev()),
459             this, SLOT(historyPrev()));
460
461     connect(searchBarWidget, SIGNAL(historyShow(QPoint)),
462             this, SLOT(showHistory(QPoint)));
463
464     connect(searchBarWidget, SIGNAL(refreshHistoryButtons()),
465             backbone->history(), SLOT(refreshStatus()));
466
467     connect(backbone->history(), SIGNAL(historyChanged(bool,bool,bool)),
468             searchBarWidget, SLOT(updateHistoryButtons(bool,bool,bool)));
469 }
470
471 void MainWindow::connectWordList() {
472     connect(this,
473             SIGNAL(showWordList(QHash<QString, QList<Translation*> >)),
474             wordListWidget,
475             SLOT(showSearchResults(QHash<QString,QList<Translation*> >)));
476
477     connect(wordListWidget, SIGNAL(showTranslation(QList<Translation*>)),
478             this, SIGNAL(searchTranslations(QList<Translation*>)));
479
480
481
482
483     connect(this, SIGNAL(setBusy()),
484             wordListWidget, SLOT(lockList()));
485
486     connect(this, SIGNAL(setIdle()),
487             wordListWidget, SLOT(unlockList()));
488
489     connect(wordListWidget, SIGNAL(addBookmark(QList<Translation*>)),
490             backbone, SLOT(addBookmark(QList<Translation*>)));
491
492     connect(wordListWidget, SIGNAL(removeBookmark(QList<Translation*>)),
493             backbone, SLOT(removeBookmark(QList<Translation*>)));
494 }
495
496 void MainWindow::connectTranslationWidget() {
497     connect(this, SIGNAL(showTranslation(QStringList)),
498             translationWidget, SLOT(show(QStringList)));
499
500      #ifdef Q_WS_MAEMO_5
501         connect(translationWidget, SIGNAL(search(QString)),
502                 this, SLOT(search(QString)));
503     #else
504         connect(translationWidget, SIGNAL(search(QString)),
505                 this, SLOT(searchExact(QString)));
506     #endif
507
508
509 }
510
511 void MainWindow::connectDictManager() {
512     connect(dictManagerWidget, SIGNAL(addDictionary(CommonDictInterface*)),
513             this, SIGNAL(addNewDictionary(CommonDictInterface*)));
514
515     connect(dictManagerWidget, SIGNAL(removeDictionary(CommonDictInterface*)),
516             this, SIGNAL(removeDictionary(CommonDictInterface*)));
517
518     connect(dictManagerWidget,
519             SIGNAL(selectedDictionaries(QList<CommonDictInterface*>)),
520             this, SIGNAL(selectedDictionaries(QList<CommonDictInterface*>)));
521 }
522
523 void MainWindow::connectMenu() {
524     connect(this, SIGNAL(setBusy()),
525             this, SLOT(disableMenu()));
526
527     connect(this, SIGNAL(setIdle()),
528             this, SLOT(enableMenu()));
529 }
530
531
532 void MainWindow::connectBookmarksWidget() {
533     #ifdef Q_WS_MAEMO_5
534         //after removing bookmarks we search for them once again to clear word list
535         connect(bookmarksWidget, SIGNAL(removeAllBookmarks()),
536                 this, SLOT(removeBookmarks()));
537
538
539         connect(bookmarksWidget, SIGNAL(showAllBookmarks()),
540                 menuWidget, SLOT(hideMenu()));
541
542         connect(bookmarksWidget, SIGNAL(showAllBookmarks()),
543                 backbone, SLOT(fetchBookmarks()));
544
545
546     #else
547         connect(bookmarksRemoveAllAction, SIGNAL(triggered()),
548                 this, SLOT(removeBookmarks()));
549         connect(bookmarksShowAllAction, SIGNAL(triggered()),
550                 backbone, SLOT(fetchBookmarks()));
551
552     #endif
553 }
554
555
556 void MainWindow::removeBookmarks() {
557     QWidget* par;
558     #ifdef Q_WS_MAEMO_5
559         par = bookmarksWidget;
560     #else
561         par = this;
562     #endif
563     if(QMessageBox::question(par, tr("Delete all bookmarks"),
564              tr("Do you want to delete all bookmarks? (This action cannot be revoked)"),
565              QMessageBox::Yes, QMessageBox::Cancel) == QMessageBox::Yes) {
566         backbone->removeAllBookmarks();
567         if(searchString.size())
568             backbone->search(searchString);
569
570     }
571 }