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